一,场景设计
1, Plane加一个碰撞器
2, player加一个刚体,加一个碰撞器
二, Character.ts
import {
_decorator,
Camera,
CapsuleCollider,
Component,
EventTouch,
Input,
input,
Node,
Quat,
RigidBody,
v3,
Vec2,
Vec3,
geometry,
PhysicsSystem,
PhysicsRayResult,
} from "cc";
const { ccclass, property } = _decorator;
@ccclass("Character")
export class Character extends Component {
@property({ type: RigidBody, tooltip: "角色刚体" })
private playerRigidBody: RigidBody = null;
@property({ type: Camera, tooltip: "主摄像机" })
private camera3D: Camera = null;
/**当前的屏幕坐标*/
private curScreenLocation: Vec2;
private curWorldPosition: Vec3;
private tempV3: Vec3;
private tempQuat: Quat;
private curQuat: Quat;
private tempScreenRay: geometry.Ray;
//#region player旋转相关
private readonly PLAYER_ROTATION_DURATION_SECOND: number = 0.5;
private isPlayerRotating: boolean;
private curPlayerRotationTime: number;
//#endregion
//#region player移动相关
private isPlayerMoving: boolean;
private perDistance: number;
//#endregion
protected onLoad(): void {
this.tempV3 = v3(0, 0);
this.tempQuat = new Quat();
this.curQuat = new Quat();
this.isPlayerRotating = false;
this.isPlayerMoving = false;
this.tempScreenRay = new geometry.Ray();
}
protected onEnable(): void {
this.listener(true);
}
protected onDisable(): void {
this.listener(false);
}
private listener(isAdd: boolean): void {
if (isAdd) {
input.on(Input.EventType.TOUCH_END, this.onTouchHandler, this);
} else {
input.off(Input.EventType.TOUCH_END, this.onTouchHandler, this);
}
}
private onTouchHandler(e: EventTouch): void {
switch (e.type) {
case Input.EventType.TOUCH_END: //玩家点击结束
this.curScreenLocation = e.getLocation(); //获得了屏幕的坐标
this.camera3D.screenPointToRay(
this.curScreenLocation.x,
this.curScreenLocation.y,
this.tempScreenRay
); //构建一条射线
if (
PhysicsSystem.instance.raycastClosest(
this.tempScreenRay,
PhysicsSystem.PhysicsGroup.DEFAULT
) == true
) {
this.curPlayerRotationTime = 0;
this.isPlayerMoving = false;
this.perDistance = null;
let ressult: PhysicsRayResult = PhysicsSystem.instance.raycastClosestResult; //最近的一个碰撞体
this.curWorldPosition = ressult.hitPoint;
this.curWorldPosition.y = this.node.worldPosition.y;
//获得从player指向点击点的向量
Vec3.subtract(this.tempV3, this.curWorldPosition, this.node.worldPosition);
//获得一个face指向点击点的四元数
Quat.fromViewUp(this.curQuat, this.tempV3.clone().normalize(), Vec3.UP);
this.isPlayerRotating = true;
}
break;
}
}
protected update(deltaTime: number): void {
if (this.isPlayerRotating) {
this.curPlayerRotationTime += deltaTime / this.PLAYER_ROTATION_DURATION_SECOND;
if (this.curPlayerRotationTime >= 1) {
this.curPlayerRotationTime = 1;
this.isPlayerRotating = false;
this.isPlayerMoving = true;
this.curPlayerRotationTime = 0;
this.perDistance = null;
}
this.tempQuat
.set(this.node.worldRotation)
.slerp(this.curQuat, this.curPlayerRotationTime);
this.node.setWorldRotation(this.tempQuat);
return;
}
if (this.isPlayerMoving) {
//从player指向目标点的向量
Vec3.subtract(this.tempV3, this.curWorldPosition, this.node.worldPosition);
//计算向量的模
const distance: number = this.tempV3.length();
if (this.perDistance != null && distance == this.perDistance && distance <= 0.2) {
this.isPlayerMoving = false;
} else {
this.perDistance = distance;
}
this.playerRigidBody.setLinearVelocity(this.tempV3);
}
}
protected onDestroy(): void {
this.curScreenLocation = null;
this.curWorldPosition = null;
this.tempV3 = null;
this.tempQuat = null;
this.tempScreenRay = null;
}
}
三, 结果