mirror of
http://junepve.top:3000/chicrobot/CINC.git
synced 2026-10-30 04:11:29 +08:00
235 lines
6.5 KiB
JavaScript
235 lines
6.5 KiB
JavaScript
// objects/Unit.js
|
||
export default class Unit extends Phaser.Physics.Arcade.Sprite {
|
||
constructor(scene, x, y, texture) {
|
||
super(scene, x, y, texture);
|
||
scene.add.existing(this);
|
||
scene.physics.add.existing(this);
|
||
|
||
// 设置角色原点为底部中点
|
||
this.setOrigin(0.5, 1);
|
||
|
||
// 设置角色深度,确保显示在指示器上方
|
||
this.setDepth(10);
|
||
|
||
// 启用圆形碰撞体(更自然)
|
||
this.setCircle(14);
|
||
|
||
// 启用与世界边界的碰撞(必须配合 physics.world.setBounds)
|
||
this.setCollideWorldBounds(true);
|
||
|
||
// 移动目标(x, y)
|
||
this.target = null;
|
||
|
||
// 选中状态
|
||
this.isSelected = false;
|
||
this.selectedIndicator = null;
|
||
this.createSelectedIndicator();
|
||
|
||
// 目标地点显示
|
||
this.targetIndicator = null;
|
||
this.pathGraphics = null;
|
||
|
||
// 移动控制
|
||
this.canMove = true;
|
||
}
|
||
|
||
/**
|
||
* 创建选中状态指示器
|
||
*/
|
||
createSelectedIndicator() {
|
||
// 创建一个外圈指示器,默认隐藏
|
||
// 椭圆指示器:中心位于图片底边中心,宽度为角色宽度的1.4倍,高度为角色高度的0.3倍
|
||
this.selectedIndicator = this.scene.add.ellipse(this.x, this.y, this.width * 1.5, this.height * 0.5, 0x00ff00, 0.0);
|
||
this.selectedIndicator.setStrokeStyle(2, 0x00ff00, 1);
|
||
this.selectedIndicator.setVisible(false);
|
||
|
||
// 确保指示器与单位一起移动
|
||
this.selectedIndicator.setOrigin(0.5, 0.5);
|
||
// 移除固定位置设置,让指示器随单位和相机一起移动
|
||
this.selectedIndicator.setScrollFactor(1, 1);
|
||
// 设置较低的深度,确保角色显示在上方
|
||
this.selectedIndicator.setDepth(5);
|
||
}
|
||
|
||
/**
|
||
* 创建目标地点指示器
|
||
*/
|
||
createTargetIndicator() {
|
||
if (!this.targetIndicator) {
|
||
// 创建目标地点指示器(红色圆点)
|
||
this.targetIndicator = this.scene.add.circle(0, 0, 8, 0xff0000, 1);
|
||
this.targetIndicator.setOrigin(0.5, 0.5);
|
||
this.targetIndicator.setScrollFactor(1, 1);
|
||
this.targetIndicator.setVisible(false);
|
||
// 设置较低的深度,确保角色显示在上方
|
||
this.targetIndicator.setDepth(5);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 创建寻路路径图形
|
||
*/
|
||
createPathGraphics() {
|
||
if (!this.pathGraphics) {
|
||
// 创建图形对象用于绘制路径
|
||
this.pathGraphics = this.scene.add.graphics();
|
||
this.pathGraphics.setScrollFactor(1, 1);
|
||
// 设置较低的深度,确保角色显示在上方
|
||
this.pathGraphics.setDepth(5);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 设置单位选中状态
|
||
* @param {boolean} isSelected
|
||
*/
|
||
setSelected(isSelected) {
|
||
this.isSelected = isSelected;
|
||
if (this.selectedIndicator) {
|
||
this.selectedIndicator.setVisible(isSelected);
|
||
}
|
||
|
||
// 只有选中时才显示目标地点和路径
|
||
this.updateTargetVisibility();
|
||
}
|
||
|
||
/**
|
||
* 更新目标地点和路径的可见性
|
||
*/
|
||
updateTargetVisibility() {
|
||
if (this.targetIndicator) {
|
||
this.targetIndicator.setVisible(this.isSelected && this.target !== null);
|
||
}
|
||
if (this.pathGraphics) {
|
||
this.pathGraphics.clear();
|
||
// 只有选中且有目标时才绘制路径
|
||
if (this.isSelected && this.target !== null) {
|
||
this.drawPath();
|
||
}
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 绘制寻路路径
|
||
*/
|
||
drawPath() {
|
||
if (!this.pathGraphics || !this.target) {
|
||
return;
|
||
}
|
||
|
||
this.pathGraphics.clear();
|
||
this.pathGraphics.lineStyle(2, 0x00ff00, 0.8);
|
||
this.pathGraphics.beginPath();
|
||
this.pathGraphics.moveTo(this.x, this.y);
|
||
this.pathGraphics.lineTo(this.target.x, this.target.y);
|
||
this.pathGraphics.stroke();
|
||
}
|
||
|
||
/**
|
||
* 设置移动目标点
|
||
* @param {number} x
|
||
* @param {number} y
|
||
*/
|
||
setTarget(x, y) {
|
||
// 获取世界边界
|
||
const worldBounds = this.scene.physics.world.bounds;
|
||
|
||
// 限制目标点在世界边界内
|
||
const clampedX = Math.max(worldBounds.x, Math.min(worldBounds.right, x));
|
||
const clampedY = Math.max(worldBounds.y, Math.min(worldBounds.bottom, y));
|
||
|
||
this.target = { x: clampedX, y: clampedY };
|
||
|
||
// 创建目标指示器和路径图形(如果不存在)
|
||
this.createTargetIndicator();
|
||
this.createPathGraphics();
|
||
|
||
// 更新目标指示器位置
|
||
if (this.targetIndicator) {
|
||
this.targetIndicator.setPosition(this.target.x, this.target.y);
|
||
}
|
||
|
||
// 更新目标可见性和路径绘制
|
||
this.updateTargetVisibility();
|
||
}
|
||
|
||
/**
|
||
* 清除目标并停止移动
|
||
*/
|
||
clearTarget() {
|
||
this.target = null;
|
||
this.setVelocity(0, 0);
|
||
|
||
// 隐藏目标指示器和清除路径
|
||
if (this.targetIndicator) {
|
||
this.targetIndicator.setVisible(false);
|
||
}
|
||
if (this.pathGraphics) {
|
||
this.pathGraphics.clear();
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 相对移动控制(用于键盘/虚拟摇杆)
|
||
* @param {number} x - 水平方向 (-1 到 1)
|
||
* @param {number} y - 垂直方向 (-1 到 1)
|
||
*/
|
||
moveRelative(x, y) {
|
||
// 检查是否可以移动
|
||
if (this.canMove === false) {
|
||
this.setVelocity(0, 0);
|
||
return;
|
||
}
|
||
|
||
const speed = 150; // 单位:像素/秒
|
||
// 归一化方向向量
|
||
const magnitude = Math.sqrt(x * x + y * y);
|
||
if (magnitude > 0) {
|
||
// 有按键输入时,清除目标点,切换到直接控制模式
|
||
this.clearTarget();
|
||
const normalizedX = x / magnitude;
|
||
const normalizedY = y / magnitude;
|
||
this.setVelocity(normalizedX * speed, normalizedY * speed);
|
||
} else {
|
||
// 没有按键输入时,保持当前的目标点(如果有的话)
|
||
this.setVelocity(0, 0);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 每帧更新移动逻辑(需在 GameScene.update 中调用)
|
||
*/
|
||
update() {
|
||
// 更新选中指示器位置
|
||
if (this.selectedIndicator && this.isSelected) {
|
||
// 保持与创建时相同的位置偏移,确保指示器显示在角色底部
|
||
this.selectedIndicator.setPosition(this.x, this.y);
|
||
}
|
||
|
||
// 更新路径绘制(单位位置变化时)
|
||
if (this.isSelected && this.target !== null) {
|
||
this.drawPath();
|
||
}
|
||
}
|
||
|
||
updateMovement() {
|
||
if (!this.target) {
|
||
return;
|
||
}
|
||
|
||
const dx = this.target.x - this.x;
|
||
const dy = this.target.y - this.y;
|
||
const distance = Math.sqrt(dx * dx + dy * dy);
|
||
|
||
// 到达阈值:5 像素内视为“到达”
|
||
if (distance < 5) {
|
||
// 精确对齐到目标点(可选)
|
||
this.setPosition(this.target.x, this.target.y);
|
||
this.clearTarget();
|
||
} else {
|
||
const speed = 150; // 单位:像素/秒
|
||
const angle = Math.atan2(dy, dx);
|
||
this.setVelocity(Math.cos(angle) * speed, Math.sin(angle) * speed);
|
||
}
|
||
}
|
||
} |