mirror of
http://junepve.top:3000/chicrobot/CINC.git
synced 2026-10-29 19:51:29 +08:00
refactor(SRC) 重构核心场景路径位置
This commit is contained in:
1 parent
942ba567f3
commit
cbbed1519e
18 files changed
+845
-473
No files matched your search
@@ -51,23 +51,25 @@ import WeaponTestScene from './scenes/testScenes/WeaponTestScene.js';
|
|||||||
|
|
||||||
// 故事场景
|
// 故事场景
|
||||||
// 开天辟地,创建场景
|
// 开天辟地,创建场景
|
||||||
import PrimordialDevide from './scenes/storeScenes/PrimordialDevide.js';
|
import PrimordialDevide from './src/scenes/PrimordialDevide.js';
|
||||||
// 日月山川,创建时间,地图、物品
|
// 日月山川,创建时间,地图、物品
|
||||||
import WorldTime from './scenes/storeScenes/WorldTime.js';
|
import WorldTime from './src/scenes/WorldTime.js';
|
||||||
import WorldLand from './scenes/storeScenes/WorldLand.js';
|
import WorldLand from './src/scenes/WorldLand.js';
|
||||||
// 女娲造人,创建角色
|
// 女娲造人,创建角色
|
||||||
import BreatheLife from './scenes/storeScenes/BreatheLife.js';
|
import BreatheLife from './src/scenes/BreatheLife.js';
|
||||||
// 伏羲画卦,创建角色控制与信息栏
|
// 伏羲画卦,创建角色控制、信息栏与多语言
|
||||||
import Control from './scenes/storeScenes/Control.js';
|
import Control from './src/scenes/Control.js';
|
||||||
// import InfoBar from './scenes/storeScenes/InfoBar.js';
|
// import InfoBar from './src/scenes/InfoBar.js';
|
||||||
// // 钻木取火,添加合成系统
|
// import MultiLanguage from './src/scenes/MultiLanguage.js';
|
||||||
// import Synthesis from './scenes/storeScenes/Synthesis.js';
|
// // 钻木取火,添加光影与合成系统
|
||||||
|
// import Shadow from './src/scenes/Shadow.js';
|
||||||
|
// import Synthesis from './src/scenes/Synthesis.js';
|
||||||
// // 神农百草,创建耕种系统
|
// // 神农百草,创建耕种系统
|
||||||
// import Farming from './scenes/storeScenes/Farming.js';
|
// import Farming from './src/scenes/Farming.js';
|
||||||
// // 涿鹿之战,创建战斗系统
|
// // 涿鹿之战,创建战斗系统
|
||||||
// import Battle from './scenes/storeScenes/Battle.js';
|
// import Battle from './src/scenes/Battle.js';
|
||||||
// // 大禹治水,创建地形系统
|
// // 大禹治水,创建建造,含地形改造
|
||||||
// import Terrain from './scenes/storeScenes/Terrain.js';
|
// import Building from './src/scenes/Building.js';
|
||||||
|
|
||||||
// 创建游戏的最终配置对象
|
// 创建游戏的最终配置对象
|
||||||
const config = {
|
const config = {
|
||||||
|
|||||||
Whitespace-only changes.
Whitespace-only changes.
@@ -1,79 +0,0 @@
|
|||||||
export default class Joystick {
|
|
||||||
constructor(scene, x, y, radius, baseColor, thumbColor) {
|
|
||||||
this.scene = scene
|
|
||||||
this.x = x
|
|
||||||
this.y = y
|
|
||||||
this.radius = radius
|
|
||||||
this.baseColor = baseColor
|
|
||||||
this.thumbColor = thumbColor
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* 创建摇杆,设置层级
|
|
||||||
*/
|
|
||||||
createJoystick(layer = 100) {
|
|
||||||
// 创建基座
|
|
||||||
this.joystickBase = this.scene.add.circle(0, 0, this.radius, this.baseColor)
|
|
||||||
this.joystickBase.setPosition(this.x, this.y)
|
|
||||||
// 创建按钮
|
|
||||||
this.joystickButton = this.scene.add.circle(0, 0, this.radius / 2, this.thumbColor)
|
|
||||||
this.joystickButton.setPosition(this.x, this.y)
|
|
||||||
// 设置层级
|
|
||||||
this.joystickBase.setDepth(layer)
|
|
||||||
this.joystickButton.setDepth(layer)
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* 获取摇杆归一化方向与力度
|
|
||||||
* @returns {Object} 归一化方向 {x, y} 与力度 magnitude
|
|
||||||
*/
|
|
||||||
getJoystickDirection() {
|
|
||||||
// 获取摇杆方向,归一化
|
|
||||||
const direction = {
|
|
||||||
x: this.joystickButton.x - this.joystickBase.x,
|
|
||||||
y: this.joystickButton.y - this.joystickBase.y,
|
|
||||||
}
|
|
||||||
// 计算力度
|
|
||||||
const magnitude = Math.sqrt(direction.x ** 2 + direction.y ** 2)
|
|
||||||
// 归一化方向
|
|
||||||
direction.x /= magnitude
|
|
||||||
direction.y /= magnitude
|
|
||||||
return {direction, magnitude}
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* 重置摇杆位置
|
|
||||||
*/
|
|
||||||
resetJoystick() {
|
|
||||||
this.joystickButton.setPosition(this.x, this.y)
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* 监听摇杆输入
|
|
||||||
*/
|
|
||||||
listenJoystickInput() {
|
|
||||||
// 监听按钮按下事件
|
|
||||||
this.joystickButton.on('pointerdown', (pointer) => {
|
|
||||||
this.joystickButton.setPosition(pointer.x, pointer.y)
|
|
||||||
})
|
|
||||||
// 监听按钮移动事件
|
|
||||||
this.joystickButton.on('pointermove', (pointer) => {
|
|
||||||
// 计算摇杆按钮到基座中心的距离
|
|
||||||
const dx = pointer.x - this.x
|
|
||||||
const dy = pointer.y - this.y
|
|
||||||
const distance = Math.sqrt(dx * dx + dy * dy)
|
|
||||||
|
|
||||||
if (distance > this.radius) {
|
|
||||||
// 限制在基座范围内
|
|
||||||
const angle = Math.atan2(dy, dx)
|
|
||||||
this.joystickButton.setPosition(
|
|
||||||
this.x + this.radius * Math.cos(angle),
|
|
||||||
this.y + this.radius * Math.sin(angle)
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
// 在基座范围内,跟随手指
|
|
||||||
this.joystickButton.setPosition(pointer.x, pointer.y)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
// 监听按钮松开事件
|
|
||||||
this.joystickButton.on('pointerup', () => {
|
|
||||||
this.resetJoystick()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Whitespace-only changes.
@@ -0,0 +1,72 @@
|
|||||||
|
/**
|
||||||
|
* AI 行为基类
|
||||||
|
*
|
||||||
|
* 定义单位的行为模式,用于实现不同的 AI 逻辑
|
||||||
|
*/
|
||||||
|
export default class AIBehavior {
|
||||||
|
/**
|
||||||
|
* 构造函数
|
||||||
|
* @param {Unit} unit - 单位对象
|
||||||
|
*/
|
||||||
|
constructor(unit) {
|
||||||
|
this.unit = unit;
|
||||||
|
this.isActive = false;
|
||||||
|
this.target = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 激活行为
|
||||||
|
*/
|
||||||
|
activate() {
|
||||||
|
this.isActive = true;
|
||||||
|
this.onStart();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 停用行为
|
||||||
|
*/
|
||||||
|
deactivate() {
|
||||||
|
this.isActive = false;
|
||||||
|
this.onStop();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新行为
|
||||||
|
* @param {number} delta - 时间增量
|
||||||
|
*/
|
||||||
|
update(delta) {
|
||||||
|
if (!this.isActive) return;
|
||||||
|
this.onUpdate(delta);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 行为开始时的回调
|
||||||
|
*/
|
||||||
|
onStart() {
|
||||||
|
// 子类重写
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 行为停止时的回调
|
||||||
|
*/
|
||||||
|
onStop() {
|
||||||
|
// 子类重写
|
||||||
|
this.target = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 行为更新时的回调
|
||||||
|
* @param {number} delta - 时间增量
|
||||||
|
*/
|
||||||
|
onUpdate(delta) {
|
||||||
|
// 子类重写
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置目标
|
||||||
|
* @param {Object} target - 目标对象
|
||||||
|
*/
|
||||||
|
setTarget(target) {
|
||||||
|
this.target = target;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,107 @@
|
|||||||
|
/**
|
||||||
|
* 玩家控制行为类
|
||||||
|
*
|
||||||
|
* 实现玩家通过摇杆或键盘控制单位的行为
|
||||||
|
*/
|
||||||
|
import AIBehavior from './AIBehavior.js';
|
||||||
|
|
||||||
|
export default class PlayerControlBehavior extends AIBehavior {
|
||||||
|
/**
|
||||||
|
* 构造函数
|
||||||
|
* @param {Unit} unit - 单位对象
|
||||||
|
* @param {Object} options - 配置选项
|
||||||
|
*/
|
||||||
|
constructor(unit, options = {}) {
|
||||||
|
super(unit);
|
||||||
|
|
||||||
|
this.speed = options.speed || 200;
|
||||||
|
this.useJoystick = options.useJoystick !== false;
|
||||||
|
this.useKeyboard = options.useKeyboard !== false;
|
||||||
|
|
||||||
|
this.moveDirection = { x: 0, y: 0 };
|
||||||
|
this.joystickEventName = options.joystickEventName || 'move-relative';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 行为开始
|
||||||
|
*/
|
||||||
|
onStart() {
|
||||||
|
if (this.useJoystick) {
|
||||||
|
this.setupJoystickControl();
|
||||||
|
}
|
||||||
|
if (this.useKeyboard) {
|
||||||
|
this.setupKeyboardControl();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 行为停止
|
||||||
|
*/
|
||||||
|
onStop() {
|
||||||
|
this.moveDirection = { x: 0, y: 0 };
|
||||||
|
this.unit.stopMovement();
|
||||||
|
|
||||||
|
if (this.useJoystick) {
|
||||||
|
this.teardownJoystickControl();
|
||||||
|
}
|
||||||
|
if (this.useKeyboard) {
|
||||||
|
this.teardownKeyboardControl();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 行为更新
|
||||||
|
* @param {number} delta - 时间增量
|
||||||
|
*/
|
||||||
|
onUpdate(delta) {
|
||||||
|
if (this.moveDirection.x !== 0 || this.moveDirection.y !== 0) {
|
||||||
|
this.unit.setMovementDirection(this.moveDirection);
|
||||||
|
} else {
|
||||||
|
this.unit.stopMovement();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置摇杆控制
|
||||||
|
*/
|
||||||
|
setupJoystickControl() {
|
||||||
|
this.joystickHandler = (data) => {
|
||||||
|
this.moveDirection = { x: data.x, y: data.y };
|
||||||
|
};
|
||||||
|
|
||||||
|
this.unit.scene.events.on(this.joystickEventName, this.joystickHandler);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 移除摇杆控制
|
||||||
|
*/
|
||||||
|
teardownJoystickControl() {
|
||||||
|
if (this.joystickHandler) {
|
||||||
|
this.unit.scene.events.off(this.joystickEventName, this.joystickHandler);
|
||||||
|
this.joystickHandler = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置键盘控制
|
||||||
|
*/
|
||||||
|
setupKeyboardControl() {
|
||||||
|
this.cursors = this.unit.scene.input.keyboard.createCursorKeys();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 移除键盘控制
|
||||||
|
*/
|
||||||
|
teardownKeyboardControl() {
|
||||||
|
this.cursors = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置移动速度
|
||||||
|
* @param {number} speed - 移动速度
|
||||||
|
*/
|
||||||
|
setSpeed(speed) {
|
||||||
|
this.speed = speed;
|
||||||
|
this.unit.setSpeed(speed);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,161 @@
|
|||||||
|
/**
|
||||||
|
* 搜索行为类
|
||||||
|
*
|
||||||
|
* 实现单位自动搜索并收集目标物品的行为
|
||||||
|
*/
|
||||||
|
import AIBehavior from './AIBehavior.js';
|
||||||
|
|
||||||
|
export default class SearchBehavior extends AIBehavior {
|
||||||
|
/**
|
||||||
|
* 构造函数
|
||||||
|
* @param {Unit} unit - 单位对象
|
||||||
|
* @param {Array} targets - 目标物品数组
|
||||||
|
* @param {Object} options - 配置选项
|
||||||
|
*/
|
||||||
|
constructor(unit, targets, options = {}) {
|
||||||
|
super(unit);
|
||||||
|
|
||||||
|
this.targets = targets;
|
||||||
|
this.searchDelay = options.searchDelay || 500;
|
||||||
|
this.moveSpeed = options.moveSpeed || 200;
|
||||||
|
this.onCollect = options.onCollect || null;
|
||||||
|
this.onComplete = options.onComplete || null;
|
||||||
|
|
||||||
|
this.currentTarget = null;
|
||||||
|
this.isMoving = false;
|
||||||
|
this.delayTimer = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 行为开始
|
||||||
|
*/
|
||||||
|
onStart() {
|
||||||
|
this.searchNearestTarget();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 行为停止
|
||||||
|
*/
|
||||||
|
onStop() {
|
||||||
|
if (this.delayTimer) {
|
||||||
|
this.delayTimer.remove();
|
||||||
|
this.delayTimer = null;
|
||||||
|
}
|
||||||
|
this.currentTarget = null;
|
||||||
|
this.isMoving = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 行为更新
|
||||||
|
* @param {number} delta - 时间增量
|
||||||
|
*/
|
||||||
|
onUpdate(delta) {
|
||||||
|
if (this.isMoving) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this.currentTarget) {
|
||||||
|
this.searchNearestTarget();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 搜索最近的目标
|
||||||
|
*/
|
||||||
|
searchNearestTarget() {
|
||||||
|
if (!this.targets || this.targets.length === 0) {
|
||||||
|
if (this.onComplete) {
|
||||||
|
this.onComplete();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let nearestTarget = null;
|
||||||
|
let minDistance = Infinity;
|
||||||
|
|
||||||
|
for (const target of this.targets) {
|
||||||
|
if (target.alpha === 0.5) continue;
|
||||||
|
|
||||||
|
const distance = Phaser.Math.Distance.Between(
|
||||||
|
this.unit.x,
|
||||||
|
this.unit.y,
|
||||||
|
target.x,
|
||||||
|
target.y
|
||||||
|
);
|
||||||
|
|
||||||
|
if (distance < minDistance) {
|
||||||
|
minDistance = distance;
|
||||||
|
nearestTarget = target;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nearestTarget) {
|
||||||
|
this.moveToTarget(nearestTarget, minDistance);
|
||||||
|
} else {
|
||||||
|
if (this.onComplete) {
|
||||||
|
this.onComplete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 移动到目标位置
|
||||||
|
* @param {Phaser.GameObjects.Sprite} target - 目标对象
|
||||||
|
* @param {number} distance - 距离
|
||||||
|
*/
|
||||||
|
moveToTarget(target, distance) {
|
||||||
|
this.currentTarget = target;
|
||||||
|
this.isMoving = true;
|
||||||
|
|
||||||
|
const duration = distance * 10;
|
||||||
|
|
||||||
|
this.unit.scene.tweens.add({
|
||||||
|
targets: this.unit,
|
||||||
|
x: target.x,
|
||||||
|
y: target.y,
|
||||||
|
duration: duration,
|
||||||
|
ease: 'Linear',
|
||||||
|
onComplete: () => {
|
||||||
|
this.collectTarget(target);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 收集目标
|
||||||
|
* @param {Phaser.GameObjects.Sprite} target - 目标对象
|
||||||
|
*/
|
||||||
|
collectTarget(target) {
|
||||||
|
target.setAlpha(0.5);
|
||||||
|
|
||||||
|
if (this.onCollect) {
|
||||||
|
this.onCollect(target);
|
||||||
|
}
|
||||||
|
|
||||||
|
const index = this.targets.indexOf(target);
|
||||||
|
if (index > -1) {
|
||||||
|
this.targets.splice(index, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
target.destroy();
|
||||||
|
|
||||||
|
this.currentTarget = null;
|
||||||
|
this.isMoving = false;
|
||||||
|
|
||||||
|
const delay = Phaser.Math.Between(this.searchDelay / 2, this.searchDelay * 1.5);
|
||||||
|
this.delayTimer = this.unit.scene.time.delayedCall(delay, () => {
|
||||||
|
this.searchNearestTarget();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新目标数组
|
||||||
|
* @param {Array} targets - 新的目标数组
|
||||||
|
*/
|
||||||
|
updateTargets(targets) {
|
||||||
|
this.targets = targets;
|
||||||
|
if (!this.currentTarget) {
|
||||||
|
this.searchNearestTarget();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,72 @@
|
|||||||
|
export default class Joystick {
|
||||||
|
constructor(scene, x, y) {
|
||||||
|
this.scene = scene // 场景上下文
|
||||||
|
this.centerX = x // 摇杆中心x坐标
|
||||||
|
this.centerY = y // 摇杆中心y坐标
|
||||||
|
this.radius = 50 // 摇杆半径
|
||||||
|
this.baseColor = 0x888888
|
||||||
|
this.thumbColor = 0xcccccc
|
||||||
|
|
||||||
|
this.activePointer = null; // 保持单一激活指针,但允许不同指针触发
|
||||||
|
this.isActive = false; // 是否激活
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 创建摇杆,设置层级
|
||||||
|
*/
|
||||||
|
createJoystick(layer = 100) {
|
||||||
|
// 创建基座
|
||||||
|
this.joystickBase = this.scene.add.circle(this.centerX, this.centerY, this.radius, this.baseColor)
|
||||||
|
// 创建按钮
|
||||||
|
this.joystickButton = this.scene.add.circle(this.centerX, this.centerY, this.radius / 2, this.thumbColor)
|
||||||
|
// 设置层级
|
||||||
|
this.joystickBase.setDepth(layer)
|
||||||
|
this.joystickButton.setDepth(layer)
|
||||||
|
// 不随相机移动
|
||||||
|
this.joystickBase.setScrollFactor(0)
|
||||||
|
this.joystickButton.setScrollFactor(0)
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 获取摇杆归一化方向与力度
|
||||||
|
* @returns {Object} 归一化方向 {x, y} 与力度 magnitude
|
||||||
|
*/
|
||||||
|
getJoystickDirection() {
|
||||||
|
// 获取摇杆方向,归一化
|
||||||
|
const direction = {
|
||||||
|
x: this.joystickButton.x - this.joystickBase.x,
|
||||||
|
y: this.joystickButton.y - this.joystickBase.y,
|
||||||
|
}
|
||||||
|
// 计算力度
|
||||||
|
const magnitude = Math.sqrt(direction.x ** 2 + direction.y ** 2)
|
||||||
|
// 归一化方向
|
||||||
|
direction.x /= magnitude
|
||||||
|
direction.y /= magnitude
|
||||||
|
return {direction, magnitude}
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 重置摇杆位置
|
||||||
|
*/
|
||||||
|
resetJoystick() {
|
||||||
|
this.joystickButton.setPosition(this.centerX, this.centerY)
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 监听摇杆输入
|
||||||
|
*/
|
||||||
|
startJoystickListen() {
|
||||||
|
// 监听指针按下事件
|
||||||
|
this.scene.input.on('pointerdown', (ptr) => {
|
||||||
|
if (this.isInBase(ptr)) {
|
||||||
|
// 只有在没有激活指针时才设置新指针
|
||||||
|
// 这样可以避免不同触摸点之间的干扰
|
||||||
|
if (!this.isActive) {
|
||||||
|
this.activePointer = ptr;
|
||||||
|
this.isActive = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
isInBase(pointer) {
|
||||||
|
const dx = pointer.x - this.centerX;
|
||||||
|
const dy = pointer.y - this.centerY;
|
||||||
|
return Math.sqrt(dx * dx + dy * dy) <= this.radius + 20; // 容差
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,368 @@
|
|||||||
|
/**
|
||||||
|
* Unit 类
|
||||||
|
*
|
||||||
|
* 游戏中的基础单位类,用于创建和管理游戏角色、敌人等实体
|
||||||
|
* 包含位置、移动、渲染、碰撞检测等核心功能
|
||||||
|
* 支持行为系统,可灵活配置不同的 AI 或玩家控制行为
|
||||||
|
*/
|
||||||
|
export default class Unit extends Phaser.GameObjects.Sprite {
|
||||||
|
/**
|
||||||
|
* 构造函数
|
||||||
|
* @param {Phaser.Scene} scene - 游戏场景
|
||||||
|
* @param {number} x - 初始 x 坐标
|
||||||
|
* @param {number} y - 初始 y 坐标
|
||||||
|
* @param {string} texture - 单位纹理
|
||||||
|
* @param {string} name - 单位名称
|
||||||
|
*/
|
||||||
|
constructor(scene, x, y, texture, name = 'unit') {
|
||||||
|
super(scene, x, y, texture);
|
||||||
|
|
||||||
|
// 场景引用
|
||||||
|
this.scene = scene;
|
||||||
|
|
||||||
|
// 基础属性
|
||||||
|
this.name = name;
|
||||||
|
this.type = 'unit'; // 单位类型
|
||||||
|
|
||||||
|
// 移动属性
|
||||||
|
this.speed = 100; // 移动速度
|
||||||
|
this.velocity = { x: 0, y: 0 }; // 速度向量
|
||||||
|
this.canMove = true; // 是否可以移动
|
||||||
|
|
||||||
|
// 状态属性
|
||||||
|
this.isSelected = false; // 是否被选中
|
||||||
|
this.isMoving = false; // 是否正在移动
|
||||||
|
this.isAlive = true; // 是否存活
|
||||||
|
|
||||||
|
// 健康属性
|
||||||
|
this.maxHealth = 100;
|
||||||
|
this.health = this.maxHealth;
|
||||||
|
|
||||||
|
// 渲染属性
|
||||||
|
this.depth = 10; // 渲染层级
|
||||||
|
|
||||||
|
// 碰撞属性
|
||||||
|
this.collider = null; // 碰撞器
|
||||||
|
|
||||||
|
// 行为系统
|
||||||
|
this.behavior = null; // 当前行为
|
||||||
|
this.behaviorStack = []; // 行为栈
|
||||||
|
|
||||||
|
// 初始化单位
|
||||||
|
this.create();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建单位精灵和物理体
|
||||||
|
*/
|
||||||
|
create() {
|
||||||
|
this.setOrigin(0.5, 1); // 设置原点为中心底部
|
||||||
|
this.setScale(1);
|
||||||
|
|
||||||
|
// 启用物理
|
||||||
|
this.scene.physics.add.existing(this);
|
||||||
|
this.setCollideWorldBounds(true);
|
||||||
|
|
||||||
|
// 同步位置
|
||||||
|
this.x = this.x;
|
||||||
|
this.y = this.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新单位状态
|
||||||
|
* @param {number} delta - 时间增量
|
||||||
|
*/
|
||||||
|
update(delta) {
|
||||||
|
if (!this.isAlive) return;
|
||||||
|
|
||||||
|
// 更新行为
|
||||||
|
if (this.behavior) {
|
||||||
|
this.behavior.update(delta);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新移动
|
||||||
|
this.updateMovement();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新移动状态
|
||||||
|
*/
|
||||||
|
updateMovement() {
|
||||||
|
if (!this.canMove || !this.isMoving) {
|
||||||
|
this.setVelocity(0, 0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置速度
|
||||||
|
this.setVelocity(
|
||||||
|
this.velocity.x * this.speed,
|
||||||
|
this.velocity.y * this.speed
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置单位移动方向
|
||||||
|
* @param {Object} direction - 归一化方向向量 {x, y}
|
||||||
|
*/
|
||||||
|
setMovementDirection(direction) {
|
||||||
|
if (!this.canMove) return;
|
||||||
|
|
||||||
|
// 归一化方向向量
|
||||||
|
const magnitude = Math.sqrt(direction.x ** 2 + direction.y ** 2);
|
||||||
|
if (magnitude > 0) {
|
||||||
|
this.velocity.x = direction.x / magnitude;
|
||||||
|
this.velocity.y = direction.y / magnitude;
|
||||||
|
this.isMoving = true;
|
||||||
|
} else {
|
||||||
|
this.velocity.x = 0;
|
||||||
|
this.velocity.y = 0;
|
||||||
|
this.isMoving = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 停止移动
|
||||||
|
*/
|
||||||
|
stopMovement() {
|
||||||
|
this.velocity.x = 0;
|
||||||
|
this.velocity.y = 0;
|
||||||
|
this.isMoving = false;
|
||||||
|
this.setVelocity(0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置选中状态
|
||||||
|
* @param {boolean} selected - 是否选中
|
||||||
|
*/
|
||||||
|
setSelected(selected) {
|
||||||
|
this.isSelected = selected;
|
||||||
|
// 可以在这里添加选中视觉效果
|
||||||
|
if (this.isSelected) {
|
||||||
|
this.setTint(0x00ff00);
|
||||||
|
} else {
|
||||||
|
this.clearTint();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 受到伤害
|
||||||
|
* @param {number} damage - 伤害值
|
||||||
|
*/
|
||||||
|
takeDamage(damage) {
|
||||||
|
if (!this.isAlive) return;
|
||||||
|
|
||||||
|
this.health -= damage;
|
||||||
|
if (this.health <= 0) {
|
||||||
|
this.health = 0;
|
||||||
|
this.die();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 可以在这里添加受伤视觉效果
|
||||||
|
this.setTint(0xff0000);
|
||||||
|
this.scene.tweens.add({
|
||||||
|
targets: this,
|
||||||
|
alpha: 0.5,
|
||||||
|
duration: 100,
|
||||||
|
yoyo: true,
|
||||||
|
onComplete: () => {
|
||||||
|
this.clearTint();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 恢复健康
|
||||||
|
* @param {number} amount - 恢复量
|
||||||
|
*/
|
||||||
|
heal(amount) {
|
||||||
|
if (!this.isAlive) return;
|
||||||
|
|
||||||
|
this.health += amount;
|
||||||
|
if (this.health > this.maxHealth) {
|
||||||
|
this.health = this.maxHealth;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 死亡
|
||||||
|
*/
|
||||||
|
die() {
|
||||||
|
this.isAlive = false;
|
||||||
|
this.isSelected = false;
|
||||||
|
this.isMoving = false;
|
||||||
|
this.canMove = false;
|
||||||
|
|
||||||
|
// 停止移动
|
||||||
|
this.stopMovement();
|
||||||
|
|
||||||
|
// 停止行为
|
||||||
|
if (this.behavior) {
|
||||||
|
this.behavior.deactivate();
|
||||||
|
this.behavior = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 死亡视觉效果
|
||||||
|
this.setTint(0x888888);
|
||||||
|
this.scene.tweens.add({
|
||||||
|
targets: this,
|
||||||
|
alpha: 0,
|
||||||
|
scale: 0,
|
||||||
|
duration: 1000,
|
||||||
|
onComplete: () => {
|
||||||
|
this.destroy();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 销毁单位
|
||||||
|
*/
|
||||||
|
destroy() {
|
||||||
|
if (this.behavior) {
|
||||||
|
this.behavior.deactivate();
|
||||||
|
this.behavior = null;
|
||||||
|
}
|
||||||
|
if (this.collider) {
|
||||||
|
this.collider.destroy();
|
||||||
|
this.collider = null;
|
||||||
|
}
|
||||||
|
super.destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加碰撞检测
|
||||||
|
* @param {Phaser.GameObjects.Group|Phaser.GameObjects.Sprite} target - 碰撞目标
|
||||||
|
* @param {Function} callback - 碰撞回调
|
||||||
|
*/
|
||||||
|
addCollider(target, callback) {
|
||||||
|
this.collider = this.scene.physics.add.collider(
|
||||||
|
this,
|
||||||
|
target,
|
||||||
|
callback,
|
||||||
|
null,
|
||||||
|
this.scene
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 播放动画
|
||||||
|
* @param {string} animationKey - 动画键值
|
||||||
|
*/
|
||||||
|
playAnimation(animationKey) {
|
||||||
|
if (this.anims) {
|
||||||
|
this.anims.play(animationKey);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置速度
|
||||||
|
* @param {number} speed - 移动速度
|
||||||
|
*/
|
||||||
|
setSpeed(speed) {
|
||||||
|
this.speed = speed;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查与其他单位的距离
|
||||||
|
* @param {Unit} otherUnit - 其他单位
|
||||||
|
* @returns {number} 距离
|
||||||
|
*/
|
||||||
|
distanceTo(otherUnit) {
|
||||||
|
const dx = this.x - otherUnit.x;
|
||||||
|
const dy = this.y - otherUnit.y;
|
||||||
|
return Math.sqrt(dx * dx + dy * dy);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查是否与其他单位碰撞
|
||||||
|
* @param {Unit} otherUnit - 其他单位
|
||||||
|
* @returns {boolean} 是否碰撞
|
||||||
|
*/
|
||||||
|
collidesWith(otherUnit) {
|
||||||
|
const distance = this.distanceTo(otherUnit);
|
||||||
|
const combinedRadius = (this.width + otherUnit.width) / 4;
|
||||||
|
return distance < combinedRadius;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置单位类型
|
||||||
|
* @param {string} type - 单位类型
|
||||||
|
*/
|
||||||
|
setType(type) {
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置单位名称
|
||||||
|
* @param {string} name - 单位名称
|
||||||
|
*/
|
||||||
|
setName(name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取单位信息
|
||||||
|
* @returns {Object} 单位信息
|
||||||
|
*/
|
||||||
|
getInfo() {
|
||||||
|
return {
|
||||||
|
name: this.name,
|
||||||
|
type: this.type,
|
||||||
|
x: this.x,
|
||||||
|
y: this.y,
|
||||||
|
health: this.health,
|
||||||
|
maxHealth: this.maxHealth,
|
||||||
|
speed: this.speed,
|
||||||
|
isSelected: this.isSelected,
|
||||||
|
isMoving: this.isMoving,
|
||||||
|
isAlive: this.isAlive
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 暂停单位
|
||||||
|
*/
|
||||||
|
pause() {
|
||||||
|
this.canMove = false;
|
||||||
|
this.stopMovement();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 恢复单位
|
||||||
|
*/
|
||||||
|
resume() {
|
||||||
|
this.canMove = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置行为
|
||||||
|
* @param {AIBehavior} behavior - 行为对象
|
||||||
|
*/
|
||||||
|
setBehavior(behavior) {
|
||||||
|
if (this.behavior) {
|
||||||
|
this.behavior.deactivate();
|
||||||
|
}
|
||||||
|
this.behavior = behavior;
|
||||||
|
if (this.behavior) {
|
||||||
|
this.behavior.activate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 移除行为
|
||||||
|
*/
|
||||||
|
removeBehavior() {
|
||||||
|
if (this.behavior) {
|
||||||
|
this.behavior.deactivate();
|
||||||
|
this.behavior = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取当前行为
|
||||||
|
* @returns {AIBehavior} 当前行为
|
||||||
|
*/
|
||||||
|
getBehavior() {
|
||||||
|
return this.behavior;
|
||||||
|
}
|
||||||
|
}
|
||||||
File renamed without changes.
@@ -1,10 +1,11 @@
|
|||||||
/**
|
/**
|
||||||
* Control 场景类
|
* Control 场景类
|
||||||
*
|
*
|
||||||
* 允许用户控制角色
|
* 允许用户控制角色,NPC 自动搜索并收集小草
|
||||||
*/
|
*/
|
||||||
import BreatheLife from './BreatheLife.js'
|
import BreatheLife from './BreatheLife.js'
|
||||||
import Joystick from './Joystick.js'
|
import Unit from '../objects/Unit.js'
|
||||||
|
import SearchBehavior from '../behaviors/SearchBehavior.js'
|
||||||
export default class Control extends BreatheLife {
|
export default class Control extends BreatheLife {
|
||||||
constructor(sceneKey = 'Control') {
|
constructor(sceneKey = 'Control') {
|
||||||
// 场景相关
|
// 场景相关
|
||||||
@@ -26,6 +27,18 @@ export default class Control extends BreatheLife {
|
|||||||
// 添加随机NPC
|
// 添加随机NPC
|
||||||
this.addRandomNPCs()
|
this.addRandomNPCs()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
update() {
|
||||||
|
super.update()
|
||||||
|
|
||||||
|
// 更新所有 NPC 的行为
|
||||||
|
this.NPCObjects.forEach(npc => {
|
||||||
|
if (npc.update) {
|
||||||
|
npc.update()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// Control 场景不再需要覆盖 initSceneTransition 方法
|
// Control 场景不再需要覆盖 initSceneTransition 方法
|
||||||
// 数组初始化由父类 BreatheLife.create() 中的 initSceneTransition() 完成
|
// 数组初始化由父类 BreatheLife.create() 中的 initSceneTransition() 完成
|
||||||
// targetCount 通过在 create() 中直接设置来覆盖
|
// targetCount 通过在 create() 中直接设置来覆盖
|
||||||
@@ -39,9 +52,6 @@ export default class Control extends BreatheLife {
|
|||||||
const { x, y } = this.input.activePointer
|
const { x, y } = this.input.activePointer
|
||||||
this.handleClick(x, y)
|
this.handleClick(x, y)
|
||||||
})
|
})
|
||||||
|
|
||||||
// 添加摇杆
|
|
||||||
this.addJoystick()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -55,28 +65,42 @@ export default class Control extends BreatheLife {
|
|||||||
console.log("点击到的精灵:", clickedSprite)
|
console.log("点击到的精灵:", clickedSprite)
|
||||||
if (clickedSprite && this.NPCObjects.includes(clickedSprite)) { // 如果点击到了角色
|
if (clickedSprite && this.NPCObjects.includes(clickedSprite)) { // 如果点击到了角色
|
||||||
this.handleSpriteClick(clickedSprite)
|
this.handleSpriteClick(clickedSprite)
|
||||||
}else {
|
}else if (this.NPCObjects.length < this.targetCount) {
|
||||||
// 创建玩家可控制角色
|
// 如果角色数量不足目标数量,创建新的角色
|
||||||
// this.createCharacter(x, y)
|
const sprite = this.physics.add.sprite(x, y, 'player').setScale(1).setOrigin(0.5, 1)
|
||||||
|
sprite.setDepth(this.SpriteDepth) // 设置角色层级
|
||||||
|
this.NPCObjects.push(sprite) // 加入角色集合
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 创建NPC
|
* 创建NPC
|
||||||
* @param {number} x - NPC的 x 坐标
|
* @param {number} x - NPC的 x 坐标
|
||||||
* @param {number} y - NPC的 y 坐标
|
* @param {number} y - NPC的 y 坐标
|
||||||
*/
|
*/
|
||||||
createNPC(x, y) {
|
createNPC(x, y) {
|
||||||
// 创建一个新的角色 sprite,缩放为1倍,并设置原点为中心底部
|
// 使用 Unit 类创建 NPC
|
||||||
const sprite = this.physics.add.sprite(x, y, `player1-0`).setScale(1).setOrigin(0.5, 1)
|
const npc = new Unit(this, x, y, 'player1-0')
|
||||||
sprite.setDepth(this.SpriteDepth) // 设置角色层级
|
npc.setType('npc')
|
||||||
|
npc.setDepth(this.SpriteDepth) // 设置NPC渲染层级
|
||||||
this.NPCObjects.push(sprite) // 加入角色集合
|
|
||||||
|
// 为 NPC 添加搜索行为
|
||||||
this.addSpriteAnimation(sprite) // 添加角色动画
|
const searchBehavior = new SearchBehavior(npc, this.smallGrassObjects, {
|
||||||
this.searchAndAddSmallGrass(sprite) // 添加搜索逻辑,自动检测最近的小草
|
searchDelay: 500,
|
||||||
// // 设置角色碰撞世界边界
|
moveSpeed: 200,
|
||||||
// sprite.setCollideWorldBounds(true)
|
onCollect: (grass) => {
|
||||||
|
this.sound.play('coin-a')
|
||||||
|
},
|
||||||
|
onComplete: () => {
|
||||||
|
console.log('NPC 收集完所有小草')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
npc.setBehavior(searchBehavior)
|
||||||
|
|
||||||
|
// 添加到NPC数组
|
||||||
|
this.NPCObjects.push(npc)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 添加随机NPC
|
* 添加随机NPC
|
||||||
*/
|
*/
|
||||||
@@ -93,12 +117,4 @@ export default class Control extends BreatheLife {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/**
|
}
|
||||||
* 添加摇杆
|
|
||||||
*/
|
|
||||||
addJoystick() {
|
|
||||||
this.joystick = new Joystick(this, 100, this.game.config.height - 100, 50, 0x888888, 0xcccccc)
|
|
||||||
this.joystick.createJoystick(this.UIDepth) // 创建并设置摇杆层级为UI层
|
|
||||||
this.joystick.listenJoystickInput()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -0,0 +1,7 @@
|
|||||||
|
export function generateUUID() {
|
||||||
|
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
|
||||||
|
const r = Math.random() * 16 | 0;
|
||||||
|
const v = c === 'x' ? r : (r & 0x3 | 0x8);
|
||||||
|
return v.toString(16);
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -1,354 +0,0 @@
|
|||||||
// 移动逻辑测试场景
|
|
||||||
// 本文件将当前移动逻辑拆分为不同的测试场景
|
|
||||||
|
|
||||||
// 测试场景1: 相对移动(键盘控制)
|
|
||||||
// 测试内容:
|
|
||||||
// 1. 键盘方向键输入检测
|
|
||||||
// 2. 方向向量归一化
|
|
||||||
// 3. 移动速度控制
|
|
||||||
// 4. 停止移动逻辑
|
|
||||||
function testRelativeMovement() {
|
|
||||||
console.log("=== 测试场景1: 相对移动(键盘控制) ===");
|
|
||||||
|
|
||||||
// 模拟键盘输入
|
|
||||||
const testCases = [
|
|
||||||
{ dir: { x: 1, y: 0 }, description: "向右移动" },
|
|
||||||
{ dir: { x: 0, y: 1 }, description: "向下移动" },
|
|
||||||
{ dir: { x: -1, y: 0 }, description: "向左移动" },
|
|
||||||
{ dir: { x: 0, y: -1 }, description: "向上移动" },
|
|
||||||
{ dir: { x: 1, y: 1 }, description: "向右下对角线移动" },
|
|
||||||
{ dir: { x: 0, y: 0 }, description: "停止移动" }
|
|
||||||
];
|
|
||||||
|
|
||||||
testCases.forEach(testCase => {
|
|
||||||
console.log(`测试: ${testCase.description}`);
|
|
||||||
console.log(`输入方向: (${testCase.dir.x}, ${testCase.dir.y})`);
|
|
||||||
|
|
||||||
// 计算归一化向量
|
|
||||||
const magnitude = Math.sqrt(testCase.dir.x * testCase.dir.x + testCase.dir.y * testCase.dir.y);
|
|
||||||
let normalizedDir = { x: 0, y: 0 };
|
|
||||||
if (magnitude > 0) {
|
|
||||||
normalizedDir = {
|
|
||||||
x: testCase.dir.x / magnitude,
|
|
||||||
y: testCase.dir.y / magnitude
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log(`归一化方向: (${normalizedDir.x.toFixed(2)}, ${normalizedDir.y.toFixed(2)})`);
|
|
||||||
|
|
||||||
// 计算速度向量
|
|
||||||
const speed = 150;
|
|
||||||
const velocity = {
|
|
||||||
x: normalizedDir.x * speed,
|
|
||||||
y: normalizedDir.y * speed
|
|
||||||
};
|
|
||||||
|
|
||||||
console.log(`速度向量: (${velocity.x.toFixed(2)}, ${velocity.y.toFixed(2)})`);
|
|
||||||
console.log("------------------------");
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// 测试场景2: 目标点移动
|
|
||||||
// 测试内容:
|
|
||||||
// 1. 目标点设置
|
|
||||||
// 2. 世界边界限制
|
|
||||||
// 3. 移动路径计算
|
|
||||||
// 4. 到达目标点检测
|
|
||||||
function testMoveToPoint() {
|
|
||||||
console.log("=== 测试场景2: 目标点移动 ===");
|
|
||||||
|
|
||||||
// 模拟世界边界
|
|
||||||
const worldBounds = { x: 0, y: 0, width: 1000, height: 800 };
|
|
||||||
|
|
||||||
// 测试用例
|
|
||||||
const testCases = [
|
|
||||||
{
|
|
||||||
unitPos: { x: 100, y: 100 },
|
|
||||||
targetPos: { x: 500, y: 400 },
|
|
||||||
description: "正常范围内移动"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
unitPos: { x: 100, y: 100 },
|
|
||||||
targetPos: { x: 1200, y: 900 },
|
|
||||||
description: "超出世界边界的目标点"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
unitPos: { x: 500, y: 400 },
|
|
||||||
targetPos: { x: 505, y: 405 },
|
|
||||||
description: "接近当前位置的目标点"
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
testCases.forEach(testCase => {
|
|
||||||
console.log(`测试: ${testCase.description}`);
|
|
||||||
console.log(`单位位置: (${testCase.unitPos.x}, ${testCase.unitPos.y})`);
|
|
||||||
console.log(`目标位置: (${testCase.targetPos.x}, ${testCase.targetPos.y})`);
|
|
||||||
|
|
||||||
// 应用世界边界限制
|
|
||||||
const clampedTarget = {
|
|
||||||
x: Math.max(worldBounds.x, Math.min(worldBounds.width, testCase.targetPos.x)),
|
|
||||||
y: Math.max(worldBounds.y, Math.min(worldBounds.height, testCase.targetPos.y))
|
|
||||||
};
|
|
||||||
|
|
||||||
console.log(`限制后目标: (${clampedTarget.x}, ${clampedTarget.y})`);
|
|
||||||
|
|
||||||
// 计算距离和方向
|
|
||||||
const dx = clampedTarget.x - testCase.unitPos.x;
|
|
||||||
const dy = clampedTarget.y - testCase.unitPos.y;
|
|
||||||
const distance = Math.sqrt(dx * dx + dy * dy);
|
|
||||||
|
|
||||||
console.log(`距离: ${distance.toFixed(2)}`);
|
|
||||||
|
|
||||||
// 检查是否到达目标
|
|
||||||
const arrived = distance < 5;
|
|
||||||
console.log(`是否到达目标: ${arrived}`);
|
|
||||||
|
|
||||||
if (!arrived) {
|
|
||||||
// 计算移动方向和速度
|
|
||||||
const angle = Math.atan2(dy, dx);
|
|
||||||
const speed = 150;
|
|
||||||
const velocity = {
|
|
||||||
x: Math.cos(angle) * speed,
|
|
||||||
y: Math.sin(angle) * speed
|
|
||||||
};
|
|
||||||
console.log(`移动速度: (${velocity.x.toFixed(2)}, ${velocity.y.toFixed(2)})`);
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log("------------------------");
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// 测试场景3: 单位选择与移动命令
|
|
||||||
// 测试内容:
|
|
||||||
// 1. 单个单位选择
|
|
||||||
// 2. 多个单位选择
|
|
||||||
// 3. 移动命令分发
|
|
||||||
function testSelectionAndCommand() {
|
|
||||||
console.log("=== 测试场景3: 单位选择与移动命令 ===");
|
|
||||||
|
|
||||||
// 模拟单位和选择状态
|
|
||||||
const mockUnits = [
|
|
||||||
{ id: 1, name: "单位1", moveRelative: () => {}, setTarget: () => {} },
|
|
||||||
{ id: 2, name: "单位2", moveRelative: () => {}, setTarget: () => {} },
|
|
||||||
{ id: 3, name: "单位3", moveRelative: () => {}, setTarget: () => {} }
|
|
||||||
];
|
|
||||||
|
|
||||||
// 测试用例
|
|
||||||
const testCases = [
|
|
||||||
{
|
|
||||||
selectedUnits: [],
|
|
||||||
activeUnit: mockUnits[0],
|
|
||||||
command: "move-relative",
|
|
||||||
dir: { x: 1, y: 0 },
|
|
||||||
description: "无选中单位,使用激活单位"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
selectedUnits: [mockUnits[0], mockUnits[1]],
|
|
||||||
activeUnit: mockUnits[0],
|
|
||||||
command: "move-to-point",
|
|
||||||
target: { x: 500, y: 400 },
|
|
||||||
description: "多个选中单位,执行目标点移动"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
selectedUnits: [mockUnits[2]],
|
|
||||||
activeUnit: mockUnits[0],
|
|
||||||
command: "move-relative",
|
|
||||||
dir: { x: 0, y: -1 },
|
|
||||||
description: "单个选中单位,执行相对移动"
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
testCases.forEach(testCase => {
|
|
||||||
console.log(`测试: ${testCase.description}`);
|
|
||||||
console.log(`激活单位: ${testCase.activeUnit.name}`);
|
|
||||||
console.log(`选中单位: ${testCase.selectedUnits.map(u => u.name).join(", ")}`);
|
|
||||||
|
|
||||||
// 确定命令目标
|
|
||||||
const targets = testCase.selectedUnits.length > 0 ? testCase.selectedUnits : [testCase.activeUnit];
|
|
||||||
console.log(`命令目标: ${targets.map(u => u.name).join(", ")}`);
|
|
||||||
|
|
||||||
if (testCase.command === "move-relative") {
|
|
||||||
console.log(`执行相对移动: (${testCase.dir.x}, ${testCase.dir.y})`);
|
|
||||||
} else if (testCase.command === "move-to-point") {
|
|
||||||
console.log(`执行目标点移动: (${testCase.target.x}, ${testCase.target.y})`);
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log("------------------------");
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// 测试场景4: 虚拟摇杆控制
|
|
||||||
// 测试内容:
|
|
||||||
// 1. 摇杆激活检测
|
|
||||||
// 2. 摇杆方向计算
|
|
||||||
// 3. 归一化方向输出
|
|
||||||
// 4. 停止移动处理
|
|
||||||
function testVirtualJoystick() {
|
|
||||||
console.log("=== 测试场景4: 虚拟摇杆控制 ===");
|
|
||||||
|
|
||||||
// 模拟摇杆配置
|
|
||||||
const joystickConfig = { centerX: 100, centerY: 100, radius: 50 };
|
|
||||||
|
|
||||||
// 测试用例
|
|
||||||
const testCases = [
|
|
||||||
{
|
|
||||||
pointerPos: { x: 120, y: 100 },
|
|
||||||
description: "向右轻微拖动"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
pointerPos: { x: 160, y: 100 },
|
|
||||||
description: "向右拖动超出摇杆范围"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
pointerPos: { x: 135, y: 135 },
|
|
||||||
description: "向右下对角线拖动"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
pointerPos: { x: 100, y: 100 },
|
|
||||||
description: "摇杆中心位置(停止)"
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
testCases.forEach(testCase => {
|
|
||||||
console.log(`测试: ${testCase.description}`);
|
|
||||||
console.log(`摇杆中心: (${joystickConfig.centerX}, ${joystickConfig.centerY})`);
|
|
||||||
console.log(`指针位置: (${testCase.pointerPos.x}, ${testCase.pointerPos.y})`);
|
|
||||||
|
|
||||||
// 计算方向和距离
|
|
||||||
const dx = testCase.pointerPos.x - joystickConfig.centerX;
|
|
||||||
const dy = testCase.pointerPos.y - joystickConfig.centerY;
|
|
||||||
const distance = Math.sqrt(dx * dx + dy * dy);
|
|
||||||
|
|
||||||
console.log(`距离: ${distance.toFixed(2)}`);
|
|
||||||
|
|
||||||
// 限制在摇杆范围内
|
|
||||||
let limitedDx = dx;
|
|
||||||
let limitedDy = dy;
|
|
||||||
if (distance > joystickConfig.radius) {
|
|
||||||
const angle = Math.atan2(dy, dx);
|
|
||||||
limitedDx = Math.cos(angle) * joystickConfig.radius;
|
|
||||||
limitedDy = Math.sin(angle) * joystickConfig.radius;
|
|
||||||
console.log(`限制后偏移: (${limitedDx.toFixed(2)}, ${limitedDy.toFixed(2)})`);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 计算归一化方向
|
|
||||||
const dirX = limitedDx / joystickConfig.radius;
|
|
||||||
const dirY = limitedDy / joystickConfig.radius;
|
|
||||||
console.log(`归一化方向: (${dirX.toFixed(2)}, ${dirY.toFixed(2)})`);
|
|
||||||
|
|
||||||
console.log("------------------------");
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// 测试场景5: 移动更新逻辑
|
|
||||||
// 测试内容:
|
|
||||||
// 1. 每帧移动更新
|
|
||||||
// 2. 位置更新计算
|
|
||||||
// 3. 目标到达检测
|
|
||||||
function testMovementUpdate() {
|
|
||||||
console.log("=== 测试场景5: 移动更新逻辑 ===");
|
|
||||||
|
|
||||||
// 模拟单位和时间增量
|
|
||||||
const mockUnit = {
|
|
||||||
x: 100,
|
|
||||||
y: 100,
|
|
||||||
target: { x: 500, y: 400 },
|
|
||||||
setVelocity: (vx, vy) => { mockUnit.velocity = { x: vx, y: vy }; },
|
|
||||||
setPosition: (x, y) => { mockUnit.x = x; mockUnit.y = y; }
|
|
||||||
};
|
|
||||||
|
|
||||||
const speed = 150;
|
|
||||||
const deltaTime = 1/60; // 60fps
|
|
||||||
|
|
||||||
console.log("初始状态:");
|
|
||||||
console.log(`单位位置: (${mockUnit.x}, ${mockUnit.y})`);
|
|
||||||
console.log(`目标位置: (${mockUnit.target.x}, ${mockUnit.target.y})`);
|
|
||||||
|
|
||||||
// 模拟几帧的移动更新
|
|
||||||
for (let i = 0; i < 5; i++) {
|
|
||||||
console.log(`\n第${i+1}帧更新:`);
|
|
||||||
|
|
||||||
const dx = mockUnit.target.x - mockUnit.x;
|
|
||||||
const dy = mockUnit.target.y - mockUnit.y;
|
|
||||||
const distance = Math.sqrt(dx * dx + dy * dy);
|
|
||||||
|
|
||||||
console.log(`距离目标: ${distance.toFixed(2)}`);
|
|
||||||
|
|
||||||
if (distance < 5) {
|
|
||||||
// 到达目标
|
|
||||||
mockUnit.setPosition(mockUnit.target.x, mockUnit.target.y);
|
|
||||||
mockUnit.setVelocity(0, 0);
|
|
||||||
mockUnit.target = null;
|
|
||||||
console.log("到达目标,停止移动");
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
// 继续移动
|
|
||||||
const angle = Math.atan2(dy, dx);
|
|
||||||
const velocity = {
|
|
||||||
x: Math.cos(angle) * speed,
|
|
||||||
y: Math.sin(angle) * speed
|
|
||||||
};
|
|
||||||
|
|
||||||
mockUnit.setVelocity(velocity.x, velocity.y);
|
|
||||||
|
|
||||||
// 更新位置
|
|
||||||
mockUnit.x += velocity.x * deltaTime;
|
|
||||||
mockUnit.y += velocity.y * deltaTime;
|
|
||||||
|
|
||||||
console.log(`速度: (${velocity.x.toFixed(2)}, ${velocity.y.toFixed(2)})`);
|
|
||||||
console.log(`新位置: (${mockUnit.x.toFixed(2)}, ${mockUnit.y.toFixed(2)})`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log("\n最终状态:");
|
|
||||||
console.log(`单位位置: (${mockUnit.x}, ${mockUnit.y})`);
|
|
||||||
console.log(`目标状态: ${mockUnit.target ? "有目标" : "无目标"}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 运行所有测试场景
|
|
||||||
function runAllTests() {
|
|
||||||
console.log("开始运行移动逻辑测试场景\n");
|
|
||||||
|
|
||||||
testRelativeMovement();
|
|
||||||
console.log("\n" + "=".repeat(50) + "\n");
|
|
||||||
|
|
||||||
testMoveToPoint();
|
|
||||||
console.log("\n" + "=".repeat(50) + "\n");
|
|
||||||
|
|
||||||
testSelectionAndCommand();
|
|
||||||
console.log("\n" + "=".repeat(50) + "\n");
|
|
||||||
|
|
||||||
testVirtualJoystick();
|
|
||||||
console.log("\n" + "=".repeat(50) + "\n");
|
|
||||||
|
|
||||||
testMovementUpdate();
|
|
||||||
|
|
||||||
console.log("\n" + "=".repeat(50));
|
|
||||||
console.log("所有测试场景运行完成");
|
|
||||||
}
|
|
||||||
|
|
||||||
// 导出测试函数
|
|
||||||
if (typeof module !== 'undefined' && module.exports) {
|
|
||||||
module.exports = {
|
|
||||||
testRelativeMovement,
|
|
||||||
testMoveToPoint,
|
|
||||||
testSelectionAndCommand,
|
|
||||||
testVirtualJoystick,
|
|
||||||
testMovementUpdate,
|
|
||||||
runAllTests
|
|
||||||
};
|
|
||||||
// Node.js环境下自动运行测试
|
|
||||||
runAllTests();
|
|
||||||
} else {
|
|
||||||
// 浏览器环境下自动运行测试
|
|
||||||
window.movementTests = {
|
|
||||||
runAllTests,
|
|
||||||
testRelativeMovement,
|
|
||||||
testMoveToPoint,
|
|
||||||
testSelectionAndCommand,
|
|
||||||
testVirtualJoystick,
|
|
||||||
testMovementUpdate
|
|
||||||
};
|
|
||||||
// 浏览器环境下自动运行测试
|
|
||||||
runAllTests();
|
|
||||||
}
|
|
||||||
Reference in new issue
Block a user