LazyAn-CocosCreator3D教程-玩家移动和地面uv滚动

前言

最近开始做3D项目了,用了一段时间CocosCreator3.4.1版本,记录一些简单的功能实现

  • 点击地图玩家移动

  • 摄像机跟随

  • 地面uv无限滚动

准备工作

新建一个3D工程,用cocos官方的soldier模型作为我们的玩家角色,找一张图片作为地面贴图,注意图片尺寸一定要是2的n次幂,并且,红框属性调成repeat,这样才可以实现uv滚动.

LazyAn-CocosCreator3D教程-玩家移动和地面uv滚动_第1张图片

有了地面贴图,再新建一个材质文件,并把贴图拖入

LazyAn-CocosCreator3D教程-玩家移动和地面uv滚动_第2张图片

在场景创建一个Plane,拖入材质,将主摄像机镜头调到合适的角度,前期场景工作就完成了。

LazyAn-CocosCreator3D教程-玩家移动和地面uv滚动_第3张图片


实现

1.点击地图玩家移动

通常游戏角色的移动都是固定的几种控制方式,比如虚拟摇杆移动,点击地面移动,本篇来实现点击地面移动。
「点击地面移动的过程中 有几个关键点:」

  • 点击屏幕,检测到地面的目标位置

  • 获取玩家角度,改变朝向

  • 玩家匀速移动

具体实现方式:

点击屏幕触发事件,根据触摸点从摄像机发射一条射线,射线检测到地面(地面需要添加碰撞器)之后,返回我们需要的具体数据:

const outRay = new geometry.Ray();this.mainCamera.screenPointToRay(e.getLocation().x, e.getLocation().y, outRay);let isCol = PhysicsSystem.instance.raycastClosest(outRay);

LazyAn-CocosCreator3D教程-玩家移动和地面uv滚动_第4张图片

//  获取射线返回的数据let result = PhysicsSystem.instance.raycastClosestResult;//  移动的目标位置let targetPoint = result.hitPoint;//  移动tween(this.soldier)  .to(1, { position: targetPoint })  .start()

基本的点击移动就实现了,移动当然要转头了,所以我们根据目标位置和玩家当前位置求出玩家朝向:

//  玩家角色当前位置let curSelfPoint = this.soldier.getPosition();const quat_end = new Quat(); // 最终旋转四元数const dirV3 = targetPoint.clone().subtract(curSelfPoint).normalize() // 前方向向量const dir_up = new Vec3(0, 1, 0);// 模型正好朝z轴方向Quat.fromViewUp(quat_end, dirV3, dir_up); // 根据视口的前方向和上方向计算四元数this.soldier.setRotation(quat_end);

再给个匀速移动就完成了,

​​​​​​​

let distance = targetPoint.clone().subtract(curSelfPoint).length();let moveSpeed = 4;let moveTime = distance / moveSpeed;tween(this.soldier)  .to(moveTime, { position: targetPoint })  .start()

2.摄像机跟随

「摄像机跟随的关键点:」

  • 计算玩家和摄像机的坐标差

  • 根据坐标差每帧设置摄像机坐标

具体实现方式:

获取玩家和摄像机的坐标差:

​​​​​​​

/** 获取摄像机和玩家的坐标差值 */private getTheCoordinateDifference() {  let cameraPos = this.mainCamera.node.getPosition();  let playerPos = this.soldier.getPosition();  this._differencePos = cameraPos.subtract(playerPos);}

然后在uodate里每帧给摄像机坐标赋值:    

​​​​​​​

//  upadte中调用/** 摄像机跟随玩家 */  private cameraFollowPlayer() {  let playerPos = this.soldier.getPosition();  this.mainCamera.node.setPosition(playerPos.add(this._differencePos));}

2.地面uv滚动

通常我们在做无限的地图时会用2到3块地面循环滚动来实现,但是如果玩家是360度无限制移动的话,通常都需要进行复杂的计算地面循环,很麻烦,所以我最后选择了使用uv滚动来模拟;

「地面uv滚动的关键点:」

  • 地面节点位置要实时跟玩家同步

  • 计算移动方向

  • 用代码更改材质属性

首先利用uv滚动模拟的话,地面一定要和玩家位置同步,即地面实时跟随玩家

/** 地面跟随玩家 */private mapFollowPlayer() {  let playerPos = this.soldier.getPosition();  this.planeNode.setPosition(playerPos)}

在玩家移动的代码中获取玩家移动的方向

​​​​​​​

let eulerAngles = this.soldier.eulerAngles;let toQuat = new Quat();//  欧拉角转四元数let tempQuat = Quat.fromEuler(toQuat, eulerAngles.x, eulerAngles.y, eulerAngles.z);//  移动的向量方向let normalV3 = new Vec3(0, 0, 1);//  旋转后的向量normalV3Vec3.transformQuat(normalV3, normalV3, tempQuat);//  保存玩家方向,用与地图uv滚动this.curNormalV3 = normalV3;//   打开uv滚动开关this.uvScrollSwitch = true;
tween(this.soldier)  .to(moveTime, { position: targetPoint })  .call(() => {  //  关闭uv滚动    this.uvScrollSwitch = false;  })  .start()

然后我们修改地面节点材质的tilingOffset属性,可以看到地面的纹理发生了变化,我们用代码每帧给tilingOffset赋值 根据玩家的方向计算uv偏移方向

LazyAn-CocosCreator3D教程-玩家移动和地面uv滚动_第5张图片

代码:

​​​​​​​

 /** 地图UV滚动 */private mapUVScroll(dt) {  // 滚动开关   if (!this.uvScrollSwitch) return;  //  获取当前偏移数值  let curUV: any = this.planeNode.getComponent(MeshRenderer).material.getProperty("tilingOffset");  //  玩家朝向  let curNormalV3 = this.curNormalV3;  //  模拟移动速度数值,根据需要调整数值大小  let coeNum1 = 0.5;  let coeNum2 = 1.5;  //  给材质属性赋值  this.planeNode.getComponent(MeshRenderer).material.setProperty(    "tilingOffset",    curUV.add(new Vec4(0, 0, dt * coeNum1 / coeNum2 * curNormalV3.x, dt * coeNum1 / coeNum2 * curNormalV3.z)),    0  )}


最终效果

,时长00:31

!!公众号回复“uv”获取完整代码!!


往期内容

Cocos从零开发一个翻译插件


更多精彩欢迎关注微信公众号

LazyAn-CocosCreator3D教程-玩家移动和地面uv滚动_第6张图片

“点赞“ ”在看” 鼓励一下

你可能感兴趣的:(cocoscreator,TypeScript,cocos-creator,typescript)