mirror of
http://junepve.top:3000/chicrobot/CINC.git
synced 2026-10-29 19:41:29 +08:00
310 lines
8.8 KiB
JavaScript
310 lines
8.8 KiB
JavaScript
// 物品类:表示游戏中的单个物品实体
|
|
|
|
export default class Item extends Phaser.GameObjects.Sprite {
|
|
constructor(scene, x, y, itemData) {
|
|
// 从itemData中提取精灵属性
|
|
const { id, name, description, type, weight, volume, value, gridSize, sprite, properties } = itemData;
|
|
|
|
// 创建一个简单的图形纹理作为物品精灵
|
|
if (!scene.textures.exists(id)) {
|
|
const canvas = document.createElement('canvas');
|
|
canvas.width = sprite.width;
|
|
canvas.height = sprite.height;
|
|
const ctx = canvas.getContext('2d');
|
|
|
|
// 设置物品颜色
|
|
ctx.fillStyle = `#${sprite.color.toString(16).padStart(6, '0')}`;
|
|
ctx.fillRect(0, 0, sprite.width, sprite.height);
|
|
|
|
// 添加物品边框
|
|
ctx.strokeStyle = '#000000';
|
|
ctx.lineWidth = 1;
|
|
ctx.strokeRect(0, 0, sprite.width, sprite.height);
|
|
|
|
// 添加物品ID的第一个字符作为图标
|
|
ctx.fillStyle = '#ffffff';
|
|
ctx.font = `${sprite.width * 0.8}px Arial`;
|
|
ctx.textAlign = 'center';
|
|
ctx.textBaseline = 'middle';
|
|
ctx.fillText(id.charAt(0).toUpperCase(), sprite.width / 2, sprite.height / 2);
|
|
|
|
// 将canvas添加为纹理
|
|
scene.textures.addCanvas(id, canvas);
|
|
}
|
|
|
|
// 调用父类构造函数创建精灵
|
|
super(scene, x, y, id);
|
|
|
|
// 设置物品属性
|
|
this.itemTypeId = id; // 物品类型ID,用于识别物品类型
|
|
this.id = `${id}_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`; // 生成唯一ID
|
|
this.name = name;
|
|
this.description = description;
|
|
this.type = type;
|
|
this.weight = weight;
|
|
this.volume = volume;
|
|
this.value = value;
|
|
this.gridSize = gridSize || { width: 1, height: 1 }; // 默认1x1网格
|
|
this.properties = properties;
|
|
|
|
// 背包相关属性
|
|
this.position = null; // 在背包中的位置
|
|
this.positionInInventory = null; // 在背包中的位置(保持向后兼容)
|
|
this.inInventory = false;
|
|
|
|
// 添加到场景中
|
|
scene.add.existing(this);
|
|
scene.physics.add.existing(this, true); // 静态物体,不响应物理碰撞
|
|
|
|
// 设置物品的碰撞体
|
|
this.setSize(sprite.width, sprite.height);
|
|
|
|
// 设置物品的交互性
|
|
this.setInteractive({
|
|
useHandCursor: true
|
|
});
|
|
|
|
// 绑定点击事件
|
|
this.on('pointerdown', (pointer) => {
|
|
// 检查鼠标是否在UI元素上,如果是则不处理
|
|
if (this.scene.inputSystem && this.scene.inputSystem.isMouseOnUI && this.scene.inputSystem.isMouseOnUI(pointer)) {
|
|
return;
|
|
}
|
|
|
|
// 添加视觉反馈:缩放物品
|
|
this.scene.tweens.add({
|
|
targets: this,
|
|
scale: { from: 1, to: 1.2, duration: 100, yoyo: true, repeat: 1 }
|
|
});
|
|
this.onItemClicked();
|
|
});
|
|
}
|
|
|
|
/**
|
|
* 检查单位是否在交互距离内
|
|
* @param {Object} unit - 要检查的单位
|
|
* @returns {boolean} - 是否在交互距离内
|
|
*/
|
|
isInInteractionRange(unit) {
|
|
const maxDistance = 50; // 最大交互距离
|
|
const dx = this.x - unit.x;
|
|
const dy = this.y - unit.y;
|
|
const distance = Math.sqrt(dx * dx + dy * dy);
|
|
return distance <= maxDistance;
|
|
}
|
|
|
|
/**
|
|
* 物品被点击时的处理函数
|
|
*/
|
|
onItemClicked() {
|
|
// 触发物品点击事件
|
|
this.scene.events.emit('item-clicked', this);
|
|
}
|
|
|
|
/**
|
|
* 拾取物品
|
|
* @param {Object} user - 拾取物品的单位
|
|
*/
|
|
pickup(user) {
|
|
// 检查是否在交互范围内
|
|
if (!this.isInInteractionRange(user)) {
|
|
console.log('距离太远,无法拾取物品');
|
|
return;
|
|
}
|
|
|
|
console.log(`${user.name} 拾取了 ${this.name}`);
|
|
|
|
// 检查用户是否有背包
|
|
if (user.inventory) {
|
|
// 尝试将物品添加到背包
|
|
const success = user.inventory.addItem(this);
|
|
if (success) {
|
|
this.inInventory = true;
|
|
|
|
// 保存场景引用,避免在destroy后访问undefined
|
|
const scene = this.scene;
|
|
|
|
// 如果场景中有背包UI,更新UI
|
|
if (scene && scene.inventoryUI) {
|
|
scene.inventoryUI.updateUI();
|
|
}
|
|
|
|
// 发射物品拾取事件
|
|
if (scene && scene.events) {
|
|
scene.events.emit('item-picked-up', this, user);
|
|
}
|
|
|
|
// 成功拾取后从地图上删除物品,避免潜在bug
|
|
this.destroy();
|
|
} else {
|
|
console.log('背包空间不足');
|
|
}
|
|
} else {
|
|
// 如果没有背包系统,简单移除物品
|
|
this.destroy();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 从背包中使用物品
|
|
* @param {Object} user - 使用物品的单位
|
|
*/
|
|
useFromInventory(user) {
|
|
// 从用户对象中获取场景引用
|
|
if (user && user.scene) {
|
|
this.scene = user.scene;
|
|
}
|
|
// 使用物品
|
|
this.use(user);
|
|
// 注意:物品的具体使用方法(如useSeed)中已经处理了从背包移除的逻辑
|
|
}
|
|
|
|
/**
|
|
* 设置物品的场景引用
|
|
* @param {Object} scene - 场景对象
|
|
*/
|
|
setScene(scene) {
|
|
this.scene = scene;
|
|
}
|
|
|
|
/**
|
|
* 创建物品实例(静态方法)
|
|
* @param {Object} itemData - 物品数据
|
|
* @returns {Item} 物品实例
|
|
*/
|
|
static createFromData(itemData) {
|
|
// 这个方法需要在具体场景中实现
|
|
// 因为需要场景上下文来创建精灵
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* 使用物品
|
|
* @param {Object} user - 使用物品的单位
|
|
*/
|
|
use(user) {
|
|
// 根据物品类型和属性执行不同的使用逻辑
|
|
switch (this.type) {
|
|
case 'food':
|
|
this.useFood(user);
|
|
break;
|
|
case 'medical':
|
|
this.useMedical(user);
|
|
break;
|
|
case 'tool':
|
|
this.useTool(user);
|
|
break;
|
|
case 'weapon':
|
|
this.equipWeapon(user);
|
|
break;
|
|
case 'seed':
|
|
this.useSeed(user);
|
|
break;
|
|
default:
|
|
console.log(`无法使用物品:${this.name}`);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 使用种子物品
|
|
* @param {Object} user - 使用物品的单位
|
|
*/
|
|
useSeed(user) {
|
|
console.log('DEBUG: useSeed 方法被调用');
|
|
if (this.properties.plantable) {
|
|
console.log(`DEBUG: ${user.name} 准备种植 ${this.name}`);
|
|
|
|
// 触发种植事件,让场景处理具体的种植逻辑
|
|
console.log('DEBUG: 触发 plant-seed 事件');
|
|
this.scene.events.emit('plant-seed', this, user);
|
|
|
|
// 注意:不立即从背包中移除种子,而是在实际种植时移除
|
|
// 这样用户可以取消种植而不会失去种子
|
|
|
|
// 显示种植提示
|
|
this.scene.events.emit('show-message', `准备种植 ${this.name}`);
|
|
} else {
|
|
console.log(`DEBUG: ${this.name} 不可种植`);
|
|
this.scene.events.emit('show-message', `${this.name} 不可种植`);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 使用食物物品
|
|
* @param {Object} user - 使用物品的单位
|
|
*/
|
|
useFood(user) {
|
|
if (this.properties.drinkable) {
|
|
// 处理饮水逻辑
|
|
console.log(`${user.name} 喝了 ${this.name}`);
|
|
if (user.hydration !== undefined) {
|
|
user.hydration = Math.min(100, user.hydration + this.properties.hydration);
|
|
}
|
|
} else if (this.properties.edible) {
|
|
// 处理进食逻辑
|
|
console.log(`${user.name} 吃了 ${this.name}`);
|
|
if (user.nutrition !== undefined) {
|
|
user.nutrition = Math.min(100, user.nutrition + this.properties.nutrition);
|
|
}
|
|
if (user.hydration !== undefined) {
|
|
user.hydration = Math.min(100, user.hydration + (this.properties.hydration || 0));
|
|
}
|
|
}
|
|
|
|
// 使用后移除物品
|
|
this.destroy();
|
|
}
|
|
|
|
/**
|
|
* 使用医疗物品
|
|
* @param {Object} user - 使用物品的单位
|
|
*/
|
|
useMedical(user) {
|
|
if (this.properties.heal_amount && user.health !== undefined) {
|
|
console.log(`${user.name} 使用了 ${this.name}`);
|
|
user.health = Math.min(100, user.health + this.properties.heal_amount);
|
|
// 使用后移除物品
|
|
this.destroy();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 使用工具物品
|
|
* @param {Object} user - 使用物品的单位
|
|
*/
|
|
useTool(user) {
|
|
console.log(`${user.name} 使用了工具:${this.name}`);
|
|
// 工具使用逻辑可以根据具体工具类型扩展
|
|
}
|
|
|
|
/**
|
|
* 装备武器
|
|
* @param {Object} user - 装备武器的单位
|
|
*/
|
|
equipWeapon(user) {
|
|
console.log(`${user.name} 装备了武器:${this.name}`);
|
|
// 装备武器逻辑
|
|
if (user.equipWeapon) {
|
|
user.equipWeapon(this);
|
|
}
|
|
// 装备后可以选择保留物品或移除,这里选择保留
|
|
}
|
|
|
|
/**
|
|
* 获取物品的详细信息
|
|
* @returns {Object} 物品信息对象
|
|
*/
|
|
getInfo() {
|
|
return {
|
|
id: this.id,
|
|
name: this.name,
|
|
description: this.description,
|
|
type: this.type,
|
|
weight: this.weight,
|
|
volume: this.volume,
|
|
value: this.value,
|
|
gridSize: this.gridSize,
|
|
properties: this.properties
|
|
};
|
|
}
|
|
} |