cocos creator实现浏览星球的功能,附源码
创始人
2024-02-21 14:47:03
0

预览效果:

 

技术要点:

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

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

图片已进行各概念的说明

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

也可自己提前绑定。

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

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

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

可以通过设置

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

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

控制器(planet_view_controller)代码:

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

import { _decorator, Component, Node, Camera, Input, input, EventTouch, Vec2, Quat, Vec3, screen, tween, Tween, Collider, SphereCollider, geometry, PhysicsSystem, EventHandler } from "cc";
const { ccclass, property } = _decorator;
@ccclass("PlanetViewController")
export class PlanetViewController extends Component {start() {this.bindInputEvent();this.setLimitEuler();this.clickManagerStart();}//浏览功能区@property({
    displayName: "顶部额外限制角度",})private upLimitAngle = 0;@property({
    displayName: "底部额外限制角度",})private downLimitAngle = 0;@property(Camera)private centerCamera!: Camera;private bindInputEvent() {
    input.on(Input.EventType.TOUCH_START, this.onTouchStart, this);
    input.on(Input.EventType.TOUCH_MOVE, this.onTouchMove, this);
    input.on(Input.EventType.TOUCH_END, this.onTouchEnd, this);}private limitEdgeEuler = 0;private setLimitEuler() {this.limitEdgeEuler = (180 * Math.atan(Math.tan((this.centerCamera.fov * Math.PI) / 360) / this.centerCamera.camera.aspect)) / Math.PI;}private startLocation = new Vec2();private onTouchStart(e: EventTouch) {
    e.getLocation(this.startLocation);
    Tween.stopAllByTarget(this.lastRotaionSpeed);}private lastRotaionSpeed = new Vec2();private onTouchMove(e: EventTouch) {
    e.getDelta(this.lastRotaionSpeed);this.rotateCenterCamera(this.lastRotaionSpeed);}private clickLocation = new Vec2();private onTouchEnd(e: EventTouch) {
    e.getLocation(this.clickLocation);const dis = Vec2.squaredDistance(this.startLocation, this.clickLocation);if (dis <= 0.1) {this.node.emit("click", this.clickLocation);console.log("click");return;}tween(this.lastRotaionSpeed).to(0.5,{
          x: 0,
          y: 0,},{
          easing: "sineOut",
          onUpdate: () => {this.rotateCenterCamera(this.lastRotaionSpeed);},}).start();}private curRotateResultEuler = new Vec3();private rotateQuat = new Quat();private lastRotationQuat = new Quat();private rotateCenterCamera(volume: Vec2) {
    Quat.fromAxisAngle(this.rotateQuat, Vec3.UP, (volume.x * 0.785) / screen.windowSize.width);
    Quat.rotateX(this.rotateQuat, this.rotateQuat, (-volume.y * 0.785) / screen.windowSize.height);this.lastRotationQuat.set(this.centerCamera.node.rotation);
    Quat.multiply(this.lastRotationQuat, this.lastRotationQuat, this.rotateQuat);this.lastRotationQuat.getEulerAngles(this.curRotateResultEuler);this.centerCamera.node.rotate(this.rotateQuat);const isOverUp = this.curRotateResultEuler.x < -this.limitEdgeEuler + this.upLimitAngle;const isOverDown = this.curRotateResultEuler.x > this.limitEdgeEuler - this.downLimitAngle;if (isOverUp || isOverDown) {this.lastRotationQuat.set(this.centerCamera.node.rotation);this.lastRotationQuat.getEulerAngles(this.curRotateResultEuler);const { y, z } = this.curRotateResultEuler;const x = isOverUp ? -this.limitEdgeEuler + this.upLimitAngle : this.limitEdgeEuler - this.downLimitAngle;this.centerCamera.node.setRotationFromEuler(x, y, z);}const { x, y } = this.centerCamera.node.eulerAngles;this.centerCamera.node.setRotationFromEuler(x, y, 0);}//点击检测功能区@property([EventHandler])private collisionEventHandlerArray: EventHandler[] = [];@property([Node])private collisionNodeArray: Node[] = [];private clickManagerStart() {this.setCollisionNodeCollider();this.bindClickEvent();}private setCollisionNodeCollider() {this.collisionNodeArray.forEach((node) => {let collider = node.getComponent(Collider);if (!collider) {
        collider = node.addComponent(SphereCollider);}
      collider.isTrigger = true;});}private clickRay = new geometry.Ray();private bindClickEvent() {this.node.on("click", ({ x, y }: Vec2) => {if (this.collisionNodeArray.length === 0) return;this.centerCamera.screenPointToRay(x, y, this.clickRay);
      PhysicsSystem.instance.raycast(this.clickRay);if (PhysicsSystem.instance.raycastResults.length) {const firstColliderNode = PhysicsSystem.instance.raycastResults[0].collider.node;this.collisionEventHandlerArray.forEach((handler) => handler.emit([firstColliderNode]));}});}
}

相关内容

热门资讯

喜欢穿一身黑的男生性格(喜欢穿... 今天百科达人给各位分享喜欢穿一身黑的男生性格的知识,其中也会对喜欢穿一身黑衣服的男人人好相处吗进行解...
发春是什么意思(思春和发春是什... 本篇文章极速百科给大家谈谈发春是什么意思,以及思春和发春是什么意思对应的知识点,希望对各位有所帮助,...
网络用语zl是什么意思(zl是... 今天给各位分享网络用语zl是什么意思的知识,其中也会对zl是啥意思是什么网络用语进行解释,如果能碰巧...
为什么酷狗音乐自己唱的歌不能下... 本篇文章极速百科小编给大家谈谈为什么酷狗音乐自己唱的歌不能下载到本地?,以及为什么酷狗下载的歌曲不是...
华为下载未安装的文件去哪找(华... 今天百科达人给各位分享华为下载未安装的文件去哪找的知识,其中也会对华为下载未安装的文件去哪找到进行解...
怎么往应用助手里添加应用(应用... 今天百科达人给各位分享怎么往应用助手里添加应用的知识,其中也会对应用助手怎么添加微信进行解释,如果能...
家里可以做假山养金鱼吗(假山能... 今天百科达人给各位分享家里可以做假山养金鱼吗的知识,其中也会对假山能放鱼缸里吗进行解释,如果能碰巧解...
四分五裂是什么生肖什么动物(四... 本篇文章极速百科小编给大家谈谈四分五裂是什么生肖什么动物,以及四分五裂打一生肖是什么对应的知识点,希...
一帆风顺二龙腾飞三阳开泰祝福语... 本篇文章极速百科给大家谈谈一帆风顺二龙腾飞三阳开泰祝福语,以及一帆风顺二龙腾飞三阳开泰祝福语结婚对应...
美团联名卡审核成功待激活(美团... 今天百科达人给各位分享美团联名卡审核成功待激活的知识,其中也会对美团联名卡审核未通过进行解释,如果能...