mirror of
http://junepve.top:3000/chicrobot/CINC.git
synced 2026-10-29 22:41:29 +08:00
feat(SS) 添加物品类、单位类
This commit is contained in:
1 parent
cbbed1519e
commit
494922246b
11 files changed
+440
-855
No files matched your search
@@ -78,11 +78,11 @@ const config = {
|
|||||||
...gameConfig,
|
...gameConfig,
|
||||||
// 指定游戏使用的场景列表,包括主场景和所有测试场景
|
// 指定游戏使用的场景列表,包括主场景和所有测试场景
|
||||||
scene: [
|
scene: [
|
||||||
|
Control,
|
||||||
PrimordialDevide,
|
PrimordialDevide,
|
||||||
WorldTime,
|
WorldTime,
|
||||||
WorldLand,
|
WorldLand,
|
||||||
BreatheLife,
|
BreatheLife,
|
||||||
Control,
|
|
||||||
|
|
||||||
// 测试场景
|
// 测试场景
|
||||||
MenuScene,
|
MenuScene,
|
||||||
|
|||||||
@@ -1,72 +0,0 @@
|
|||||||
/**
|
|
||||||
* 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,107 +0,0 @@
|
|||||||
/**
|
|
||||||
* 玩家控制行为类
|
|
||||||
*
|
|
||||||
* 实现玩家通过摇杆或键盘控制单位的行为
|
|
||||||
*/
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,161 +0,0 @@
|
|||||||
/**
|
|
||||||
* 搜索行为类
|
|
||||||
*
|
|
||||||
* 实现单位自动搜索并收集目标物品的行为
|
|
||||||
*/
|
|
||||||
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,24 @@
|
|||||||
|
{
|
||||||
|
"items": {
|
||||||
|
"smallGrass": {
|
||||||
|
"name": "小草",
|
||||||
|
"type": ["plant"],
|
||||||
|
"weight": 0.1,
|
||||||
|
"volume": 0.5,
|
||||||
|
"hardness": 1,
|
||||||
|
"elasticity": 0.2,
|
||||||
|
"physicalState": "solid",
|
||||||
|
"description": "普通的小草,可用于制作简单的物品"
|
||||||
|
},
|
||||||
|
"cactus": {
|
||||||
|
"name": "仙人掌",
|
||||||
|
"type": ["plant", "spiky"],
|
||||||
|
"weight": 2,
|
||||||
|
"volume": 3,
|
||||||
|
"hardness": 3,
|
||||||
|
"elasticity": 0.1,
|
||||||
|
"physicalState": "solid",
|
||||||
|
"description": "带刺的仙人掌,小心处理"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,72 +0,0 @@
|
|||||||
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; // 容差
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,368 +0,0 @@
|
|||||||
/**
|
|
||||||
* 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -16,6 +16,14 @@ export default class BreatheLife extends WorldLand {
|
|||||||
|
|
||||||
// 层级相关
|
// 层级相关
|
||||||
this.SpriteDepth = 10 // 角色层级
|
this.SpriteDepth = 10 // 角色层级
|
||||||
|
|
||||||
|
// 碰撞层级
|
||||||
|
this.collisionLayers = {
|
||||||
|
NPC: 0b0001, // NPC 碰撞层
|
||||||
|
CACTUS: 0b0010, // 仙人掌碰撞层
|
||||||
|
OBSTACLE: 0b0100, // 障碍物碰撞层
|
||||||
|
ALL: 0b1111 // 所有碰撞层
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
preload() {
|
preload() {
|
||||||
@@ -41,14 +49,16 @@ export default class BreatheLife extends WorldLand {
|
|||||||
create() {
|
create() {
|
||||||
super.create()
|
super.create()
|
||||||
|
|
||||||
// 覆盖场景切换条件
|
// 场景切换条件
|
||||||
this.initSceneTransition()
|
this.initSceneTransition()
|
||||||
|
|
||||||
// 覆盖输入
|
// 输入
|
||||||
this.initInput()
|
this.initInput()
|
||||||
|
|
||||||
// 添加随机小草
|
// 当前场景为'BreatheLife'时添加随机小草
|
||||||
this.addRandomSmallGrass()
|
if (this.scene.key === 'BreatheLife') {
|
||||||
|
this.addRandomSmallGrass()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
initSceneTransition() {
|
initSceneTransition() {
|
||||||
// 初始化角色计数器,用于跟踪创建的角色数量
|
// 初始化角色计数器,用于跟踪创建的角色数量
|
||||||
|
|||||||
+138
-67
@@ -4,44 +4,37 @@
|
|||||||
* 允许用户控制角色,NPC 自动搜索并收集小草
|
* 允许用户控制角色,NPC 自动搜索并收集小草
|
||||||
*/
|
*/
|
||||||
import BreatheLife from './BreatheLife.js'
|
import BreatheLife from './BreatheLife.js'
|
||||||
import Unit from '../objects/Unit.js'
|
import { generateUUID } from '../utils/String.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') {
|
||||||
// 场景相关
|
// 场景相关
|
||||||
super(sceneKey)
|
super(sceneKey)
|
||||||
this.nextScene = 'InfoBar'
|
this.nextScene = 'InfoBar'
|
||||||
}
|
}
|
||||||
preload() {
|
async preload() {
|
||||||
super.preload()
|
super.preload()
|
||||||
|
// 加载仙人掌图片
|
||||||
|
this.load.image('cactus', `${this.TilesPath}/tile_0063.png`)
|
||||||
|
// 加载物品配置
|
||||||
|
await Item.loadItemsConfig(this)
|
||||||
}
|
}
|
||||||
create() {
|
create() {
|
||||||
super.create()
|
super.create()
|
||||||
|
|
||||||
// 设置 Control 场景的目标角色数量
|
|
||||||
this.targetCount = 2 // 目标角色数量
|
|
||||||
|
|
||||||
// 初始化输入事件
|
// 场景切换条件
|
||||||
|
this.initSceneTransition()
|
||||||
|
|
||||||
|
// 输入事件
|
||||||
this.initInput()
|
this.initInput()
|
||||||
|
|
||||||
// 添加随机NPC
|
// 添加随机NPC
|
||||||
this.addRandomNPCs()
|
this.addRandomNPCs()
|
||||||
}
|
}
|
||||||
|
initSceneTransition() {
|
||||||
update() {
|
this.cactusObjects = [] // 维护仙人掌集合
|
||||||
super.update()
|
|
||||||
|
|
||||||
// 更新所有 NPC 的行为
|
|
||||||
this.NPCObjects.forEach(npc => {
|
|
||||||
if (npc.update) {
|
|
||||||
npc.update()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Control 场景不再需要覆盖 initSceneTransition 方法
|
// Control 场景不再需要覆盖 initSceneTransition 方法
|
||||||
// 数组初始化由父类 BreatheLife.create() 中的 initSceneTransition() 完成
|
// 数组初始化由父类 BreatheLife.create() 中的 initSceneTransition() 完成
|
||||||
// targetCount 通过在 create() 中直接设置来覆盖
|
|
||||||
initInput() {
|
initInput() {
|
||||||
// 移除父类的输入事件监听器,避免重复监听
|
// 移除父类的输入事件监听器,避免重复监听
|
||||||
super.removeListener()
|
super.removeListener()
|
||||||
@@ -53,6 +46,10 @@ export default class Control extends BreatheLife {
|
|||||||
this.handleClick(x, y)
|
this.handleClick(x, y)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
update() {
|
||||||
|
super.update()
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 处理点击事件
|
* 处理点击事件
|
||||||
@@ -65,56 +62,130 @@ 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 if (this.NPCObjects.length < this.targetCount) {
|
}else{
|
||||||
// 如果角色数量不足目标数量,创建新的角色
|
|
||||||
const sprite = this.physics.add.sprite(x, y, 'player').setScale(1).setOrigin(0.5, 1)
|
|
||||||
sprite.setDepth(this.SpriteDepth) // 设置角色层级
|
|
||||||
this.NPCObjects.push(sprite) // 加入角色集合
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
addRandomNPCs(count = 3) {
|
||||||
/**
|
// 随机生成NPC
|
||||||
* 创建NPC
|
for (let i = 0; i < count; i++) {
|
||||||
* @param {number} x - NPC的 x 坐标
|
const randomX = Phaser.Math.Between(100, this.sys.game.config.width - 100)
|
||||||
* @param {number} y - NPC的 y 坐标
|
const randomY = Phaser.Math.Between(100, this.sys.game.config.height - 100)
|
||||||
*/
|
const npc = new Human(this, randomX, randomY, 'human')
|
||||||
createNPC(x, y) {
|
this.NPCObjects.push(npc)
|
||||||
// 使用 Unit 类创建 NPC
|
|
||||||
const npc = new Unit(this, x, y, 'player1-0')
|
|
||||||
npc.setType('npc')
|
|
||||||
npc.setDepth(this.SpriteDepth) // 设置NPC渲染层级
|
|
||||||
|
|
||||||
// 为 NPC 添加搜索行为
|
|
||||||
const searchBehavior = new SearchBehavior(npc, this.smallGrassObjects, {
|
|
||||||
searchDelay: 500,
|
|
||||||
moveSpeed: 200,
|
|
||||||
onCollect: (grass) => {
|
|
||||||
this.sound.play('coin-a')
|
|
||||||
},
|
|
||||||
onComplete: () => {
|
|
||||||
console.log('NPC 收集完所有小草')
|
|
||||||
}
|
|
||||||
})
|
|
||||||
npc.setBehavior(searchBehavior)
|
|
||||||
|
|
||||||
// 添加到NPC数组
|
|
||||||
this.NPCObjects.push(npc)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 添加随机NPC
|
|
||||||
*/
|
|
||||||
addRandomNPCs() {
|
|
||||||
// 随机生成NPC数量
|
|
||||||
const randomCount = 5
|
|
||||||
for (let i = 0; i < randomCount; i++) {
|
|
||||||
// 随机间隔随机位置生成NPC
|
|
||||||
const interval = Phaser.Math.Between(0, 500)
|
|
||||||
this.time.delayedCall(interval, () => {
|
|
||||||
const x = Phaser.Math.Between(0, this.game.config.width)
|
|
||||||
const y = Phaser.Math.Between(0, this.game.config.height)
|
|
||||||
this.createNPC(x, y)
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* 物品类
|
||||||
|
* 用于表示游戏中的可收集物品
|
||||||
|
* @param {Phaser.Scene} scene - 场景实例
|
||||||
|
* @param {number} x - 物品的 x 坐标
|
||||||
|
* @param {number} y - 物品的 y 坐标
|
||||||
|
* @param {string} texture - 物品的纹理键
|
||||||
|
*/
|
||||||
|
export class Item extends Phaser.GameObjects.Sprite {
|
||||||
|
// 静态属性,存储所有物品的配置数据
|
||||||
|
static itemsConfig = null
|
||||||
|
|
||||||
|
// 静态方法,加载物品配置
|
||||||
|
static loadItemsConfig(scene) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
scene.load.json('itemsConfig', 'src/data/items.json')
|
||||||
|
scene.load.once('complete', () => {
|
||||||
|
Item.itemsConfig = scene.cache.json.get('itemsConfig')
|
||||||
|
resolve()
|
||||||
|
})
|
||||||
|
scene.load.start()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(scene, x, y, texture, itemInfoName = null, frame = 0) {
|
||||||
|
// 调用父类 Sprite 构造函数
|
||||||
|
super(scene, x, y, texture, frame)
|
||||||
|
// 渲染属性
|
||||||
|
this.setOrigin(0.5, 0.5) // 设置渲染原点,中心
|
||||||
|
this.scene.add.existing(this)
|
||||||
|
|
||||||
|
// 设置自定义额外属性
|
||||||
|
this.type = [] // 物品类型标签
|
||||||
|
this.weight = 0 // 物品重量
|
||||||
|
this.volume = 0 // 物品体积
|
||||||
|
this.hardness = 0 // 硬度
|
||||||
|
this.elasticity = 0 // 弹性
|
||||||
|
this.physicalState = 'solid' // 物理状态,solid 为固体,liquid 为液体,gas 为气体
|
||||||
|
this.name = '' // 物品名称
|
||||||
|
this.description = '' // 物品描述
|
||||||
|
|
||||||
|
// 是否被AI锁定,用于防止AI重复拾取
|
||||||
|
this.locked = false
|
||||||
|
|
||||||
|
// 如果指定了物品类型,从配置中加载属性
|
||||||
|
if (itemInfoName && Item.itemsConfig) {
|
||||||
|
this.loadFromConfig(itemInfoName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 从配置中加载物品属性
|
||||||
|
loadFromConfig(itemInfoName) {
|
||||||
|
if (Item.itemsConfig && Item.itemsConfig.items[itemInfoName]) {
|
||||||
|
const config = Item.itemsConfig.items[itemInfoName]
|
||||||
|
this.name = config.name || ''
|
||||||
|
this.type = config.type || []
|
||||||
|
this.weight = config.weight || 0
|
||||||
|
this.volume = config.volume || 0
|
||||||
|
this.hardness = config.hardness || 0
|
||||||
|
this.elasticity = config.elasticity || 0
|
||||||
|
this.physicalState = config.physicalState || 'solid'
|
||||||
|
this.description = config.description || ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setLocked(lockState) { // 设置物品是否被AI锁定
|
||||||
|
this.locked = lockState
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 单位类
|
||||||
|
* 用于表示游戏中的角色和敌人
|
||||||
|
* @param {Phaser.Scene} scene - 场景实例
|
||||||
|
* @param {number} x - 单位的 x 坐标
|
||||||
|
* @param {number} y - 单位的 y 坐标
|
||||||
|
* @param {string} texture - 单位的纹理键
|
||||||
|
* @param {string|number} frame - 单位的初始帧
|
||||||
|
*/
|
||||||
|
export class Unit extends Item {
|
||||||
|
constructor(scene, x, y, texture, frame) {
|
||||||
|
// 调用父类 Sprite 构造函数
|
||||||
|
super(scene, x, y, texture, frame)
|
||||||
|
// 添加物品标签为单位
|
||||||
|
this.type.push('unit')
|
||||||
|
|
||||||
|
// 设置自定义额外属性
|
||||||
|
this.uuid = generateUUID() // 单位唯一标识符
|
||||||
|
this.direction = 1 // 渲染方向,1 为向右,-1 为向左
|
||||||
|
|
||||||
|
this.mass = 0 // 单位质量
|
||||||
|
this.velocity = new Phaser.Math.Vector2(0, 0) // 单位速度向量
|
||||||
|
this.acceleration = new Phaser.Math.Vector2(0, 0) // 单位加速度向量
|
||||||
|
|
||||||
|
this.force = 0 // 单位力量
|
||||||
|
this.target = null // 单位目标点
|
||||||
|
this.status = ['alive'] // 单位状态
|
||||||
|
}
|
||||||
|
|
||||||
|
hasStatus(status) { // 单位状态检查
|
||||||
|
return this.status.includes(status)
|
||||||
|
}
|
||||||
|
addStatus(status) { // 单位状态添加
|
||||||
|
if (!this.hasStatus(status)) {
|
||||||
|
this.status.push(status)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
removeStatus(status) { // 单位状态移除
|
||||||
|
if (this.hasStatus(status)) {
|
||||||
|
this.status = this.status.filter(s => s !== status)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,259 @@
|
|||||||
|
/**
|
||||||
|
* 人类类
|
||||||
|
* 继承自Unit类,用于表示游戏中的人类角色
|
||||||
|
* @param {Phaser.Scene} scene - 场景实例
|
||||||
|
* @param {number} x - 单位的 x 坐标
|
||||||
|
* @param {number} y - 单位的 y 坐标
|
||||||
|
* @param {string} texture - 单位的纹理键
|
||||||
|
* @param {string|number} frame - 单位的初始帧
|
||||||
|
*/
|
||||||
|
import { Unit } from './Control.js'
|
||||||
|
|
||||||
|
export default class Human extends Unit {
|
||||||
|
constructor(scene, x, y, texture, frame) {
|
||||||
|
// 调用父类 Unit 构造函数
|
||||||
|
super(scene, x, y, texture, frame)
|
||||||
|
|
||||||
|
// 初始化穿戴系统
|
||||||
|
this.initWearSystem()
|
||||||
|
|
||||||
|
// 初始化携带系统
|
||||||
|
this.initCarrySystem()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 初始化穿戴系统
|
||||||
|
*/
|
||||||
|
initWearSystem() {
|
||||||
|
// 穿戴部位结构
|
||||||
|
this.wearParts = {
|
||||||
|
// 头部
|
||||||
|
head: {
|
||||||
|
eyes: null, // 眼睛部位穿戴物
|
||||||
|
mouth: null, // 嘴部穿戴物
|
||||||
|
ears: null, // 耳朵部位穿戴物
|
||||||
|
top: null // 头顶部位穿戴物
|
||||||
|
},
|
||||||
|
// 身体
|
||||||
|
body: {
|
||||||
|
chest: null, // 胸部穿戴物
|
||||||
|
waist: null, // 腰部穿戴物
|
||||||
|
abdomen: null, // 腹部穿戴物
|
||||||
|
back: null, // 背部穿戴物,用于背包、可背物品等,也可用于携带其他单位
|
||||||
|
},
|
||||||
|
// 四肢
|
||||||
|
limbs: {
|
||||||
|
leftHand: null, // 左手穿戴物
|
||||||
|
rightHand: null, // 右手穿戴物
|
||||||
|
|
||||||
|
leftArm: null, // 左臂穿戴物
|
||||||
|
rightArm: null, // 右臂穿戴物
|
||||||
|
|
||||||
|
leftLeg: null, // 左腿穿戴物
|
||||||
|
rightLeg: null, // 右腿穿戴物
|
||||||
|
|
||||||
|
leftFoot: null, // 左脚穿戴物
|
||||||
|
rightFoot: null // 右脚穿戴物
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 初始化携带系统
|
||||||
|
*/
|
||||||
|
initCarrySystem() {
|
||||||
|
// 携带部位,无穿戴时可携带物品
|
||||||
|
this.carryParts = {
|
||||||
|
leftHand: {
|
||||||
|
items: [], // 左手携带的物品
|
||||||
|
maxWeight: 10, // 左手最大负重
|
||||||
|
maxVolume: 5, // 左手最大体积
|
||||||
|
currentWeight: 0, // 左手当前负重
|
||||||
|
currentVolume: 0 // 左手当前体积
|
||||||
|
},
|
||||||
|
rightHand: {
|
||||||
|
items: [], // 右手携带的物品
|
||||||
|
maxWeight: 10, // 右手最大负重
|
||||||
|
maxVolume: 5, // 右手最大体积
|
||||||
|
currentWeight: 0, // 右手当前负重
|
||||||
|
currentVolume: 0 // 右手当前体积
|
||||||
|
},
|
||||||
|
mouth: {
|
||||||
|
items: [], // 嘴部携带的物品
|
||||||
|
maxWeight: 2, // 嘴部最大负重
|
||||||
|
maxVolume: 1, // 嘴部最大体积
|
||||||
|
currentWeight: 0, // 嘴部当前负重
|
||||||
|
currentVolume: 0 // 嘴部当前体积
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 穿戴物品到指定部位
|
||||||
|
* @param {string} partType - 部位类型:head, body, limbs
|
||||||
|
* @param {string} partName - 具体部位名称
|
||||||
|
* @param {Item} item - 要穿戴的物品
|
||||||
|
* @returns {boolean} - 是否穿戴成功
|
||||||
|
*/
|
||||||
|
wearItem(partType, partName, item) {
|
||||||
|
// 检查物品是否有对应部位的服装标签
|
||||||
|
if (!item.type.includes(`${partType}-${partName}-clothing`)) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查部位是否存在
|
||||||
|
if (!this.wearParts[partType] || !this.wearParts[partType].hasOwnProperty(partName)) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// 穿戴物品
|
||||||
|
this.wearParts[partType][partName] = item
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 卸下指定部位的物品
|
||||||
|
* @param {string} partType - 部位类型:head, body, limbs
|
||||||
|
* @param {string} partName - 具体部位名称
|
||||||
|
* @returns {Item|null} - 卸下的物品,如果没有则返回null
|
||||||
|
*/
|
||||||
|
removeItem(partType, partName) {
|
||||||
|
// 检查部位是否存在
|
||||||
|
if (!this.wearParts[partType] || !this.wearParts[partType].hasOwnProperty(partName)) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取并卸下物品
|
||||||
|
const item = this.wearParts[partType][partName]
|
||||||
|
this.wearParts[partType][partName] = null
|
||||||
|
return item
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 携带物品到指定部位
|
||||||
|
* @param {string} carryPart - 携带部位:leftHand, rightHand, mouth
|
||||||
|
* @param {Item} item - 要携带的物品
|
||||||
|
* @returns {boolean} - 是否携带成功
|
||||||
|
*/
|
||||||
|
carryItem(carryPart, item) {
|
||||||
|
// 检查携带部位是否存在
|
||||||
|
if (!this.carryParts[carryPart]) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查负重和体积是否超出限制
|
||||||
|
const carryInfo = this.carryParts[carryPart]
|
||||||
|
if (carryInfo.currentWeight + item.weight > carryInfo.maxWeight ||
|
||||||
|
carryInfo.currentVolume + item.volume > carryInfo.maxVolume) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// 携带物品
|
||||||
|
carryInfo.items.push(item)
|
||||||
|
carryInfo.currentWeight += item.weight
|
||||||
|
carryInfo.currentVolume += item.volume
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 卸下指定部位的携带物品
|
||||||
|
* @param {string} carryPart - 携带部位:leftHand, rightHand, mouth
|
||||||
|
* @param {number} index - 物品索引
|
||||||
|
* @returns {Item|null} - 卸下的物品,如果没有则返回null
|
||||||
|
*/
|
||||||
|
removeCarryItem(carryPart, index) {
|
||||||
|
// 检查携带部位是否存在
|
||||||
|
if (!this.carryParts[carryPart]) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
const carryInfo = this.carryParts[carryPart]
|
||||||
|
|
||||||
|
// 检查索引是否有效
|
||||||
|
if (index < 0 || index >= carryInfo.items.length) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取并卸下物品
|
||||||
|
const item = carryInfo.items[index]
|
||||||
|
carryInfo.items.splice(index, 1)
|
||||||
|
carryInfo.currentWeight -= item.weight
|
||||||
|
carryInfo.currentVolume -= item.volume
|
||||||
|
return item
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 向穿戴物品中存放物品(如果穿戴物品是容器)
|
||||||
|
* @param {string} partType - 部位类型:head, body, limbs
|
||||||
|
* @param {string} partName - 具体部位名称
|
||||||
|
* @param {Item} item - 要存放的物品
|
||||||
|
* @returns {boolean} - 是否存放成功
|
||||||
|
*/
|
||||||
|
storeItemInWear(partType, partName, item) {
|
||||||
|
// 检查部位是否存在
|
||||||
|
if (!this.wearParts[partType] || !this.wearParts[partType].hasOwnProperty(partName)) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
const wearItem = this.wearParts[partType][partName]
|
||||||
|
|
||||||
|
// 检查是否有穿戴物品且是否是容器
|
||||||
|
if (!wearItem || !wearItem.type.includes('container')) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查容器是否有存放物品的能力
|
||||||
|
if (!wearItem.hasOwnProperty('items')) {
|
||||||
|
wearItem.items = []
|
||||||
|
wearItem.maxWeight = wearItem.maxWeight || 20
|
||||||
|
wearItem.maxVolume = wearItem.maxVolume || 10
|
||||||
|
wearItem.currentWeight = 0
|
||||||
|
wearItem.currentVolume = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查负重和体积是否超出限制
|
||||||
|
if (wearItem.currentWeight + item.weight > wearItem.maxWeight ||
|
||||||
|
wearItem.currentVolume + item.volume > wearItem.maxVolume) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// 存放物品
|
||||||
|
wearItem.items.push(item)
|
||||||
|
wearItem.currentWeight += item.weight
|
||||||
|
wearItem.currentVolume += item.volume
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从穿戴物品中取出物品
|
||||||
|
* @param {string} partType - 部位类型:head, body, limbs
|
||||||
|
* @param {string} partName - 具体部位名称
|
||||||
|
* @param {number} index - 物品索引
|
||||||
|
* @returns {Item|null} - 取出的物品,如果没有则返回null
|
||||||
|
*/
|
||||||
|
retrieveItemFromWear(partType, partName, index) {
|
||||||
|
// 检查部位是否存在
|
||||||
|
if (!this.wearParts[partType] || !this.wearParts[partType].hasOwnProperty(partName)) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
const wearItem = this.wearParts[partType][partName]
|
||||||
|
|
||||||
|
// 检查是否有穿戴物品且是否是容器
|
||||||
|
if (!wearItem || !wearItem.type.includes('container') || !wearItem.items) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查索引是否有效
|
||||||
|
if (index < 0 || index >= wearItem.items.length) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取并取出物品
|
||||||
|
const item = wearItem.items[index]
|
||||||
|
wearItem.items.splice(index, 1)
|
||||||
|
wearItem.currentWeight -= item.weight
|
||||||
|
wearItem.currentVolume -= item.volume
|
||||||
|
return item
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -23,9 +23,10 @@ export default class WorldLand extends WorldTime {
|
|||||||
}
|
}
|
||||||
|
|
||||||
preload() {
|
preload() {
|
||||||
|
this.TilesPath = 'assets/PNG/Tiles/Tiles'
|
||||||
// 加载草地瓦片图
|
// 加载草地瓦片图
|
||||||
this.load.image(`grass`, `assets/PNG/Tiles/Tiles/tile_0024.png`)
|
this.load.image(`grass`, `${this.TilesPath}/tile_0024.png`)
|
||||||
this.load.image(`smallGrass`, `assets/PNG/Tiles/Tiles/tile_0044.png`)
|
this.load.image(`smallGrass`, `${this.TilesPath}/tile_0044.png`)
|
||||||
}
|
}
|
||||||
|
|
||||||
create() {
|
create() {
|
||||||
@@ -34,7 +35,7 @@ export default class WorldLand extends WorldTime {
|
|||||||
// 初始化场景切换条件
|
// 初始化场景切换条件
|
||||||
this.initSceneTransition()
|
this.initSceneTransition()
|
||||||
|
|
||||||
// 覆盖输入
|
// 输入
|
||||||
this.initInput()
|
this.initInput()
|
||||||
|
|
||||||
this.createTilemap() // 创建瓦片地图
|
this.createTilemap() // 创建瓦片地图
|
||||||
|
|||||||
Reference in new issue
Block a user