Files
climb/assets/scripts/PlayerController.ts

149 lines
4.5 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { _decorator, Component, Node, Vec3, input, Input, EventTouch, Camera, view } from 'cc';
const { ccclass, property } = _decorator;
@ccclass('PlayerController')
export class PlayerController extends Component {
@property(Node)
player: Node | null = null; // 玩家节点
@property(Camera)
camera: Camera | null = null; // 主摄像机
@property({ range: [1, 20] })
moveSpeed: number = 5; // 移动速度
@property
mapWidth: number = 1080; // 地图宽度
@property
mapHeight: number = 2560; // 地图高度
private isMoving: boolean = false;
private targetPosition: Vec3 = new Vec3();
private originalPosition: Vec3 = new Vec3();
onLoad() {
// 注册触摸事件
input.on(Input.EventType.TOUCH_START, this.onTouchStart, this);
}
onDestroy() {
// 移除触摸事件
input.off(Input.EventType.TOUCH_START, this.onTouchStart, this);
}
start() {
if (this.player) {
this.originalPosition.set(this.player.position);
}
}
private onTouchStart(event: EventTouch) {
if (!this.player || !this.camera) return;
// 获取触摸点的UI坐标
const touchLocation = event.getUILocation();
// 将UI坐标转换为世界坐标
const worldPos = this.screenToWorldPoint(touchLocation);
console.log(`触摸UI坐标: (${touchLocation.x}, ${touchLocation.y})`);
console.log(`转换后世界坐标: (${worldPos.x.toFixed(2)}, ${worldPos.y.toFixed(2)})`);
this.moveToPosition(worldPos);
}
private screenToWorldPoint(screenPos: { x: number, y: number }): Vec3 {
if (!this.camera) {
console.error('Camera未设置无法进行坐标转换');
return new Vec3(screenPos.x, screenPos.y, 0);
}
// 获取可见区域大小
const visibleSize = view.getVisibleSize();
// 计算屏幕中心点
const centerX = visibleSize.width * 0.5;
const centerY = visibleSize.height * 0.5;
// 将屏幕坐标转换为以屏幕中心为原点的坐标
const normalizedX = screenPos.x - centerX;
const normalizedY = screenPos.y - centerY;
// 考虑相机的位置偏移
const cameraPos = this.camera.node.position;
// 计算世界坐标
const worldX = normalizedX + cameraPos.x;
const worldY = normalizedY + cameraPos.y;
return new Vec3(worldX, worldY, 0);
}
private moveToPosition(worldPos: Vec3) {
if (!this.player) return;
// 限制目标位置在地图边界内
const clampedPos = this.clampPlayerPosition(worldPos);
// 设置目标位置保持Z轴不变
this.targetPosition.set(clampedPos.x, clampedPos.y, this.player.position.z);
this.isMoving = true;
console.log(`移动目标: (${clampedPos.x.toFixed(2)}, ${clampedPos.y.toFixed(2)})`);
}
// 限制玩家位置在地图边界内
private clampPlayerPosition(position: Vec3): Vec3 {
// 计算地图边界地图锚点为0.5,0.5,所以范围是-mapWidth/2到+mapWidth/2
const mapHalfWidth = this.mapWidth * 0.5;
const mapHalfHeight = this.mapHeight * 0.5;
// 限制玩家位置
const clampedPosition = position.clone();
clampedPosition.x = Math.max(-mapHalfWidth, Math.min(mapHalfWidth, position.x));
clampedPosition.y = Math.max(-mapHalfHeight, Math.min(mapHalfHeight, position.y));
return clampedPosition;
}
update(deltaTime: number) {
if (!this.isMoving || !this.player) return;
const currentPos = this.player.position;
const distance = Vec3.distance(currentPos, this.targetPosition);
// 如果距离很小,直接到达目标位置
if (distance < 0.1) {
this.player.position = this.targetPosition.clone();
this.isMoving = false;
console.log('到达目标位置');
return;
}
// 计算移动方向
const direction = new Vec3();
Vec3.subtract(direction, this.targetPosition, currentPos);
direction.normalize();
// 计算这一帧应该移动的距离
const moveDistance = this.moveSpeed * deltaTime * 100; // 增加移动速度倍数
// 如果剩余距离小于这一帧要移动的距离,直接到达目标
if (distance <= moveDistance) {
this.player.position = this.targetPosition.clone();
this.isMoving = false;
console.log('到达目标位置');
} else {
// 正常移动
const newPosition = new Vec3();
Vec3.scaleAndAdd(newPosition, currentPos, direction, moveDistance);
// 确保新位置在地图边界内
const clampedNewPosition = this.clampPlayerPosition(newPosition);
this.player.position = clampedNewPosition;
}
}
}