mirror of
http://junepve.top:3000/chicrobot/CINC.git
synced 2026-10-30 00:31:29 +08:00
feat(item) 添加物品系统
This commit is contained in:
1 parent
606e833f33
commit
2f7210f47e
4 files changed
+1127
No files matched your search
@@ -0,0 +1,494 @@
|
||||
// 物品系统测试场景
|
||||
|
||||
import Unit from '../objects/Unit.js';
|
||||
import { InputSystem } from '../systems/InputSystem.js';
|
||||
import { SelectionSystem } from '../systems/SelectionSystem.js';
|
||||
import { CommandSystem } from '../systems/CommandSystem.js';
|
||||
import { ItemManager } from '../items/ItemManager.js';
|
||||
|
||||
export default class ItemTestScene extends Phaser.Scene {
|
||||
constructor() {
|
||||
super({ key: 'ItemTestScene' });
|
||||
}
|
||||
|
||||
create() {
|
||||
// 物理世界和相机边界
|
||||
const worldSize = 1000;
|
||||
this.physics.world.setBounds(-worldSize, -worldSize, worldSize * 2, worldSize * 2);
|
||||
this.cameras.main.setBounds(-worldSize, -worldSize, worldSize * 2, worldSize * 2);
|
||||
this.cameras.main.centerOn(0, 0);
|
||||
|
||||
// 初始化系统
|
||||
this.inputSystem = new InputSystem(this, {
|
||||
keyboard: true,
|
||||
mouse: true,
|
||||
joystick: false,
|
||||
selection: true
|
||||
});
|
||||
this.selectionSystem = new SelectionSystem(this);
|
||||
this.commandSystem = new CommandSystem(this);
|
||||
|
||||
// 创建单位组
|
||||
this.unitGroup = this.add.group();
|
||||
|
||||
// 创建一个测试单位
|
||||
const unit = new Unit(this, 0, 0, 'player');
|
||||
// 为单位添加一些属性,用于测试物品效果
|
||||
unit.name = '测试单位';
|
||||
unit.health = 100;
|
||||
unit.nutrition = 50;
|
||||
unit.hydration = 50;
|
||||
unit.equipWeapon = function(weapon) {
|
||||
this.weapon = weapon;
|
||||
console.log(`${this.name} 装备了 ${weapon.name}`);
|
||||
};
|
||||
this.unitGroup.add(unit);
|
||||
|
||||
// 自动选中单位
|
||||
this.events.emit('select-unit', unit);
|
||||
|
||||
// 添加碰撞检测
|
||||
this.physics.add.collider(this.unitGroup, this.unitGroup);
|
||||
|
||||
// 初始化物品管理器
|
||||
this.itemManager = new ItemManager(this);
|
||||
|
||||
// 当物品数据加载完成后创建初始物品
|
||||
this.itemManager.onDataLoaded(() => {
|
||||
this.createInitialItems();
|
||||
});
|
||||
|
||||
// 创建侧边栏UI(先创建,确保它在最底层)
|
||||
this.createSidebar();
|
||||
|
||||
// 添加场景说明文本
|
||||
const titleText = this.add.text(10, 10, '物品系统测试场景', {
|
||||
fontSize: '20px',
|
||||
fill: '#ffffff'
|
||||
});
|
||||
titleText.setScrollFactor(0, 0); // 固定在屏幕上,不随相机移动
|
||||
titleText.setDepth(10); // 设置深度,确保显示在侧边栏上方
|
||||
|
||||
const moveText = this.add.text(10, 40, 'WASD或方向键移动单位,左键点击选择单位', {
|
||||
fontSize: '16px',
|
||||
fill: '#ffffff'
|
||||
});
|
||||
moveText.setScrollFactor(0, 0); // 固定在屏幕上,不随相机移动
|
||||
moveText.setDepth(10); // 设置深度,确保显示在侧边栏上方
|
||||
|
||||
const itemText = this.add.text(10, 70, '点击物品查看信息,右键移动到物品位置', {
|
||||
fontSize: '16px',
|
||||
fill: '#ffffff'
|
||||
});
|
||||
itemText.setScrollFactor(0, 0); // 固定在屏幕上,不随相机移动
|
||||
itemText.setDepth(10); // 设置深度,确保显示在侧边栏上方
|
||||
|
||||
const key1Text = this.add.text(10, 100, '按1键:创建随机物品', {
|
||||
fontSize: '16px',
|
||||
fill: '#ffffff'
|
||||
});
|
||||
key1Text.setScrollFactor(0, 0); // 固定在屏幕上,不随相机移动
|
||||
key1Text.setDepth(10); // 设置深度,确保显示在侧边栏上方
|
||||
|
||||
const key2Text = this.add.text(10, 130, '按2键:创建食物类物品', {
|
||||
fontSize: '16px',
|
||||
fill: '#ffffff'
|
||||
});
|
||||
key2Text.setScrollFactor(0, 0); // 固定在屏幕上,不随相机移动
|
||||
key2Text.setDepth(10); // 设置深度,确保显示在侧边栏上方
|
||||
|
||||
const key3Text = this.add.text(10, 160, '按3键:创建工具类物品', {
|
||||
fontSize: '16px',
|
||||
fill: '#ffffff'
|
||||
});
|
||||
key3Text.setScrollFactor(0, 0); // 固定在屏幕上,不随相机移动
|
||||
key3Text.setDepth(10); // 设置深度,确保显示在侧边栏上方
|
||||
|
||||
const key4Text = this.add.text(10, 190, '按4键:清理所有物品', {
|
||||
fontSize: '16px',
|
||||
fill: '#ffffff'
|
||||
});
|
||||
key4Text.setScrollFactor(0, 0); // 固定在屏幕上,不随相机移动
|
||||
key4Text.setDepth(10); // 设置深度,确保显示在侧边栏上方
|
||||
|
||||
const spaceText = this.add.text(10, 220, '按空格键返回启动场景', {
|
||||
fontSize: '16px',
|
||||
fill: '#ffffff'
|
||||
});
|
||||
spaceText.setScrollFactor(0, 0); // 固定在屏幕上,不随相机移动
|
||||
spaceText.setDepth(10); // 设置深度,确保显示在侧边栏上方
|
||||
|
||||
// 显示单位状态
|
||||
this.updateUnitStatus(unit);
|
||||
|
||||
// 显示默认提示
|
||||
this.itemInfoText.setText('未选择任何物品');
|
||||
this.interactionText.setText('点击物品查看详细信息,交互范围50像素');
|
||||
this.generalInfoText.setText('欢迎使用物品系统测试场景');
|
||||
|
||||
// 添加场景提示信息
|
||||
const interactionHintText = this.add.text(10, 250, '点击物品查看详细信息,交互范围50像素', {
|
||||
fontSize: '16px',
|
||||
fill: '#ffffff'
|
||||
});
|
||||
interactionHintText.setScrollFactor(0, 0); // 固定在屏幕上,不随相机移动
|
||||
interactionHintText.setDepth(10); // 设置深度,确保显示在侧边栏上方
|
||||
|
||||
// 注册键盘事件
|
||||
this.input.keyboard.on('keydown-ONE', () => {
|
||||
this.itemManager.createRandomItem();
|
||||
});
|
||||
|
||||
this.input.keyboard.on('keydown-TWO', () => {
|
||||
// 在单位附近创建食物类物品
|
||||
const x = unit.x + Phaser.Math.Between(-100, 100);
|
||||
const y = unit.y + Phaser.Math.Between(-100, 100);
|
||||
this.itemManager.createItemByType('food', x, y);
|
||||
});
|
||||
|
||||
this.input.keyboard.on('keydown-THREE', () => {
|
||||
// 在单位附近创建工具类物品
|
||||
const x = unit.x + Phaser.Math.Between(-100, 100);
|
||||
const y = unit.y + Phaser.Math.Between(-100, 100);
|
||||
this.itemManager.createItemByType('tool', x, y);
|
||||
});
|
||||
|
||||
this.input.keyboard.on('keydown-FOUR', () => {
|
||||
this.itemManager.clearAllItems();
|
||||
this.itemInfoText.setText('所有物品已清理');
|
||||
});
|
||||
|
||||
this.input.keyboard.on('keydown-SPACE', () => {
|
||||
this.scene.start('BootScene');
|
||||
});
|
||||
|
||||
// 监听物品点击事件
|
||||
this.events.on('item-clicked', (item) => {
|
||||
this.showItemInfo(item);
|
||||
});
|
||||
|
||||
// 创建一些交互按钮
|
||||
this.createButtons();
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建初始物品
|
||||
*/
|
||||
createInitialItems() {
|
||||
// 在不同位置创建各种类型的物品
|
||||
const itemTypes = ['food', 'tool', 'medical', 'weapon'];
|
||||
const unit = this.unitGroup.getFirstAlive();
|
||||
|
||||
for (let i = 0; i < itemTypes.length; i++) {
|
||||
const x = unit.x + (i - 2) * 200;
|
||||
const y = unit.y - 200;
|
||||
this.itemManager.createItemByType(itemTypes[i], x, y);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建交互按钮
|
||||
*/
|
||||
createButtons() {
|
||||
const buttonWidth = 200;
|
||||
const buttonHeight = 40;
|
||||
const buttonY = this.sys.game.config.height - 100;
|
||||
|
||||
// 创建随机物品按钮
|
||||
this.createButton(this.sys.game.config.width - buttonWidth - 10, buttonY, '创建随机物品', () => {
|
||||
this.itemManager.createRandomItem();
|
||||
});
|
||||
|
||||
// 创建清理物品按钮
|
||||
this.createButton(this.sys.game.config.width - buttonWidth - 10, buttonY + 50, '清理所有物品', () => {
|
||||
this.itemManager.clearAllItems();
|
||||
this.itemInfoText.setText('所有物品已清理');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建按钮
|
||||
* @param {number} x - 按钮x坐标
|
||||
* @param {number} y - 按钮y坐标
|
||||
* @param {string} text - 按钮文本
|
||||
* @param {function} callback - 点击回调函数
|
||||
*/
|
||||
createButton(x, y, text, callback) {
|
||||
// 创建按钮背景
|
||||
const button = this.add.rectangle(x, y, 200, 40, 0x333333);
|
||||
button.setOrigin(0.5, 0.5);
|
||||
button.setScrollFactor(0, 0); // 固定在屏幕上,不随相机移动
|
||||
button.setDepth(15); // 设置深度,确保显示在场景说明文本上方
|
||||
|
||||
// 创建按钮文本
|
||||
const buttonText = this.add.text(x, y, text, {
|
||||
fontSize: '16px',
|
||||
fill: '#ffffff',
|
||||
fontFamily: 'Arial'
|
||||
});
|
||||
buttonText.setOrigin(0.5, 0.5);
|
||||
buttonText.setScrollFactor(0, 0); // 固定在屏幕上,不随相机移动
|
||||
buttonText.setDepth(16); // 设置深度,确保显示在按钮背景上方
|
||||
|
||||
// 设置按钮交互
|
||||
button.setInteractive({
|
||||
useHandCursor: true
|
||||
});
|
||||
|
||||
// 按钮事件
|
||||
button.on('pointerdown', callback);
|
||||
|
||||
button.on('pointerover', () => {
|
||||
button.setFillStyle(0x555555);
|
||||
});
|
||||
|
||||
button.on('pointerout', () => {
|
||||
button.setFillStyle(0x333333);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 显示物品信息
|
||||
* @param {Item} item - 物品实例
|
||||
*/
|
||||
showItemInfo(item) {
|
||||
const unit = this.unitGroup.getFirstAlive();
|
||||
const isInRange = item.isInInteractionRange(unit);
|
||||
|
||||
const info = item.getInfo();
|
||||
let infoText = `${info.name}\n`;
|
||||
infoText += `${info.description}\n`;
|
||||
infoText += `类型: ${info.type}\n`;
|
||||
infoText += `重量: ${info.weight}kg\n`;
|
||||
infoText += `体积: ${info.volume}L\n`;
|
||||
infoText += `价值: ${info.value}金币\n`;
|
||||
infoText += `距离: ${Math.round(Math.sqrt(Math.pow(item.x - unit.x, 2) + Math.pow(item.y - unit.y, 2)))}m\n`;
|
||||
|
||||
// 显示物品属性
|
||||
infoText += '属性: ';
|
||||
const properties = [];
|
||||
for (const [key, value] of Object.entries(info.properties)) {
|
||||
properties.push(`${key}: ${value}`);
|
||||
}
|
||||
infoText += properties.join(', ');
|
||||
|
||||
this.itemInfoText.setText(infoText);
|
||||
|
||||
// 显示交互提示
|
||||
if (isInRange) {
|
||||
this.interactionText.setText('按E键拾取物品,按Q键快捷使用');
|
||||
// 注册E键拾取物品
|
||||
this.input.keyboard.once('keydown-E', () => {
|
||||
item.pickup(unit);
|
||||
this.interactionText.setText('');
|
||||
this.itemInfoText.setText('未选择任何物品');
|
||||
});
|
||||
// 注册Q键快捷使用物品
|
||||
this.input.keyboard.once('keydown-Q', () => {
|
||||
item.use(unit);
|
||||
this.interactionText.setText('');
|
||||
this.itemInfoText.setText('未选择任何物品');
|
||||
});
|
||||
} else {
|
||||
this.interactionText.setText('距离太远,无法交互');
|
||||
}
|
||||
|
||||
// 移除5秒后自动清除的逻辑,让信息保持显示
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建侧边栏UI
|
||||
*/
|
||||
createSidebar() {
|
||||
// 侧边栏宽度
|
||||
const sidebarWidth = 300;
|
||||
const sidebarDepth = 5; // 侧边栏深度值,确保显示在游戏元素上方,但低于场景说明文本
|
||||
|
||||
// 创建侧边栏背景
|
||||
this.sidebar = this.add.rectangle(
|
||||
this.sys.game.config.width - sidebarWidth,
|
||||
0,
|
||||
sidebarWidth,
|
||||
this.sys.game.config.height,
|
||||
0x111111,
|
||||
0.9
|
||||
);
|
||||
this.sidebar.setOrigin(0, 0);
|
||||
this.sidebar.setScrollFactor(0, 0); // 固定在屏幕上,不随相机移动
|
||||
this.sidebar.setDepth(sidebarDepth); // 设置深度,确保显示在游戏元素上方
|
||||
|
||||
// 添加侧边栏边框
|
||||
this.sidebarBorder = this.add.rectangle(
|
||||
this.sys.game.config.width - sidebarWidth,
|
||||
0,
|
||||
sidebarWidth,
|
||||
this.sys.game.config.height,
|
||||
0x444444,
|
||||
0
|
||||
);
|
||||
this.sidebarBorder.setOrigin(0, 0);
|
||||
this.sidebarBorder.setStrokeStyle(2, 0x444444, 1);
|
||||
this.sidebarBorder.setScrollFactor(0, 0); // 固定在屏幕上,不随相机移动
|
||||
this.sidebarBorder.setDepth(sidebarDepth + 1); // 设置深度,确保显示在侧边栏背景上方
|
||||
|
||||
// 侧边栏标题
|
||||
const title = this.add.text(
|
||||
this.sys.game.config.width - sidebarWidth + 20,
|
||||
20,
|
||||
'游戏信息面板',
|
||||
{
|
||||
fontSize: '20px',
|
||||
fill: '#ffffff',
|
||||
fontWeight: 'bold'
|
||||
}
|
||||
);
|
||||
title.setScrollFactor(0, 0); // 固定在屏幕上,不随相机移动
|
||||
title.setDepth(sidebarDepth + 2); // 设置深度,确保显示在侧边栏边框上方
|
||||
|
||||
// 通用信息区域标题
|
||||
const generalTitle = this.add.text(
|
||||
this.sys.game.config.width - sidebarWidth + 20,
|
||||
50,
|
||||
'通用信息:',
|
||||
{
|
||||
fontSize: '16px',
|
||||
fill: '#4CAF50',
|
||||
fontWeight: 'bold'
|
||||
}
|
||||
);
|
||||
generalTitle.setScrollFactor(0, 0); // 固定在屏幕上,不随相机移动
|
||||
generalTitle.setDepth(sidebarDepth + 2); // 设置深度,确保显示在侧边栏边框上方
|
||||
|
||||
this.generalInfoText = this.add.text(
|
||||
this.sys.game.config.width - sidebarWidth + 20,
|
||||
75,
|
||||
'',
|
||||
{
|
||||
fontSize: '14px',
|
||||
fill: '#ffffff',
|
||||
wordWrap: {
|
||||
width: sidebarWidth - 40
|
||||
}
|
||||
}
|
||||
);
|
||||
this.generalInfoText.setScrollFactor(0, 0); // 固定在屏幕上,不随相机移动
|
||||
this.generalInfoText.setDepth(sidebarDepth + 2); // 设置深度,确保显示在侧边栏边框上方
|
||||
|
||||
// 角色属性区域标题
|
||||
const characterTitle = this.add.text(
|
||||
this.sys.game.config.width - sidebarWidth + 20,
|
||||
120,
|
||||
'角色属性:',
|
||||
{
|
||||
fontSize: '16px',
|
||||
fill: '#2196F3',
|
||||
fontWeight: 'bold'
|
||||
}
|
||||
);
|
||||
characterTitle.setScrollFactor(0, 0); // 固定在屏幕上,不随相机移动
|
||||
characterTitle.setDepth(sidebarDepth + 2); // 设置深度,确保显示在侧边栏边框上方
|
||||
|
||||
this.unitStatusText = this.add.text(
|
||||
this.sys.game.config.width - sidebarWidth + 20,
|
||||
145,
|
||||
'',
|
||||
{
|
||||
fontSize: '14px',
|
||||
fill: '#ffffff',
|
||||
wordWrap: {
|
||||
width: sidebarWidth - 40
|
||||
}
|
||||
}
|
||||
);
|
||||
this.unitStatusText.setScrollFactor(0, 0); // 固定在屏幕上,不随相机移动
|
||||
this.unitStatusText.setDepth(sidebarDepth + 2); // 设置深度,确保显示在侧边栏边框上方
|
||||
|
||||
// 交互提示区域标题
|
||||
const interactionTitle = this.add.text(
|
||||
this.sys.game.config.width - sidebarWidth + 20,
|
||||
220,
|
||||
'交互提示:',
|
||||
{
|
||||
fontSize: '16px',
|
||||
fill: '#FFEB3B',
|
||||
fontWeight: 'bold'
|
||||
}
|
||||
);
|
||||
interactionTitle.setScrollFactor(0, 0); // 固定在屏幕上,不随相机移动
|
||||
interactionTitle.setDepth(sidebarDepth + 2); // 设置深度,确保显示在侧边栏边框上方
|
||||
|
||||
this.interactionText = this.add.text(
|
||||
this.sys.game.config.width - sidebarWidth + 20,
|
||||
245,
|
||||
'',
|
||||
{
|
||||
fontSize: '14px',
|
||||
fill: '#ffff00',
|
||||
wordWrap: {
|
||||
width: sidebarWidth - 40
|
||||
}
|
||||
}
|
||||
);
|
||||
this.interactionText.setScrollFactor(0, 0); // 固定在屏幕上,不随相机移动
|
||||
this.interactionText.setDepth(sidebarDepth + 2); // 设置深度,确保显示在侧边栏边框上方
|
||||
|
||||
// 物品详情区域标题
|
||||
const itemTitle = this.add.text(
|
||||
this.sys.game.config.width - sidebarWidth + 20,
|
||||
350,
|
||||
'物品详情:',
|
||||
{
|
||||
fontSize: '16px',
|
||||
fill: '#FF9800',
|
||||
fontWeight: 'bold'
|
||||
}
|
||||
);
|
||||
itemTitle.setScrollFactor(0, 0); // 固定在屏幕上,不随相机移动
|
||||
itemTitle.setDepth(sidebarDepth + 2); // 设置深度,确保显示在侧边栏边框上方
|
||||
|
||||
this.itemInfoText = this.add.text(
|
||||
this.sys.game.config.width - sidebarWidth + 20,
|
||||
375,
|
||||
'',
|
||||
{
|
||||
fontSize: '14px',
|
||||
fill: '#ffffff',
|
||||
wordWrap: {
|
||||
width: sidebarWidth - 40
|
||||
}
|
||||
}
|
||||
);
|
||||
this.itemInfoText.setScrollFactor(0, 0); // 固定在屏幕上,不随相机移动
|
||||
this.itemInfoText.setDepth(sidebarDepth + 2); // 设置深度,确保显示在侧边栏边框上方
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新单位状态显示
|
||||
* @param {Unit} unit - 单位实例
|
||||
*/
|
||||
updateUnitStatus(unit) {
|
||||
let statusText = `${unit.name} 状态:\n`;
|
||||
statusText += `生命值: ${unit.health}\n`;
|
||||
statusText += `营养值: ${unit.nutrition}\n`;
|
||||
statusText += `水分值: ${unit.hydration}\n`;
|
||||
if (unit.weapon) {
|
||||
statusText += `武器: ${unit.weapon.name}`;
|
||||
}
|
||||
|
||||
this.unitStatusText.setText(statusText);
|
||||
}
|
||||
|
||||
update() {
|
||||
this.inputSystem.update();
|
||||
|
||||
// 更新所有单位
|
||||
this.unitGroup.getChildren().forEach(unit => {
|
||||
if (unit.update) {
|
||||
unit.update();
|
||||
}
|
||||
unit.updateMovement();
|
||||
// 更新单位状态显示
|
||||
this.updateUnitStatus(unit);
|
||||
});
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user