• cocos creator实现浏览星球的功能,附源码


    预览效果:

     

    技术要点:

    1. 主摄像机的视场轴需要设置为水平。

    1. 在场景下创建一个空节点用于挂载控制器脚本

    图片已进行各概念的说明

    在“collisionNodeArray”属性下,放置需要点击的星球节点,系统会自己绑定碰撞器。

    也可自己提前绑定。

    1. 布局场景,星球围绕相机。参考如下:

    注意相机的属性。可以根据自己的需要调整相机的z值。只要保证星球绕着相机布局则行。

    1. 关于摄像机旋转的上下限制。

    可以通过设置

    这两个参数进行调节,是个经验数值。

    系统本身会进行基础的上下限制。这两个参数属于额外的限制。即顶部往下,底部往上。

    控制器(planet_view_controller)代码:

    直接拷贝到项目的一个空代码文件即可:

    1. import { _decorator, Component, Node, Camera, Input, input, EventTouch, Vec2, Quat, Vec3, screen, tween, Tween, Collider, SphereCollider, geometry, PhysicsSystem, EventHandler } from "cc";
    2. const { ccclass, property } = _decorator;
    3. @ccclass("PlanetViewController")
    4. export class PlanetViewController extends Component {
    5. start() {
    6. this.bindInputEvent();
    7. this.setLimitEuler();
    8. this.clickManagerStart();
    9. }
    10. //浏览功能区
    11. @property({
    12. displayName: "顶部额外限制角度",
    13. })
    14. private upLimitAngle = 0;
    15. @property({
    16. displayName: "底部额外限制角度",
    17. })
    18. private downLimitAngle = 0;
    19. @property(Camera)
    20. private centerCamera!: Camera;
    21. private bindInputEvent() {
    22. input.on(Input.EventType.TOUCH_START, this.onTouchStart, this);
    23. input.on(Input.EventType.TOUCH_MOVE, this.onTouchMove, this);
    24. input.on(Input.EventType.TOUCH_END, this.onTouchEnd, this);
    25. }
    26. private limitEdgeEuler = 0;
    27. private setLimitEuler() {
    28. this.limitEdgeEuler = (180 * Math.atan(Math.tan((this.centerCamera.fov * Math.PI) / 360) / this.centerCamera.camera.aspect)) / Math.PI;
    29. }
    30. private startLocation = new Vec2();
    31. private onTouchStart(e: EventTouch) {
    32. e.getLocation(this.startLocation);
    33. Tween.stopAllByTarget(this.lastRotaionSpeed);
    34. }
    35. private lastRotaionSpeed = new Vec2();
    36. private onTouchMove(e: EventTouch) {
    37. e.getDelta(this.lastRotaionSpeed);
    38. this.rotateCenterCamera(this.lastRotaionSpeed);
    39. }
    40. private clickLocation = new Vec2();
    41. private onTouchEnd(e: EventTouch) {
    42. e.getLocation(this.clickLocation);
    43. const dis = Vec2.squaredDistance(this.startLocation, this.clickLocation);
    44. if (dis <= 0.1) {
    45. this.node.emit("click", this.clickLocation);
    46. console.log("click");
    47. return;
    48. }
    49. tween(this.lastRotaionSpeed)
    50. .to(
    51. 0.5,
    52. {
    53. x: 0,
    54. y: 0,
    55. },
    56. {
    57. easing: "sineOut",
    58. onUpdate: () => {
    59. this.rotateCenterCamera(this.lastRotaionSpeed);
    60. },
    61. }
    62. )
    63. .start();
    64. }
    65. private curRotateResultEuler = new Vec3();
    66. private rotateQuat = new Quat();
    67. private lastRotationQuat = new Quat();
    68. private rotateCenterCamera(volume: Vec2) {
    69. Quat.fromAxisAngle(this.rotateQuat, Vec3.UP, (volume.x * 0.785) / screen.windowSize.width);
    70. Quat.rotateX(this.rotateQuat, this.rotateQuat, (-volume.y * 0.785) / screen.windowSize.height);
    71. this.lastRotationQuat.set(this.centerCamera.node.rotation);
    72. Quat.multiply(this.lastRotationQuat, this.lastRotationQuat, this.rotateQuat);
    73. this.lastRotationQuat.getEulerAngles(this.curRotateResultEuler);
    74. this.centerCamera.node.rotate(this.rotateQuat);
    75. const isOverUp = this.curRotateResultEuler.x < -this.limitEdgeEuler + this.upLimitAngle;
    76. const isOverDown = this.curRotateResultEuler.x > this.limitEdgeEuler - this.downLimitAngle;
    77. if (isOverUp || isOverDown) {
    78. this.lastRotationQuat.set(this.centerCamera.node.rotation);
    79. this.lastRotationQuat.getEulerAngles(this.curRotateResultEuler);
    80. const { y, z } = this.curRotateResultEuler;
    81. const x = isOverUp ? -this.limitEdgeEuler + this.upLimitAngle : this.limitEdgeEuler - this.downLimitAngle;
    82. this.centerCamera.node.setRotationFromEuler(x, y, z);
    83. }
    84. const { x, y } = this.centerCamera.node.eulerAngles;
    85. this.centerCamera.node.setRotationFromEuler(x, y, 0);
    86. }
    87. //点击检测功能区
    88. @property([EventHandler])
    89. private collisionEventHandlerArray: EventHandler[] = [];
    90. @property([Node])
    91. private collisionNodeArray: Node[] = [];
    92. private clickManagerStart() {
    93. this.setCollisionNodeCollider();
    94. this.bindClickEvent();
    95. }
    96. private setCollisionNodeCollider() {
    97. this.collisionNodeArray.forEach((node) => {
    98. let collider = node.getComponent(Collider);
    99. if (!collider) {
    100. collider = node.addComponent(SphereCollider);
    101. }
    102. collider.isTrigger = true;
    103. });
    104. }
    105. private clickRay = new geometry.Ray();
    106. private bindClickEvent() {
    107. this.node.on("click", ({ x, y }: Vec2) => {
    108. if (this.collisionNodeArray.length === 0) return;
    109. this.centerCamera.screenPointToRay(x, y, this.clickRay);
    110. PhysicsSystem.instance.raycast(this.clickRay);
    111. if (PhysicsSystem.instance.raycastResults.length) {
    112. const firstColliderNode = PhysicsSystem.instance.raycastResults[0].collider.node;
    113. this.collisionEventHandlerArray.forEach((handler) => handler.emit([firstColliderNode]));
    114. }
    115. });
    116. }
    117. }

  • 相关阅读:
    仿写muduo网络库:日志的简单实现
    在三维项目前端开发中用THREEMesh创建网格对象设置几何体和材质
    Adobe Acrobat Reader 中的漏洞
    详解JMM
    设置Oracle环境变量
    你知道哪几种Java锁?分别有什么特点?
    idea热部署-修改代码不重启
    异类词典的实现
    8、AI医生案例
    C语言sizeof函数解析
  • 原文地址:https://blog.csdn.net/q314235965/article/details/128059162