feat(SS) 添加物品类、单位类

This commit is contained in:
chicrobot committed 2026-02-13 18:18:32 +08:00
1 parent cbbed1519e
commit 494922246b
11 files changed
+440 -855

No files matched your search

+138 -67
View File
@@ -4,44 +4,37 @@
* 允许用户控制角色,NPC 自动搜索并收集小草
*/
import BreatheLife from './BreatheLife.js'
import Unit from '../objects/Unit.js'
import SearchBehavior from '../behaviors/SearchBehavior.js'
import { generateUUID } from '../utils/String.js'
export default class Control extends BreatheLife {
constructor(sceneKey = 'Control') {
// 场景相关
super(sceneKey)
this.nextScene = 'InfoBar'
}
preload() {
async preload() {
super.preload()
// 加载仙人掌图片
this.load.image('cactus', `${this.TilesPath}/tile_0063.png`)
// 加载物品配置
await Item.loadItemsConfig(this)
}
create() {
super.create()
// 设置 Control 场景的目标角色数量
this.targetCount = 2 // 目标角色数量
// 初始化输入事件
// 场景切换条件
this.initSceneTransition()
// 输入事件
this.initInput()
// 添加随机NPC
this.addRandomNPCs()
}
update() {
super.update()
// 更新所有 NPC 的行为
this.NPCObjects.forEach(npc => {
if (npc.update) {
npc.update()
}
})
initSceneTransition() {
this.cactusObjects = [] // 维护仙人掌集合
}
// Control 场景不再需要覆盖 initSceneTransition 方法
// 数组初始化由父类 BreatheLife.create() 中的 initSceneTransition() 完成
// targetCount 通过在 create() 中直接设置来覆盖
initInput() {
// 移除父类的输入事件监听器,避免重复监听
super.removeListener()
@@ -53,6 +46,10 @@ export default class Control extends BreatheLife {
this.handleClick(x, y)
})
}
update() {
super.update()
}
/**
* 处理点击事件
@@ -65,56 +62,130 @@ export default class Control extends BreatheLife {
console.log("点击到的精灵:", clickedSprite)
if (clickedSprite && this.NPCObjects.includes(clickedSprite)) { // 如果点击到了角色
this.handleSpriteClick(clickedSprite)
}else if (this.NPCObjects.length < this.targetCount) {
// 如果角色数量不足目标数量,创建新的角色
const sprite = this.physics.add.sprite(x, y, 'player').setScale(1).setOrigin(0.5, 1)
sprite.setDepth(this.SpriteDepth) // 设置角色层级
this.NPCObjects.push(sprite) // 加入角色集合
}else{
}
}
/**
* 创建NPC
* @param {number} x - NPC的 x 坐标
* @param {number} y - NPC的 y 坐标
*/
createNPC(x, y) {
// 使用 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)
})
addRandomNPCs(count = 3) {
// 随机生成NPC
for (let i = 0; i < count; i++) {
const randomX = Phaser.Math.Between(100, this.sys.game.config.width - 100)
const randomY = Phaser.Math.Between(100, this.sys.game.config.height - 100)
const npc = new Human(this, randomX, randomY, 'human')
this.NPCObjects.push(npc)
}
}
}
/**
* 物品类
* 用于表示游戏中的可收集物品
* @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)
}
}
}