From 8670595ebd0fbc2251643100d318c7d47f86fbb9 Mon Sep 17 00:00:00 2001 From: Yosgi Date: Sat, 15 Feb 2025 21:58:24 +1300 Subject: [PATCH 1/4] Ai action updated --- gamefi/app/components/BattleScene.ts | 68 +++--- .../components/controllers/AI/AIController.ts | 194 ++++++++++++++++++ .../app/components/controllers/AI/AIInput.ts | 9 + .../controllers/AI/BehaviorManager.ts | 41 ++++ .../components/controllers/AIController.ts | 0 .../components/controllers/BaseController.ts | 159 ++++++++++++++ .../Player/PlayerBehaviorProfile.ts | 8 + .../controllers/Player/PlayerController.ts | 50 +++++ .../controllers/PlayerAnimationManager.ts | 6 +- .../components/controllers/PlayerAttack.ts | 16 +- .../controllers/PlayerController.ts | 7 +- .../app/components/controllers/PlayerJump.ts | 23 ++- .../components/controllers/PlayerMovement.ts | 13 +- .../controllers/PlayerStateManager.ts | 5 +- gamefi/app/global.d.ts | 15 ++ gamefi/global.d.ts | 6 +- gamefi/public/assets/monster/Idle.png | Bin 21408 -> 0 bytes gamefi/public/assets/monster/attack1.png | Bin 22202 -> 0 bytes gamefi/public/assets/monster/attack2.png | Bin 21135 -> 0 bytes gamefi/public/assets/monster/attack3.png | Bin 21826 -> 0 bytes gamefi/public/assets/monster/death.png | Bin 20234 -> 0 bytes gamefi/public/assets/monster/defend.png | Bin 20159 -> 0 bytes gamefi/public/assets/monster/hurt.png | Bin 20167 -> 0 bytes gamefi/public/assets/monster/jump.png | Bin 24963 -> 0 bytes gamefi/public/assets/monster/run.png | Bin 24456 -> 0 bytes gamefi/public/assets/monster/walk.png | Bin 22814 -> 0 bytes gamefi/public/assets/player/attack1.png | Bin 4107 -> 0 bytes gamefi/public/assets/player/attack2.png | Bin 3048 -> 0 bytes gamefi/public/assets/player/attack3.png | Bin 4184 -> 0 bytes gamefi/public/assets/player/death.png | Bin 6212 -> 0 bytes gamefi/public/assets/player/defend.png | Bin 3545 -> 0 bytes gamefi/public/assets/player/hurt.png | Bin 2631 -> 0 bytes gamefi/public/assets/player/idle.png | Bin 3525 -> 0 bytes gamefi/public/assets/player/jump.png | Bin 3369 -> 0 bytes gamefi/public/assets/player/run.png | Bin 5394 -> 0 bytes gamefi/public/assets/player/walk.png | Bin 5790 -> 0 bytes .../public/assets/vagabond/attack1/attack.png | Bin 0 -> 2776 bytes .../assets/vagabond/attack2/attack2.png | Bin 0 -> 2503 bytes gamefi/public/assets/vagabond/block/block.png | Bin 0 -> 539 bytes gamefi/public/assets/vagabond/dash/dash.png | Bin 0 -> 609 bytes gamefi/public/assets/vagabond/death/death.png | Bin 0 -> 745 bytes gamefi/public/assets/vagabond/idle/idle.png | Bin 0 -> 375 bytes .../vagabond/jump-attack/jump-attack.png | Bin 0 -> 2997 bytes .../assets/vagabond/jump-flip/jump-flip.png | Bin 0 -> 691 bytes 44 files changed, 568 insertions(+), 52 deletions(-) create mode 100644 gamefi/app/components/controllers/AI/AIController.ts create mode 100644 gamefi/app/components/controllers/AI/AIInput.ts create mode 100644 gamefi/app/components/controllers/AI/BehaviorManager.ts delete mode 100644 gamefi/app/components/controllers/AIController.ts create mode 100644 gamefi/app/components/controllers/Player/PlayerBehaviorProfile.ts create mode 100644 gamefi/app/components/controllers/Player/PlayerController.ts create mode 100644 gamefi/app/global.d.ts delete mode 100644 gamefi/public/assets/monster/Idle.png delete mode 100644 gamefi/public/assets/monster/attack1.png delete mode 100644 gamefi/public/assets/monster/attack2.png delete mode 100644 gamefi/public/assets/monster/attack3.png delete mode 100644 gamefi/public/assets/monster/death.png delete mode 100644 gamefi/public/assets/monster/defend.png delete mode 100644 gamefi/public/assets/monster/hurt.png delete mode 100644 gamefi/public/assets/monster/jump.png delete mode 100644 gamefi/public/assets/monster/run.png delete mode 100644 gamefi/public/assets/monster/walk.png delete mode 100644 gamefi/public/assets/player/attack1.png delete mode 100644 gamefi/public/assets/player/attack2.png delete mode 100644 gamefi/public/assets/player/attack3.png delete mode 100644 gamefi/public/assets/player/death.png delete mode 100644 gamefi/public/assets/player/defend.png delete mode 100644 gamefi/public/assets/player/hurt.png delete mode 100644 gamefi/public/assets/player/idle.png delete mode 100644 gamefi/public/assets/player/jump.png delete mode 100644 gamefi/public/assets/player/run.png delete mode 100644 gamefi/public/assets/player/walk.png create mode 100644 gamefi/public/assets/vagabond/attack1/attack.png create mode 100644 gamefi/public/assets/vagabond/attack2/attack2.png create mode 100644 gamefi/public/assets/vagabond/block/block.png create mode 100644 gamefi/public/assets/vagabond/dash/dash.png create mode 100644 gamefi/public/assets/vagabond/death/death.png create mode 100644 gamefi/public/assets/vagabond/idle/idle.png create mode 100644 gamefi/public/assets/vagabond/jump-attack/jump-attack.png create mode 100644 gamefi/public/assets/vagabond/jump-flip/jump-flip.png diff --git a/gamefi/app/components/BattleScene.ts b/gamefi/app/components/BattleScene.ts index 93d82c1..f404181 100644 --- a/gamefi/app/components/BattleScene.ts +++ b/gamefi/app/components/BattleScene.ts @@ -1,6 +1,8 @@ import Phaser from 'phaser'; import { PlayerController } from './controllers/PlayerController'; import { loadPlayerSpriteSheets, createPlayerAnimations } from './assets/PlayerSpriteLoader'; +import { AIController } from './controllers/AI/AIController'; +import { CharState } from './controllers/CharState'; // 如果你仍有需要 hp 字段,可定义 interface SpriteWithHP extends Phaser.Physics.Arcade.Sprite { @@ -9,7 +11,7 @@ interface SpriteWithHP extends Phaser.Physics.Arcade.Sprite { export class BattleScene extends Phaser.Scene { private playerCtrl!: PlayerController; - private monsterCtrl!: PlayerController; + private monsterCtrl!: AIController; private playerSprite!: SpriteWithHP; private monsterSprite!: SpriteWithHP; @@ -28,7 +30,7 @@ export class BattleScene extends Phaser.Scene { // 分别加载“player”资源 & “monster”资源 loadPlayerSpriteSheets(this, 'assets/hero', 'hero', { width: 64, height: 44 }); - // loadPlayerSpriteSheets(this, 'assets/monster', 'monster', { width: 128, height: 128 }); + loadPlayerSpriteSheets(this, 'assets/hero', 'hero', { width: 64, height: 44 }); } public create(): void { @@ -41,7 +43,7 @@ export class BattleScene extends Phaser.Scene { // 创建动画 (player / monster) createPlayerAnimations(this, 'hero'); - // createPlayerAnimations(this, 'monster'); + createPlayerAnimations(this, 'hero'); // ============ 创建玩家 ============ // 1) 用 PlayerController, 传入初始纹理 (如 'player_idle') @@ -51,6 +53,7 @@ export class BattleScene extends Phaser.Scene { this.playerSprite.hp = 100; this.playerSprite.setCollideWorldBounds(true); this.physics.add.collider(this.playerSprite, ground); + (window as any).playerSprite = this.playerSprite; // HP 文本 this.playerHpText = this.add.text(20, 20, `PLAYER HP: ${this.playerSprite.hp}`, { fontSize: '16px', @@ -58,47 +61,60 @@ export class BattleScene extends Phaser.Scene { }); // ============ 创建怪物 ============ - // 2) 再来一个 PlayerController / 或 AIController - // 并给它用“monster_idle”作为纹理 - // this.monsterCtrl = new PlayerController(this, 600, 300, 'monster_idle'); - // this.monsterSprite = this.monsterCtrl.sprite as SpriteWithHP; - // this.monsterSprite.hp = 100; - // this.monsterSprite.setCollideWorldBounds(true); - // this.physics.add.collider(this.monsterSprite, ground); - - // // HP 文本 - // this.monsterHpText = this.add.text(600, 20, `MONSTER HP: ${this.monsterSprite.hp}`, { - // fontSize: '16px', - // color: '#ffffff' - // }); + // ============ 创建对手(怪物/AI) ============ + this.monsterCtrl = new AIController(this, 600, 300, 'hero_idle', { + hp: 100, + scaleFactor: 1.5, + debug: true, + // 可传入 AI 专用参数,如 dashAttackInitialSpeed、dashAttackDeceleration 等 + dashAttackInitialSpeed: 700, + dashAttackDeceleration: 0.95 + }); + this.monsterSprite = this.monsterCtrl.sprite as SpriteWithHP; + this.monsterSprite.hp = 100; + this.monsterSprite.setCollideWorldBounds(true); + this.physics.add.collider(this.monsterSprite, ground); + + this.monsterHpText = this.add.text(600, 20, `MONSTER HP: ${this.monsterSprite.hp}`, { + fontSize: '16px', + color: '#ffffff' + }); // 播放 Idle 动画 this.playerSprite.play('hero-idle'); - // this.monsterSprite.play('monster-idle'); + this.monsterSprite.play('hero-idle'); } public update(time: number, delta: number): void { // 更新玩家 this.playerCtrl.update(time, delta); // 更新怪物 - // this.monsterCtrl.update(time, delta); + this.monsterCtrl.update(time, delta); // 刷新 HP 文本 this.playerHpText.setText(`PLAYER HP: ${this.playerSprite.hp}`); - // this.monsterHpText.setText(`MONSTER HP: ${this.monsterSprite.hp}`); + this.monsterHpText.setText(`MONSTER HP: ${this.monsterSprite.hp}`); // 如果你需要碰撞检测(攻击命中等),可以在这里 - // this.checkAttackCollision(time); + this.checkAttackCollision(); } // 示例:如果要做攻击命中检测,就这么写 - /* - private checkAttackCollision(time: number) { - // e.g. use distance or overlap to see if monster is hit - // If (playerCtrl is attacking && distance < 50) => monsterSprite.hp -= 10 - // ... + + private checkAttackCollision(): void { + // 如果玩家正在攻击 + const attackStates = [CharState.Attack1, CharState.Attack2, CharState.Attack3, CharState.DashAttack]; + if (attackStates.includes(this.playerCtrl.state)) { + // 使用 Phaser 的 overlap 检测两个精灵的重叠 + if (this.physics.overlap(this.playerSprite, this.monsterSprite)) { + // 命中:减少对手 HP(这里仅示例减少 10 点) + this.monsterSprite.hp -= 10; + console.log('Hit! Monster HP:', this.monsterSprite.hp); + // 你可以在这里添加其他效果,如播放受击动画、生成粒子特效等 + } + } } - */ + } // Phaser 游戏配置 diff --git a/gamefi/app/components/controllers/AI/AIController.ts b/gamefi/app/components/controllers/AI/AIController.ts new file mode 100644 index 0000000..4c44d50 --- /dev/null +++ b/gamefi/app/components/controllers/AI/AIController.ts @@ -0,0 +1,194 @@ +// AIController.ts +import Phaser from 'phaser'; +import { BaseController } from '../BaseController'; +import { AIInput } from './AIInput'; +import { CharState } from '../CharState'; +import { BehaviorManager } from './BehaviorManager'; + +export class AIController extends BaseController { + // AI 专用:虚拟输入 + public aiInput: AIInput = { left: false, right: false, up: false, attack: false, slide: false }; + // AI 难度级别(1: 低,2: 中,3: 高) + public difficultyLevel: number = 1; + + // 跳跃冷却(避免连续跳跃) + public lastJumpTime: number = 0; + public jumpCooldown: number = 500; // 毫秒 + + // 决策更新间隔与反应延迟 + private lastDecisionTime: number = 0; + private decisionInterval: number = 150; // 每 150ms 更新一次决策 + private reactionDelay: number = 0; // 随机反应延迟(毫秒) + private lastReactionTime: number = 0; + + // 动作锁定,确保一旦决策执行后在一段时间内不更改 + private actionLockUntil: number = 0; + private defaultActionLock: number = 300; // 300ms 内不再更新动作 + + constructor( + scene: Phaser.Scene, + x: number, + y: number, + texture: string, + config?: any + ) { + super(scene, x, y, texture, config); + this.difficultyLevel = this.calculateDifficulty(); + } + + private calculateDifficulty(): number { + const winCount = window['playerWinCount'] || 0; + if (winCount < 3) return 1; + if (winCount < 6) return 2; + return 3; + } + + /** + * 更新 AI 决策,生成虚拟输入(AIInput) + * 采用 Utility 模型,根据双方距离、玩家行为数据、AI 难度及历史决策惯性, + * 在每个决策周期内更新一次输入,并锁定该决策一段时间,防止频繁切换。 + */ + public updateAIDecision(time: number): void { + // 如果当前处于动作锁定期,则不更新决策 + if (time < this.actionLockUntil) { + return; + } + // 只在决策间隔到期后更新 + if (time - this.lastDecisionTime < this.decisionInterval) { + return; + } + this.lastDecisionTime = time; + + // 模拟反应延迟 + if (time - this.lastReactionTime < this.reactionDelay) { + return; + } + // 每次更新决策时,设置一个随机反应延迟(50-150ms) + this.reactionDelay = 50 + Math.random() * 100; + this.lastReactionTime = time; + + // 获取玩家精灵(全局存储,或从 GameManager 中获取) + const playerSprite: Phaser.Physics.Arcade.Sprite = window['playerSprite']; + let distance = 300; + if (playerSprite) { + distance = Math.abs(this.sprite.x - playerSprite.x); + } + + // 获取玩家行为统计数据 + const profile = BehaviorManager.getInstance().profile; + + // 计算各动作基础效用(示例逻辑) + let attackUtility = 0; + let defendUtility = 0; + let jumpUtility = 0; + let dashUtility = 0; + let chaseUtility = 0; + + if (distance < 100) { + attackUtility = 1.0; + defendUtility = 0.5; + jumpUtility = 0.2; + dashUtility = 0.3; + chaseUtility = 0.1; + } else if (distance < 300) { + attackUtility = 0.7; + defendUtility = 0.4; + jumpUtility = 0.3; + dashUtility = 0.4; + chaseUtility = 0.6; + } else { + attackUtility = 0.3; + defendUtility = 0.2; + jumpUtility = 0.4; + dashUtility = 0.5; + chaseUtility = 1.0; + } + + // 根据玩家行为微调:如果玩家频繁使用 dashAttack,则提高防御效用 + if (profile.dashAttackCount / (profile.normalAttackCount + 1) > 0.5) { + defendUtility += 0.3; + } + + // 难度放大:难度越高攻击和追击效用越高 + attackUtility *= this.difficultyLevel; + chaseUtility *= this.difficultyLevel; + + // 加入一定惯性:如果上次决策保持同一移动方向,则增加追击效用 + if (this.aiInput.left || this.aiInput.right) { + chaseUtility += 0.2; + } + + // 加权随机选择动作 + const totalUtility = attackUtility + defendUtility + jumpUtility + dashUtility + chaseUtility; + const rand = Math.random() * totalUtility; + let selectedAction: 'attack' | 'defend' | 'jump' | 'dash' | 'chase' = 'attack'; + if (rand < attackUtility) { + selectedAction = 'attack'; + } else if (rand < attackUtility + defendUtility) { + selectedAction = 'defend'; + } else if (rand < attackUtility + defendUtility + jumpUtility) { + selectedAction = 'jump'; + } else if (rand < attackUtility + defendUtility + jumpUtility + dashUtility) { + selectedAction = 'dash'; + } else { + selectedAction = 'chase'; + } + + // 清空虚拟输入 + this.aiInput = { left: false, right: false, up: false, attack: false, slide: false }; + + // 根据选定的动作设置虚拟输入 + switch (selectedAction) { + case 'attack': + this.aiInput.attack = true; + break; + case 'defend': + // 用 slide 表示防御或闪避 + this.aiInput.slide = true; + break; + case 'jump': + if (time - this.lastJumpTime >= this.jumpCooldown) { + this.aiInput.up = true; + this.lastJumpTime = time; + } + break; + case 'dash': + if (playerSprite) { + this.aiInput.left = this.sprite.x > playerSprite.x; + this.aiInput.right = this.sprite.x < playerSprite.x; + } else { + this.aiInput.left = Math.random() < 0.5; + this.aiInput.right = !this.aiInput.left; + } + break; + case 'chase': + if (playerSprite) { + this.aiInput.left = this.sprite.x > playerSprite.x; + this.aiInput.right = this.sprite.x < playerSprite.x; + } + break; + } + + // 锁定当前动作一段时间,确保动作连贯 + this.actionLockUntil = time + this.defaultActionLock; + + if (this.debug) { + console.debug('AI selected action:', selectedAction, 'with utilities:', { + attackUtility, + defendUtility, + jumpUtility, + dashUtility, + chaseUtility, + }); + console.debug('AI Input:', this.aiInput); + } + } + + public update(time: number, delta: number): void { + this.updateAIDecision(time); + super.update(time, delta); + this.movement.handleMovementInput(time); + this.jump.handleJumpInput(time); + this.attack.handleAttackInput(); + } +} diff --git a/gamefi/app/components/controllers/AI/AIInput.ts b/gamefi/app/components/controllers/AI/AIInput.ts new file mode 100644 index 0000000..c59cdf9 --- /dev/null +++ b/gamefi/app/components/controllers/AI/AIInput.ts @@ -0,0 +1,9 @@ +// AIInput.ts +export interface AIInput { + left: boolean; + right: boolean; + up: boolean; + attack: boolean; + slide: boolean; + } + \ No newline at end of file diff --git a/gamefi/app/components/controllers/AI/BehaviorManager.ts b/gamefi/app/components/controllers/AI/BehaviorManager.ts new file mode 100644 index 0000000..e7e23ef --- /dev/null +++ b/gamefi/app/components/controllers/AI/BehaviorManager.ts @@ -0,0 +1,41 @@ +// BehaviorManager.ts +import { PlayerBehaviorProfile } from '../Player/PlayerBehaviorProfile'; + +export class BehaviorManager { + private static instance: BehaviorManager; + public profile: PlayerBehaviorProfile; + + private constructor() { + // 初始化玩家行为数据 + this.profile = { + normalAttackCount: 0, + dashAttackCount: 0, + jumpCount: 0, + slideCount: 0 + }; + } + + public static getInstance(): BehaviorManager { + if (!BehaviorManager.instance) { + BehaviorManager.instance = new BehaviorManager(); + } + return BehaviorManager.instance; + } + + // 示例接口:记录一次普通攻击 + public recordNormalAttack(): void { + this.profile.normalAttackCount++; + } + + public recordDashAttack(): void { + this.profile.dashAttackCount++; + } + + public recordJump(): void { + this.profile.jumpCount++; + } + + public recordSlide(): void { + this.profile.slideCount++; + } +} diff --git a/gamefi/app/components/controllers/AIController.ts b/gamefi/app/components/controllers/AIController.ts deleted file mode 100644 index e69de29..0000000 diff --git a/gamefi/app/components/controllers/BaseController.ts b/gamefi/app/components/controllers/BaseController.ts index e69de29..27978fb 100644 --- a/gamefi/app/components/controllers/BaseController.ts +++ b/gamefi/app/components/controllers/BaseController.ts @@ -0,0 +1,159 @@ +// BaseController.ts +import Phaser from 'phaser'; +import { CharState } from './CharState'; +import { PlayerConfig } from './PlayerController'; +import { PlayerStateManager } from './PlayerStateManager'; +import { PlayerAnimationManager } from './PlayerAnimationManager'; +import { PlayerMovement } from './PlayerMovement'; +import { PlayerJump } from './PlayerJump'; +import { PlayerAttack } from './PlayerAttack'; + +export abstract class BaseController { + public sprite: Phaser.Physics.Arcade.Sprite; + public hp: number; + public isDead: boolean = false; + public isInvincible: boolean = false; + + public state: CharState = CharState.Idle; + public scene: Phaser.Scene; + public animPrefix: string; + public debug: boolean; + + // 速度与物理参数 + public runSpeed: number; + public dashSpeed: number; + public slideSpeed: number; + public jumpVelocity: number; + public dashDuration: number; + public doubleTapThreshold: number; + public slideDuration: number; + public slideCooldown: number; + public slideInvincibleDuration: number; + public dashAttackInitialSpeed: number; + public dashAttackDeceleration: number; + + // 定时器变量 + public dashEndTime: number = 0; + public slideEndTime: number = 0; + public lastSlideTime: number = 0; + + // 跳跃相关 + public doubleJumpUsed: boolean = false; + public coyoteTime: number; + public jumpCutMultiplier: number; + public lastGroundedTime: number = 0; + public runStartTime: number = 0; + public isAirRun: boolean = false; + public airRunEligible: boolean = false; + public airRunEligibleTime: number = 0; + + // 输入相关(将输入属性声明为可选) + public cursors?: Phaser.Types.Input.Keyboard.CursorKeys; + public attackKey?: Phaser.Input.Keyboard.Key; + public blockKey?: Phaser.Input.Keyboard.Key; + public slideKey?: Phaser.Input.Keyboard.Key; + public lastDirection: 'left' | 'right' = 'right'; + public lastTap: { left: number; right: number } = { left: 0, right: 0 }; + + // 攻击连击系统 + public nextAttackRequested: boolean = false; + public attackComboStep: number = 0; + public normalAttackAnimations: string[]; + public dashAttackAnimation: string; + + // 状态与动画管理模块 + public stateManager: PlayerStateManager; + public animationManager: PlayerAnimationManager; + + // 公共子模块:移动、跳跃、攻击 + public movement!: PlayerMovement; + public jump!: PlayerJump; + public attack!: PlayerAttack; + + // 输入缓冲(用于存储命令,在当前动作结束后执行) + public bufferedAction: (() => void) | null = null; + + constructor( + scene: Phaser.Scene, + x: number, + y: number, + texture: string, + config?: PlayerConfig + ) { + this.scene = scene; + this.animPrefix = config?.animPrefix ?? 'hero'; + this.hp = config?.hp ?? 100; + this.debug = config?.debug ?? false; + + // 初始化物理参数 + this.runSpeed = config?.runSpeed ?? 150; + this.dashSpeed = config?.dashSpeed ?? 120; + this.slideSpeed = config?.slideSpeed ?? 300; + this.jumpVelocity = config?.jumpVelocity ?? -500; + this.dashDuration = config?.dashDuration ?? 250; + this.doubleTapThreshold = config?.doubleTapThreshold ?? 300; + this.slideDuration = config?.slideDuration ?? 500; + this.slideCooldown = config?.slideCooldown ?? 2000; + this.slideInvincibleDuration = config?.slideInvincibleDuration ?? 300; + this.coyoteTime = config?.coyoteTime ?? 150; + this.jumpCutMultiplier = config?.jumpCutMultiplier ?? 0.9; + this.dashAttackInitialSpeed = config?.dashAttackInitialSpeed ?? 700; + this.dashAttackDeceleration = config?.dashAttackDeceleration ?? 0.95; + + this.lastGroundedTime = 0; + + // 创建精灵并设置属性 + this.sprite = scene.physics.add.sprite(x, y, texture); + this.sprite.setCollideWorldBounds(true); + const scaleFactor = config?.scaleFactor ?? 2; + this.sprite.setScale(scaleFactor); + + // 设置攻击动画键 + this.normalAttackAnimations = [ + `${this.animPrefix}-attack1`, + `${this.animPrefix}-attack2`, + `${this.animPrefix}-attack3` + ]; + this.dashAttackAnimation = `${this.animPrefix}-dash_attack`; + + // 初始化状态与动画管理模块 + this.animationManager = new PlayerAnimationManager(this); + this.stateManager = new PlayerStateManager(this, this.animationManager); + this.movement = new PlayerMovement(this); + this.jump = new PlayerJump(this); + this.attack = new PlayerAttack(this); + } + + public update(time: number, delta: number): void { + if (this.bufferedAction) { + const action = this.bufferedAction; + this.bufferedAction = null; + action(); + } + } + + public playAnimationIfNotPlaying(animKey: string): void { + if (this.sprite.anims.currentAnim && this.sprite.anims.currentAnim.key === animKey) return; + this.sprite.play(animKey, true); + if (this.debug) { + console.debug(`Playing animation: ${animKey}`); + } + } + + public isJumping(): boolean { + return ( + this.state === CharState.Jump || + this.state === CharState.UpToFall || + this.state === CharState.Fall || + this.state === CharState.AirRun + ); + } + public isAttacking(): boolean { + return ( + this.state === CharState.Attack1 || + this.state === CharState.Attack2 || + this.state === CharState.Attack3 || + this.state === CharState.DashAttack + ); +} +} diff --git a/gamefi/app/components/controllers/Player/PlayerBehaviorProfile.ts b/gamefi/app/components/controllers/Player/PlayerBehaviorProfile.ts new file mode 100644 index 0000000..818422c --- /dev/null +++ b/gamefi/app/components/controllers/Player/PlayerBehaviorProfile.ts @@ -0,0 +1,8 @@ +// PlayerBehaviorProfile.ts +export interface PlayerBehaviorProfile { + normalAttackCount: number; + dashAttackCount: number; + jumpCount: number; + slideCount: number; + } + \ No newline at end of file diff --git a/gamefi/app/components/controllers/Player/PlayerController.ts b/gamefi/app/components/controllers/Player/PlayerController.ts new file mode 100644 index 0000000..1be6d18 --- /dev/null +++ b/gamefi/app/components/controllers/Player/PlayerController.ts @@ -0,0 +1,50 @@ +// PlayerController.ts +import Phaser from 'phaser'; +import { BaseController } from '../BaseController'; +import { CharState } from '../CharState'; +import { PlayerMovement } from '../PlayerMovement'; +import { PlayerJump } from '../PlayerJump'; +import { PlayerAttack } from '../PlayerAttack'; + +export class PlayerController extends BaseController { + public cursors: Phaser.Types.Input.Keyboard.CursorKeys; + public attackKey: Phaser.Input.Keyboard.Key; + public blockKey: Phaser.Input.Keyboard.Key; + public slideKey: Phaser.Input.Keyboard.Key; + + constructor( + scene: Phaser.Scene, + x: number, + y: number, + texture: string, + config?: any + ) { + super(scene, x, y, texture, config); + + // 初始化玩家专用输入 + this.cursors = scene.input.keyboard!.createCursorKeys(); + this.attackKey = scene.input.keyboard!.addKey(Phaser.Input.Keyboard.KeyCodes.F); + this.blockKey = scene.input.keyboard!.addKey(Phaser.Input.Keyboard.KeyCodes.D); + this.slideKey = scene.input.keyboard!.addKey(Phaser.Input.Keyboard.KeyCodes.SHIFT); + + // 初始化玩家的子模块:移动、跳跃、攻击 + this.movement = new PlayerMovement(this); + this.jump = new PlayerJump(this); + this.attack = new PlayerAttack(this); + } + + public update(time: number, delta: number): void { + // 执行基础更新(例如缓冲动作处理) + super.update(time, delta); + + // 调用各模块处理玩家输入 + this.movement.handleMovementInput(time); + this.jump.handleJumpInput(time); + this.attack.handleAttackInput(); + } + + + + + +} diff --git a/gamefi/app/components/controllers/PlayerAnimationManager.ts b/gamefi/app/components/controllers/PlayerAnimationManager.ts index ad8d384..a2656f8 100644 --- a/gamefi/app/components/controllers/PlayerAnimationManager.ts +++ b/gamefi/app/components/controllers/PlayerAnimationManager.ts @@ -1,11 +1,11 @@ // PlayerAnimationManager.ts import { PlayerController } from "./PlayerController"; import { CharState } from "./CharState"; - +import { BaseController } from "./BaseController"; export class PlayerAnimationManager { - private controller: PlayerController; + private controller: PlayerController | BaseController; - constructor(controller: PlayerController) { + constructor(controller: PlayerController | BaseController) { this.controller = controller; } /** diff --git a/gamefi/app/components/controllers/PlayerAttack.ts b/gamefi/app/components/controllers/PlayerAttack.ts index 725638f..a97587a 100644 --- a/gamefi/app/components/controllers/PlayerAttack.ts +++ b/gamefi/app/components/controllers/PlayerAttack.ts @@ -2,6 +2,7 @@ import Phaser from 'phaser'; import { PlayerController } from './PlayerController'; import { CharState } from './CharState'; +import { BaseController } from './BaseController'; /** * handle player attack input @@ -11,15 +12,22 @@ import { CharState } from './CharState'; */ export class PlayerAttack { - private controller: PlayerController; + private controller: PlayerController | BaseController; private attackBufferThreshold: number = 0.5; - constructor(controller: PlayerController) { + constructor(controller: BaseController) { this.controller = controller; } - + private getAttackInput(): boolean { + if ((this.controller as any).aiInput !== undefined) { + return (this.controller as any).aiInput.attack; + } + // 现在 BaseController 定义了 attackKey(可选),我们使用断言来确保它存在 + return Phaser.Input.Keyboard.JustDown(this.controller.attackKey!); + } + public handleAttackInput(): void { - if (Phaser.Input.Keyboard.JustDown(this.controller.attackKey)) { + if (this.getAttackInput()) { // if in the state of Run or Dash, dash attack will be triggered if ( diff --git a/gamefi/app/components/controllers/PlayerController.ts b/gamefi/app/components/controllers/PlayerController.ts index 369b269..643c479 100644 --- a/gamefi/app/components/controllers/PlayerController.ts +++ b/gamefi/app/components/controllers/PlayerController.ts @@ -86,7 +86,7 @@ export class PlayerController { public dashAttackInitialSpeed: number; public dashAttackDeceleration: number; - private dashAttackAnimation: string; + public dashAttackAnimation: string; // 子模块 public movement: PlayerMovement; @@ -145,7 +145,7 @@ export class PlayerController { this.attackKey = scene.input.keyboard!.addKey(Phaser.Input.Keyboard.KeyCodes.F); this.blockKey = scene.input.keyboard!.addKey(Phaser.Input.Keyboard.KeyCodes.D); this.slideKey = scene.input.keyboard!.addKey(Phaser.Input.Keyboard.KeyCodes.SHIFT); - + // 设置攻击动画(连击)和 dash 攻击动画 this.normalAttackAnimations = [ `${this.animPrefix}-attack1`, @@ -219,11 +219,12 @@ export class PlayerController { else if (anim.key === `${this.animPrefix}-slide` && this.state === CharState.Slide) { this.stateManager.changeState(CharState.Idle); } + // 对于 up_to_fall,交由 update() 检测动画进度转换到 Fall 状态 if (this.bufferedAction) { const action = this.bufferedAction; this.bufferedAction = null; action(); - } + } } ); } diff --git a/gamefi/app/components/controllers/PlayerJump.ts b/gamefi/app/components/controllers/PlayerJump.ts index ec1c540..a06a572 100644 --- a/gamefi/app/components/controllers/PlayerJump.ts +++ b/gamefi/app/components/controllers/PlayerJump.ts @@ -2,6 +2,7 @@ import Phaser from 'phaser'; import { PlayerController } from './PlayerController'; import { CharState } from './CharState'; +import { BaseController } from './BaseController'; /** * Handle player jump input (including jump and double jump), @@ -9,15 +10,24 @@ import { CharState } from './CharState'; * then jumping will trigger an AirRun state. */ export class PlayerJump { - private controller: PlayerController; + private controller: PlayerController |BaseController; - constructor(controller: PlayerController) { + constructor(controller: PlayerController | BaseController) { this.controller = controller; } + private getJumpInput(): boolean { + // 如果存在 aiInput,则直接返回 aiInput.up(假设 AI 在需要触发跳跃时只给 true 一帧) + if ((this.controller as any).aiInput !== undefined) { + return (this.controller as any).aiInput.up; + } + return Phaser.Input.Keyboard.JustDown(this.controller.cursors!.up!); + } + + public handleJumpInput(time: number): void { // Detect jump key press - if (Phaser.Input.Keyboard.JustDown(this.controller.cursors.up!)) { + if (this.getJumpInput()) { // If on the ground or within coyote time (jump buffer) if ( this.controller.sprite.body!.blocked.down || @@ -56,13 +66,18 @@ export class PlayerJump { } this.controller.sprite.setVelocityY(this.controller.jumpVelocity); } + + } // Flexible jump height: if upward velocity and jump key is released, // reduce upward velocity so that jump height depends on how long the key is held + const jumpHeld = (this.controller as any).aiInput + ? (this.controller as any).aiInput.up + : this.controller.cursors?.up?.isDown; if ( this.controller.sprite.body!.velocity.y < 0 && - !this.controller.cursors.up!.isDown + !jumpHeld ) { this.controller.sprite.setVelocityY( this.controller.sprite.body!.velocity.y * this.controller.jumpCutMultiplier diff --git a/gamefi/app/components/controllers/PlayerMovement.ts b/gamefi/app/components/controllers/PlayerMovement.ts index 4a8eb41..3bc107a 100644 --- a/gamefi/app/components/controllers/PlayerMovement.ts +++ b/gamefi/app/components/controllers/PlayerMovement.ts @@ -2,6 +2,7 @@ import Phaser from 'phaser'; import { PlayerController } from './PlayerController'; import { CharState } from './CharState'; +import { BaseController } from './BaseController'; /** * Handle player movement input. @@ -9,9 +10,9 @@ import { CharState } from './CharState'; * transition into Dash state as a running-to-dash transition. */ export class PlayerMovement { - private controller: PlayerController; + private controller: PlayerController | BaseController; - constructor(controller: PlayerController) { + constructor(controller: PlayerController | BaseController) { this.controller = controller; } @@ -20,9 +21,11 @@ export class PlayerMovement { let moving = false; // 判断是否在空中 const isAirborne = !this.controller.sprite.body!.blocked.down; - + const input = (this.controller as any).aiInput || this.controller.cursors; + const leftPressed = typeof input.left === 'boolean' ? input.left : input.left?.isDown; + const rightPressed = typeof input.right === 'boolean' ? input.right : input.right?.isDown; // 检测左右方向键 - if (this.controller.cursors.left?.isDown) { + if (leftPressed) { velocityX = -this.controller.runSpeed; moving = true; this.controller.sprite.setFlipX(true); @@ -31,7 +34,7 @@ export class PlayerMovement { this.controller.stateManager.changeState(CharState.Run); } this.controller.lastDirection = 'left'; - } else if (this.controller.cursors.right?.isDown) { + } else if (rightPressed) { velocityX = this.controller.runSpeed; moving = true; this.controller.sprite.setFlipX(false); diff --git a/gamefi/app/components/controllers/PlayerStateManager.ts b/gamefi/app/components/controllers/PlayerStateManager.ts index d5982c3..44690e9 100644 --- a/gamefi/app/components/controllers/PlayerStateManager.ts +++ b/gamefi/app/components/controllers/PlayerStateManager.ts @@ -2,12 +2,13 @@ import { PlayerController } from "./PlayerController"; import { PlayerAnimationManager } from "./PlayerAnimationManager"; import { CharState } from "./CharState"; +import {BaseController } from "./BaseController"; export class PlayerStateManager { - private controller: PlayerController; + private controller: PlayerController | BaseController; private animationManager: PlayerAnimationManager; - constructor(controller: PlayerController, animationManager: PlayerAnimationManager) { + constructor(controller: PlayerController | BaseController, animationManager: PlayerAnimationManager) { this.controller = controller; this.animationManager = animationManager; } diff --git a/gamefi/app/global.d.ts b/gamefi/app/global.d.ts new file mode 100644 index 0000000..2c7c0a0 --- /dev/null +++ b/gamefi/app/global.d.ts @@ -0,0 +1,15 @@ +interface Ethereum { + request: (args: any) => Promise; + on: (event: string, handler: (...args: any[]) => void) => void; +} + +interface solana { + connect: () => Promise; +} + +interface Window { + ethereum?: Ethereum; + solana?: solana; + playerWinCount?: number; +} + diff --git a/gamefi/global.d.ts b/gamefi/global.d.ts index 22bebb6..35994fb 100644 --- a/gamefi/global.d.ts +++ b/gamefi/global.d.ts @@ -1,8 +1,4 @@ -interface Ethereum { - request: (args: any) => Promise; - on: (event: string, handler: (...args: any[]) => void) => void; - } interface Window { - ethereum?: Ethereum; + playerSprite?: any; } \ No newline at end of file diff --git a/gamefi/public/assets/monster/Idle.png b/gamefi/public/assets/monster/Idle.png deleted file mode 100644 index cf2958471f593f691354d255b7cec28a2bdb0347..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 21408 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 diff --git a/gamefi/public/assets/monster/attack1.png b/gamefi/public/assets/monster/attack1.png deleted file mode 100644 index 752d374f5e530824d67649bafdc229f6a2662214..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 22202 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 M<+kQoOFe%19|Ei4e*gdg diff --git a/gamefi/public/assets/monster/attack2.png b/gamefi/public/assets/monster/attack2.png deleted file mode 100644 index d3ac9e435562f89010c1bac1513c051a9469244a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 21135 zcmeI4cT`hZx4es*vWv7sDyM<3=oPVs0boT5s{P|j6wn-bdUg+QAV*1peTaq zV1@B>P#i_D04geo6h(p908uF-MOxksMXrjI`QA70z4g{g*1EDiXYYN^{hfXG-RJ&s zcQ~wAGH&eju>b&!v$e5y1OO#5B#SlFpnsKrzorTO8RKi?>JI>#6J?hYaOm(hDoYuDjS}P!F)or028^XoKGul52yCr(pm+SjJZ(8&l(TBn6taqn}N*iryj$S#d&}ZU7+bcA{BoqW{zXCXwDAIFsN)~i3$veyx4u1gZcXY{)y|ig zyaM~a1~+>a09bA1Ik|{j?3UBm0v}^0N5BG&gMEA<-T**15B6oUH-RD)3-sdgP4%0v zeu|qepsT_TCv$6DG8sxwS6fsf3KHhwPTCl19 zfL|IU%bGFzr~wtxCR2S2*?=e)I|r1NKnS8p#wKVs4u?aLsm3@Gg@7j+q3~E734^6# za9A`JN5f%hcr0q@r*AeElITJXm*!~w)6j6x|4j8ah(x|L3??Wj$T)~#ED(BOa8xQ4 zgT-U;cr>Je_7CBUn89eizrmoBVL#TOKU>K274Zaol*})aB?u6i>g&q}`urQZFCX8} z1M&Tb*g+IA!AxHa&KQds&4|PPY~vds^d6WRhm8TfK_8GW@`vnjquN18?d(3Ajyjx= z�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 FzX0+4)D!>! diff --git a/gamefi/public/assets/monster/attack3.png b/gamefi/public/assets/monster/attack3.png deleted file mode 100644 index 3a3ac0e8b1ce4083c8a4cf2a6475657f91355c1b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 21826 zcmeI4c~nzZx4>@z859%*W%yJgDgqiZlYuD+s8kRHt)LRga08JckT44*;w+9uD+Liy zi?%ALI3dWO$RH?M2T&$UDWHH1f`CBsZa@@MOxxG*y|=!%lC^S^bN1c)obx;T?6c4P zcs`s!xPz@NJdn#_vHd^*2!DC;;N@@bx@b`<<4!fYEKvvw439T5y8gzi z_zc2c{lc^PWzWx~eZ!tfr9O+* z2spYEZbA_)JF8cugW4YRvrR25oy@MHSO7m#-y$i-r6X!a##QfZq5xK9Ulghtz?Mc& zL4^eW1l!_3cJ;pPhB*H{=#Z17aKvIBNY-O=t*2`qGyM7VY16|Zr2=|hbpV-raf`>+ zwqa~WOL=YmA$5U!XV{+)AX}Eu&m_A@(9Ue$y_=3T3I_S*~ur%n* z$v1$rnU)6Y@lGhGKwHp4-C=vpTT8lCx<1l0lZV3uYMxiDc z8M{-$h7+`in6zNpxD~9}3JSLtO(0{4WSrSVD_`6zX@|pPvm*YImCtuhu)$=ISsboE zE!c|fPxA(mfdSqY$j_A%?i}@AvO@qbm=?eQ9qg>23R55`u)s;1NU|NTSota3qjG9B*P0Gk<7mC7TENUBm=`guHSz*tvm0U)GKb z{Me&GE0D(Jf#Nl7X)wO1KSjAuK}@VO8XL$ohB(|=F~p7zGA)o_)PC;PC(Vy)>_1ND zUqdive}ekg+X(Xk1EejKF;k;=eccF;!wL?gaX}kz$V2|h8XmLyrJAI93#52^@MHfE zOazY>`p>2ThoLc9G!_POcF5x)=Z2ge#Nna+lLXZeh@cq?T2=pS8t_oa`V_DJ@226i z7c+cl0p1|f3OPQq@rwVXnPXtl7?6RdBUm^F1A)Wha0n6(itc7iI+H=dqd^pdH9o$- zwSd01N62RGWANhygo50^6aJteOM}u`kjt}TaXJ2QT410bn?VzYQe z**4IzL7WZqCiGFf^@|;38O{64+HnDtoK1chK+{klorR+z2zV@7JXK5t4G&Ek5sxM@ z@kBZcLj?aUzx#@5435>b%<;~<^{IvQbyMiJ2{1_{d|;3x0dSnZcHIMF|( z&A)~Cs85DYQczYuy6sw_Es%exo8VTXGI#Nb$S-8{#6!TKpbzw93Hp3gohX)6^^mSQ zQ7ozYS#wCe`%#tck`ze)?H+g5;y-*wjsUUN*W2$7-RcanOT600YrLH zhD$mh38@U11Q6*(87}F3B&0H25vl;M)jM?xyYB>_ZwQHD!8 z9|@@pmjn>$MHw#Xd?chYToOQ}7iGAl^O2Csa7h4>UX3k%lGF%csq!(qlr1O!G%5X^lkzSPHlFmm$D#IlKM0!z%OFAD3sSK9{ z5a~r3F6n$Eq%vF*K%^ICxTN!ukjijL0Fhpl;gZfrLMp>00YrLHDz2%Y->m@#Krhq? zgWjAG_2`@)Rm*Hns~g?1OJr);+$pH_Xzgsy{ViKWtzXqi zYIz5nU)eOJCnkSrD2AWUdz-Dev?mJPU0!u_SD6wZ@PEH!xI`@Q)wkaI?#&O5l?Tf35r#<( zZ{wRv9#*lGZeHs%nU613>VW~v3>}^XCe7(+w<|Il9z3J3TJ~xuKJ8Wfj3#-Aw*{it zpeH@6=3F0jU*2JHogF1`6+pf<>&VM{^X_QzAq((8`P6$Smx+ZGbYbn3S0?YD@EF(l zhi+@m8Eql~z|BFt-_V*r9O>CqvZd3>TIZCTs;XF3PW}?ql^6Bx*Xrj3>+Z##(x2XB zTU&jD!!=)AP@`}|A(hdPd&km}VE9_e*3L=}2G?&qXnEG6SflM!mHJ*-^~=a(s#N#* z{E-l1zjt~|aZ`C_74M!`*PRU=t2IiM2Kwv;Zu8KQI=4S4TvMWy(a?~$uL!))h^iC%GWshpku{lp9~Ku6Duk#Xj`$_1^gWxi zq5Xm9uh8JQ(S1j9-#z5io4~cAdbUM%5uTsu(FxuEU|=bcw7`Fn#X!Z>cpp{z#dD-hf5o6*fjSL~mM&Txhh zhtk3=A9_A~&O@plC_iuj9Nf~gVDPSfRnu;QwKea})u`vfgLd=vOO*~4K_g_~A}dYu zD{F@eug$p$yEN_Y)yuH<^JRzZ?3%LPhxI&bTET5@bch(NaYFEmKmSDKvEU%IPc zXKa)*GF{nv`HWkOTX(}=%&q?+Zt6;%yvzwFmctP=?>W+aG z{{FYWsqoqic~|Aj291uD^Y!K0H|-z!SERZ3TpNIYfJ(@|)3Gf;?1HcT;kVdL48W2w9at`iQeJ$}03sFtSo2pRN3~!&Dksn6x6N?<)a+#14_(LS_A2ODs!|jjjxKZ{ zLxbG2$MHc!$3Wifm|M5Q_e~vC--XJ}TO4(INwCc4Y|_)KoW4_TKlLddy`u)W=HpDw zP8``h6j#}RfsyO|lZi{T1_z4xJ@?nK`P~sLb$h#vOe+Iz3p~*5yE;O(rqy^(%L9c1 zkLvPEgb2@ox#=}=>JN^!?b2}31Y$yVUDthev;>uX`Ess5Q12+WsZs19FB?PzY-H8? zd1VJUs7RZC2~4y)x=!YDXDv{7=uh!hc&a*+Z*6WT9v!}{^~KQsqlVA5Gu0@^-io+w zm#(fpaSR&Hs+?tZK!G)NT47?s=|-%!bF&_QWM0c%M(>CD@14J;HVOTn^e(DSM#Zns zz`Wc!J^tq4tIK{?;q4WgJO}0BH|m~eEzB;LJAb$E!O)6@=XEW4B+7%@O3^^hllIsB zk722tQz*;zA(LO`0*U{MBXKY&XI4y;(1AWg4q)FPRRO!yIA2 zFjnsUE;Jry8dQCeH?Jag^TO#*lY0is9 zk$FxI!8f-~M@hL{XJ%XYqsy1{w$)j+*xYL@yC3&WV`|-e!_Y-hN;Lov)$yjVi;VtWrr(~(7L>I(I zTudsbu%fHWu2Jm=I^G_Ryuz!9H}`DhAeC~y-~FzFGPk=w+0u&I1p11gw>!O@mb$p; zMWa`!GFZ09qpMQuoU%{MQKy*i7CJnraaiBkz;bPBkD42de{oWs8O>1Fr%uJ{Eb z2L_vtozEs;x{6w2@XMNp2Lm;%)QkbnMbQqJ&o}*>S#tMp@vC}M+bz>kPd&Y3>rU4g z3rGPwnq8kyx%I~0bAijcffQ^1^3pD!lA+LBDhCq3(|>o$y{(VRQh2#Jit2kh#dw%3 z)YqNY_p@#&%mP`Ki%#f{oN-|zZ4cn2PfC}Q41oxT4avUO9KJoi@wMX@Qq0m%1rKaa4M2uN<}=%I)6~6SV&Ihx2-{tnE9x(t#~n>e2jr`BlkY zH+;_C)O<{78nRte!I;VKRHabUGF;UwP8-CT4X=IuHXE^cQ;<c$%>RoAMrEf2?;U)W@9u3eCKe#gxrjo(b-@BHjr zuyuDs*uL$?A4V#sr31e&&)kSj?Gx4Y8=ltUXQ~Q(cgJ|Pw9wz&Rna(7o1FTJ04jD~ zQ?8)*T68LQ_>P=AQJySU?dkPcndm%FcA!}&|HqvkKVfEF`V9(ME+rQm(T&d(3To3f zU%Pu_XT9RDGm>&|YL8S@^v7w1SC(O6_69D$Uq|+w(%n_L|EENvhOy-hu2|(@HC)#Ay~wQQ<)$qR=d_dc*daB8XA9c4 zS*x3ckmZhaU<(WNdm1-h_iK$CU|8)Vh+cavWmR-EKb*bwmIzRztXY#um%D#bQK@^M z%D^^b#q02=9l-11kz|E)>_?*Vn!!p1L2N_c3%OT^U>6p&>)7yb75*ISh1B>^4=X;J zvMxttvA`>78-|XFkxyH=@?=(4iZT&nk+>B~j@<--Id=}e)raljnxv+u`Mq8|TXE%q zhq0M;`YGRpy8%Gf(C)w-egQzt;cL*Q3RFr#HtqY`uGAzfVM}6=W#n+}LDk$Db=Ku> zb*Jm{E4w=v)px?qZ6&(YYu>7!rk?InZ5|speYeKzC_r`R>{Q*}Egl)|6{6}rbj{Qk zBTL9rP!F~bYN7V=iH4MWxveeBcdf``Y%a8RWSn&qsAo2~6GSjYxOPWJ%Q@F0MWNpg;Dx5~`C$Xm$l}61)?R>#9xOfp8Sp(!FsI9RYU-+R z?Ag`c)>)CF>(Ex%_n~vYrP5H)#tdZf40#tWP3u5N1(0*{g}-R2r`HKLpz$r=u_Lpy zHg~bN>B%N}IpxQ|T8}5_dkwX!#T!r*cf$fR1;}8zI8JR5W>mG^LWhaWqZKR^tYAiM ztvL~gUZ`Q@6ubB)E`8Ap?w;P%sdn&3y=~OFKoLf;Tagl<_OP|#*?iQLJ=&(jH`C>U zMM5l;+&DhqQPyYbcD<%Qy3AkK-ML%`zNrE{ZE`tAc=f^V*V9-Iylv)U{P}pCQ~XbZIWIh>U)1y-+EB&V zs9615x&4NwUvz$7Mrhppe57-3%;qyq!^#4x%G{J?-QIT@FBc>M2{7c$0kW^C76#Zi zSt4fM!N%g$gu2^ebbd^D=apKf-4TCG`^RlB%Zja)Q*IR>@wNqu)=zV!Z&37Unkg_A zYF-TT*yQGkbF_7X%A|pag)|>0E((2qZM}g{3=c zBX1f(J9}nteR8lUL4Yc1IH8wpjXC1kZm)d{A#8$q!VfEkb8wxcW#-0n)G4U#L(po1X>rZ;?-l z$h%4xQnxxP#GGnIcMh~zbgxgN4BwpzT%7;Dk9uP-z~`kJ30bFgSIt|x~N+?FnxzN-?L~AQ7E!F7&ZTGk@fpIK2H@Wb2pqE$T<;} z8JqsEVk0?PurPE^hp}KE{|H-f=`v$RP>FT1Z+_4!VBPjdZC=nA=R?*HHmbS|`)hjf zFD6ZaLFZkKw0olGcki|14dI*GZ@!7qr0aKHn^9!_t==^yuPRY^3C%W9C+>WC^ba_S zi0(n4W(;T!g=a>8FK9eqy$U#-HaE?1s(oSp!;{svo+mHl!kg7+iSz+o%do5u24X<{%Z2% zA8LZG93aiGJbGus^}7f5eJ1&zfPgy*>(ZB*T1VyPU7s)a>A-1SSJqToPFTB^u;+Q% z<;RLk|0;<%2ycZgL+?nrx0>TQ?LQ9lgNlcqx-C639IBd_+;-{dG+brOubIvkomb+w zPqmn%u9t32B2IPHetK~1k2aLG35VUvj54^Ad#*g_yMPyD*D2RD7L%vkYjTT+#6`{V zlqV4V+A0%DgzAvd3NNm2aE>48$Tx^r_D=klJX?f2R-|wlKI-d_52vR)Zqb_N2`-jM zxr$>emc-R|&@-RjD0`4%srHZkWT_i_!PAPV|J+^iwCYOqnBg)w*7tPzv~%~>Nwxcr zE!ua%q_vuycV(XD+0uCe2y#!7Ebv$Pd(YttW#NvnNG3oWqr>HZHw5uqqUEqK6j2cc zNU%gY-M%3^*PbX5O}Agn^rm>r-H{NFg8@k5!t)&&3MsV;2<1P!NlnB zFsYIoJ>9;`FBkmQiOKfFt|qF`>Gp2A4vGHWK16q!0wFRTok&6|l}coB9H~q;oyPox zNTX1hWD18&rI098E|tQiQHVX4J>Lxc;weO8uCIq@Pj}#d)9pi4Dmj--j*5zMjG{Zr z6v1RFhr=OLXk;3V1X_@kF;W#AO_C}dx}Eg;@j#S9g+#8B$fQJ_UsxcEP))bD*LBo) z^~@_=-q(>-*~1P{BuB$?GS!hn9?VE2?6Z+aD8jmiCK8g7FeDt2s+7QvI;b5$>h0ZU zI%s#{;e%Q#RWl;N40?zRYN=chBS*--h*B1z5F#@o!AKki8@y8Gi}b^N4_Bc1ppN9d zJ9hAK^{L;9Q6&+-V<0-sJI#=2$vez+nr^eMnCf0?9-z*3S0J!TrdS}8h4H(?wLjm0 zbfXJT;^f5=sYn*3oWdgyH0ckVes72etU~xS3W!AtheW3=pg3_EG%k%XjY8*AD0)u1 zTMqEy4K|SoR>8eq=sGVH#sVsfOQ&$@G<`2`wH@e3CX$F_-pfmWOFbVVAy+I@gu^Pn zBpeP#$Z}~gkK8ZRYuOdOTra6o1xtm9mj@pR93>JFSHz;SgjAY{L}fGSB$klDA+ecE zHc7}9QaMzHfB}m{T{yhG_03VPJ!HZN-39`#yK{|5CIs&L0*T9EI5{zC91e*gpovLT zDuR&MbSDu>>_kOG3>Jk!p~Af#={ZAnG*2M`sSpm+YonWsNH-T)M5BojAqk-f5E4fK z=E7mpm?Sm>;Rpmy3=YC#_jWOe8&p@bBuWr>F?#U`qOvR5`5`Ocmi8*bBwa~M4l9(1 zZck6Q@7>gWS*|aM>1?`k0~Z$R(j8x@3v>kFeoNXvtUk*gGsz&!`CbUR{p*>(yN{?4 zM2fXhx?Od(dbbm$OstB66^L6fh>-W$!`)urHXG=kN7g+a!X*C-3!#J~|JpJzXs}2O zi)kR(#T*g{ZV>DUg9)CW93Ww_5hsdM?=t_{WnhAo)t9gS|CXUYiiIJtG#C-_$-Oh{ z75q1?9LGt>ri-a`5=RU(NkTezO?0W(cRWhR9W3rpOo{#^-C>0?J z$$yez^hPP{#YFrsoAY1Jsqa^*7SIvmd2~mor*2Q_ z9RnghBbo z5z(Dk457eDs7u|tzVw_8)|c$B7Mb0>4C1E0x88No!>w1!@cQx=*IgDSQ+Ufn2%pX) z4<^?0*{=p~Vtl$^#Pk$gzB4~1P6mf?HaH^<+H6oay=Ar=I5z02VWr*}bpfUekWb;@ zx23%bP@D~Z7@)!wL?C9sBo>oS)h(5X1T(>+v6)nkh{+a+X>8<=>brNirqNj}5sN_~ zF$HwE+cg`ei%1+6L%?P+=xl}v90IUQ$9K3EQ>h%L6DZ?g77Pwdx={;+3^5orM<8@! zido=*@rSN^4=Wron?d0SXe6ef zL~II(e+J;m5>QD_R0^9)5pw8a7IW~CbxYq~LH+o^T7RDIsLur_DNxmSJ$Ct29vLOm z3#%@jzwSg77SVO$VbLhy0&kYU)nlr!9%#A*+f-jY(6rxjp;V&c(|URvAl9?ey^rYL zdVb&?9Kv^EGUfP+>UaG{xCNDR0z;Gk6oTxcd35(6#_ zIB1mt7n%u%#DEI}4q9cvg=T^wG2p_0gH{=Ep_yPv47f1hpj8H3XeJmE11=0WXq5pM znhA!)fC~c-T4lh6W`ZFx;KG1|RvB=inP5l^xG>rx;35LXg z3j+>XWx$1If*~>B!hnNT8E~PQU`PzOFyNq723%++7!m_63^-_&0T-GHhQxpi0}fhc zz=dXlA;H9D*8gn{L<&Br5e2@S@neXh9(;9!D4gZ%4MDLVf$yKJg`n43aDN6tz68i< zv_AxKw?UA#?A}tlE#Q+VIbI%a3!+Qw$}fdlNyc7n3{3jx^d&djZjq&1QFhh0ROKHc{SX{N06HY*~}26ZSqLn%kys{v`jySU1lP@@J zwm-V|Ie+5jogDwTjk3q}pDm1txOM%&gVy%d>fOoQ>SfIxds+|GydVy9H-b9oc`inf zB^Wjif?UCk0RD`?B)|<11`ck2PWk7oF#G!(Ts~Sf)goz03ivpU{B+xKa*F2+mrffn z=M82THB3KSzv7S^R+=_pBp!;VJ$s|AoD(yr>8rxllpTlfOxv;8ul7c|+1TAF_2Vx+ zdGee3^5w#eyntnQ$MVhdDXPwOX;V_XQb*&T=Qn=8{@`7Y`SK=z|3KR>?y@?!Cr&tF zEPp22W)<<~{HR~X4xMjR#vW2v9#kB1#Zz6F+$=74gV?v8f4gRQA{B?HjSaZx>H1{i zgV_&*hdsL6m`AXDNrX~2B_0d79#Q2-D4W)iI>zXSC2_>nN(Z9y`+GH`y>68q`{wqw z#40*Xad6~`6jLbKRDFKq**mY##5zK5>D~nPIdlA$u)Kn=Dy-C}?R}0cwo2Z%WYvgG zx%Y>*WNm&lx{3&yoin!Cv-H=f#WQ^qGZq~Wd9i33^FuHdoAFlLr{fr*yRE&A;;YM; z5PiswdDnhenzP@zeqo`6(RiM8B=tc0?1pm$|Kc;-Y>aRZ>Y~p&C|4ir7Vy{_}2bdI33i zf1C4(&ZyEOhYDP3IdPL_HJTb#=CSkmhpZ2eTKccK9tGN}@61cvp60%)uS;uA$<=(F zerex$$ia25b8v;lZCjJVtyj655?GV8uPn;bjBBOVDo?d~rn9=uCM1KG5jt&z|H`Xi zg$U~8H9frQzndzm+b{Fqy zvPWbmulFe<2H^?OS;mAl#G^kyxLrT)9`b1(-qmLP>epl1sbvKO%M&%}H|)%0n{rPo zs$*Y;ZpsNZjm;+%^Tc=pF0Zl5E;wIJe3{-B$VpgqHqd3^tq5XM4wwi5ibjg>jN%_@ zo1GfNC#>0GDbH@BZT@ zQIw@^%PdOR^RpcuTJFLtAHAJO#8)~T^mO$q*S@KK8vFY*+iCSNtunh247?6tv{BHo zM|J>awX>R$wyKet4Q} zOk=1~OoJIb2V^ig5uX}~E3;&Ibc?!~ih!j@GP+ltaQC#*ML`=WA2ka~l&y1*{6bbe*F=E9VY zC;R0~EsHhQzXB@U$fU;c0r5A3GmTH&1-t3v2hF66U2W@^*Hyb&&UBk>>(^HANqjI7 z!mHE2zrvLyJ^06m8I{(#ZGLS=DaL!pIpeFcjjliiqqVy#c+R}aR$q{;cJ7p|^_5KC zdZ4iItm)FI3l?gj!z8~b{G_>yhpxuat=CjXDGFrT$6P2OWsS^i)ggveCOPHsg0W_- z3{$Yh(_M*B3$d07f!Wng?u@kA>dBvghw6@e`}_9KzS}3y;C+1PO!+xRDQ&gfXF{b2 zni$^PR918Te(c?mIJuo{*oL)rZwgzTGE65jzgvI$BJXhNosos}oJR2QyM{vTk-4J| z9w`l*K6_YFbZgpZTpg~g%minez`IDU(GXG+6i;&0b9ZHW26|DB`H@GUd zpvcq<)LqNG-EJ)|ZPHBb$WZUJmzu>_B?{BaM-FpKKlbhKCCMkAoxNo5D8A5?*ev*H z@x!ySkvC5{L^lhP?%}QKO4uv2vW~Q_+mu3(SeCJE542bTCN+*=0jd%3g9GEbAbmFfX*>dxei+B819Ev=XItJJDm3LA#VlnU7 z_1EJ;ntE82+cDMaP2266agH4^1)E*UwGa6Z+s`=MRD?a6cowqDZ!S93ay;N@-Q-&_ zo8$IKT?&8tqBcv>aa5X{kX3yi0LVPX+nCk4_m^)b7M7>po~5O?o@%rEX}o$$XU?ui zOOmwSwcjOlK3=>kz9#+0%#@$C^0c<>DJ|v6rde9S7s|*}FC-=vR&n(9d2d8{r+2&G z-FVHhv++fs@2isGMqcwR4|FcOkUQ?$jZjGQ;#HGXVwU#u%HMYu^RHDKZ3wPEl>uch zX^^J9{_<*o3#|p@{5OxtiHn;%On2O~Q)p}(GL2p}d9ccJm;2PcNI9FpjyK8Uzdn_f zTW)0p`ailVUK6)GRJm=N#_@!v^R`QS{>rm2Dq0#!4{{ZcE|(=1B?KC`X(6rof!VmW RDmw^VUNh!;WPTd7=HH6f_1ORb diff --git a/gamefi/public/assets/monster/defend.png b/gamefi/public/assets/monster/defend.png deleted file mode 100644 index 350fc813a7ca7fb4f6ca4bd466d6ebb3bee306ea..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 20159 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 F{{g-I;TQk_ diff --git a/gamefi/public/assets/monster/hurt.png b/gamefi/public/assets/monster/hurt.png deleted file mode 100644 index 02df88566183f0254e01e974c9a999071e36dcd7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 20167 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 diff --git a/gamefi/public/assets/monster/walk.png b/gamefi/public/assets/monster/walk.png deleted file mode 100644 index 3f8246e34dd0e8a341f026c4c3989646ead67c8b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 22814 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 diff --git a/gamefi/public/assets/player/attack1.png b/gamefi/public/assets/player/attack1.png deleted file mode 100644 index 3c0b70d876c1845a1410931d7c5cbf0043a74544..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4107 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 diff --git a/gamefi/public/assets/player/attack2.png b/gamefi/public/assets/player/attack2.png deleted file mode 100644 index 8ba30137370cf642a1aa5f283f3b083b2e2083b8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3048 zcmb_eX*d*W8>Wbq>Kq3lrclb#ltKw}Dzb$V%ARc`A&q^RNs%IC97|>x%VZf#))_m6 z)Eq--jIm9HnX-*-n0>zKJJf4s||`?;U@zTfwGUfi%XmzGkL5)l!RwzM#{ z7ZDNtD%?9r?h(!|%=s(AMHFIhenq5q=*UkIk$okWrk5R}kSjB=d+rO$1M9;hEw#GI zMS_-*N#1<`$l}~o2nFE#dmxJc{mS&vc)e{brz%9cYRa&v^GP% z?ZU|4^QP?{P-@bL^eso94I$MlW8(ugGpf{8IZ>Igj)p>kc&NeMV(>L=O#f|oTdm76 z%b4|Vxib>j=|5cC8dCfZ>RtazW**6+npiioqm0N_T(?eR@JM^U~o z-084k$DqbYi>ZT9Ds?BVb?%m5WE>_2zbiFzydYKghuE3zRe+->UEfANh0W;epQniY z2Z8vI2k1pGhD%4vRMB|b=*3ybA@Lv_5Mtd(V-PNe;3=?O*X69>RDa3{xh$a_SGIWA zTD2iVo;9HLH>>=tN&&)>7YO)>n1+izbbzzUC{jiQf zMQNkWSkm_foL=BZ6OVbo+iDsLv#SIABO8NynnL$2Mt{0uDFjh>jBtWd4x6=zUN1L? zN50x&1aBUIYAgQ}v5HlW5lLn|yU%z&`bEhKL+OCLFvxCPny-u=GYllvN^=>nGZXsk zM2{=~BOQZ#Ys8|rOYW#+#^V*0k<8n(YtRDizs|d#ECVO2-=rASlESt4D^?JV%YwVJ zOZ$y^KMq{9%MNezGlg$81NXe)K;~!u>$W6YJVGq;DKhZUF=2R!?LrjpTnNZWyHdAz zjk#&g_{4yXzbVLeP9D=yyUsC?BoF+J5-cGgr&&PMzcXHLvn4h^j+KfIk#fOkcNj)2 z=e1?DvwLSqKk?lr`6<~CEosOq(+N;syN7iaWwIx^b$*T-|bYGq)UUrD_Y1c3*{_cld-i8brg+&?CCnCOb%M9GUa|oh)U% ztWcD+g8>aUMga$3TEShW9>s9J`owUG{%S{$UM0|#AX$?#X|8Gwx$4S? zi9%AiW}Wik4~1JEJ}A4q4DKAUnl)hm_-U{PX42!MHOcKTo3;|*FKewSZ#}v_vsmZ3 zNo`-upRE{}p%8+}ldrJ;FD})W!FMhRMob4n=|{H@fR{Kzd5z0O!^5zSye{6FjO%An z(8Z1{RinUTWY9U?uX&YCE@Z^e!9~{;9~8G#O^|X&YAp?zi>y;U@5UcdoOk$SQH)47Oa% zG7g|J-V_nrZO*49bG5t?Ptsiymt<$hv2K21)%eby2;ir#6Wo!{3#)z^$N+X`E+JfN zcpLdSGz7y(=xu-M8+2|S-XA;0=XdaoKW8iBFwHfOo=l8gmK=ii>?jIYBhU**oPEh) z z!xYar8@?AAwDv6?t`6hpz4hSRhto9h^>+M`Oabzayq6`!Y+{-c)rIeeLs_W>jwGr5 z*Lr06GCj%|HvsC#h0}uO4VQwVNA>fJYiSZD9d^8+Xu9GWKHb&vbj}uI^FhP!(7)Xr z_{#)|=Lm!1id^vfUk=F}o6H$>M1@x6!W`ziFU))D+zh#YGo_AadbF`=8ibEwSj;M* zG~2V1?7iuN6ze8Zg;~eJ%1-YCU1tHEbpls+uq*%Jgg z9|~dhS^O?0psU`zYT8}H?jo32+bs#KW5!UXf~>U!Mr}Xu2wmnrw%4Vijw?^@yPnFX zb|0DtxT|gK$WyfEQ6D8jmkp!w>#yI*xc}+~>^S4uQVUt* zPf{Ck(FHfD)dlYeDmxR_y_UbD$AJ(NRzS>NEV%@#Nqn%*xYivYe|{rP^TC$vae@D} zJxE{(FLWNJRh3i9+!LfGklHwy%bb03s)GMLu=@jm3n|FHsS9|2;~Ply<;kR@_qHxV zX@uhb2yg0xuMSP!yZtgAu9UH-^f>fOGfS>ZSiKid8g^(V>(q8BC2=5H1VNIp>9-_A zn}{uVz7;Wj{p5t;p4_dtryFk#*v+1ZGOi4%C}vUCv$8?PR#>ftCb6+JI7bSfsSB8{ zD6Ll<>q%E%nE@@X$aDTQkbrs8u|>QyAz0NSrqwB6&rL%UFS8a8QT+lNr2!tYh#M%I zP(k|k38Z*Q(Eo>LWrV10EWh#|`nNYsMVWK{odenRhXRL~4j0#?!Dq)h)7tcv&Z{<| zu}n6ZoGk0r>-t*7{;{h{-1wzhUatFKGW_B6@L95f_m)pOh=)Oe{%A%O;H}@-^}s1U|)X4+a-*wA=G=7R=t2qX*|8Wt==y0 zd(P~FjdAgUu8CvLsrz1~UQ_nKL@5O`f6N;DwHcU7i&2(qbuQ=dt$HD+sygYRZDMRqA-az zw0P@KSThdQ;1+9QpnZK0-P zT#Qx~L}dy__vR<8Wu(g^1Y;Si6_d03Z*i@UEe*g*%zMD|&95?$y5A5>-EsWo@4_PY z5f(svolt>?UG=vWwm4VzHG6HqxUAAyta4<~F@f1vro{i)*dBT(5M`wA)*lZoy!s2u N(#+Ph_R8HS{{p5tHiiHI diff --git a/gamefi/public/assets/player/attack3.png b/gamefi/public/assets/player/attack3.png deleted file mode 100644 index 51401674f1dfb3186c32d3a1668bfce4f7cfe9a9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4184 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 UcS`f0(qsL!HT3V5-m!V}U*kI*i~s-t diff --git a/gamefi/public/assets/player/defend.png b/gamefi/public/assets/player/defend.png deleted file mode 100644 index ae991920fd0023c9074680410fd7f4de43bb7784..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3545 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 diff --git a/gamefi/public/assets/player/jump.png b/gamefi/public/assets/player/jump.png deleted file mode 100644 index aa0c02e9218ef71662babe297a84eb0095ad3d02..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3369 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 Pj~78rt*=!Yd&d74C46>{ diff --git a/gamefi/public/assets/player/run.png b/gamefi/public/assets/player/run.png deleted file mode 100644 index 3b2fc4ed208b703654ff014759fde8c784a78786..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5394 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 literal 0 HcmV?d00001 diff --git a/gamefi/public/assets/vagabond/attack2/attack2.png b/gamefi/public/assets/vagabond/attack2/attack2.png new file mode 100644 index 0000000000000000000000000000000000000000..f14d9a730351b0aea4c1e0f1019c508d5ad9513c GIT binary patch literal 2503 zcmbVNdpuOz9$$k@219*FdKjmhJQ9+KgPD$`NW=-1nvvJJO6Y{rnf9nuCtXt+k0OtX zDPq*7h+n zMgRb4Z{N1X4*+!r{H82ahfk-_ht2?Kq;21_`N!kAW4-(sal|tGmp2W#l}^2VT73_i zZ)kRW*8}D5`eJ+q@XwN${W*g93{xOC*=Z){HuHPGMsj0kO;>vvQ0o!oW7<+XT6 zXxF_T3{Z5Mp9YL~o1WmHLw)14lCpIK_R?0gOqG8Ds#w1}&FBtH7aAk5UuR z{jzAs0|K123U33w6zgg|`~6-S=0f8Ix}ahUkp`WN^oQm@&6@cYTb!O>@CjZQdTs7> zMg06aF!|;M9Qertrv_cQVUm*E?+D9bnsp(>?0Kl2J|&c87fL1W{Hg{lf7PczZ{4e6 z3j~0-BAg+#Vp)zXasUno?6@k*X8t4Ps2ZTT>M3W!acvh+)_0@Jx;A1;2h=?^V?dLU zzQqE0!5e}r-JhRHG4<3144MD@WRKL!Sv;U^|5FT)Ye`c~uU9xQ`Yr3O1B?QKh((%? zrQ;HRgIo}6u~r!w6hzb+Te}EUdg-YvegG;#Z%Qm(e{ze zByjVO>hKx$6INM>c(=lCuFCcTZ?`6CKnE;pDFH{{<6*dou1HzOJ#nPJhiUP+WUlIDvof zWy%4wAF?C~u8#bCIs)T;S9QdTPX*cJP2A^ncd%Mb1$3K(?Q!!<)c9MP%`q zVeM2SmW$s!j&<;DF)NNLY@ZqVT#wa@xE*M}`?vc7m!rzn6k|bpM z0iMP$@rg0RpHDv&U~)dTu87snq++rnsmRR*v;DM2DiWPfO?@rGq#~vw^pouc`4EE6 zO;#yF-36hkf-v0CwZCcpXuzf3wW7TWJ7nW`JKZ2_OStrB80vyI%iYg`ci7&yJ!(no1u+_*36|K$Vq2Izekxk*7J`k`1Y3Ij0KVVItG*T~ z?qT`D-LB-U@VqNa{#=dRAKiz`Z2ySTWYk9^^?WDU(7zb-=#c)l?Wi!J`7$~%VbI{i zM=j;FW#ia}SD7|v?X$2Fs(QunV#?2EV7Q#45bS#hju}=Q*Q=|~Q7n#?AOB4xex^?g zgVDy8q0MAqb)Z9)cFN`1sr=MEurF(k>kYf*a_RF*2thrmEooud|3hB~$udV$x| z$&C^N^CE6lzqS11)D^5^-wehHks58yv8`y1`tr74!r7xw=`uYvAd*g1s=Rcq@Rc&l z@-T5vzK|Tl8UO5pszMr`KL=?c>~!0c$rjqo49=DupZnsG6iwdu)P6d-Bpq>`eThio zUcfuxI{Flq=+q{R&AMupRugXL@tviCgUHD$3!}Unrn2cn_6sg^(ahnt%ly=0E`QWu z0#?&c5|=AJg;SSHsd;WDJ_hjRDmg1aPNc1)2jqB{;tGUyErC?#+|i}M$UR9gwFnZ= zbkA2lvn2Gg& zBx4OWurJ!aY`o#sq!=X>!?tu(?x{ENfh)Y!*BvN@)-YqqvR}TXWJ{ElAvhR3rC}FUXR9 z^2P1}>*=qT;suhir2QjDkBVsA$|vC*<6&TAj}FJ)d)G#=2X$6EEbOrV3|k zom+>z(7Bw^^JT8@4>kDoTDGbbP`x7)PR-8cutlW}w5v$Mzq5tsQFccXR`WNvwKW#g zXRpxFB*BS0g|U@|ZGK8&weImxu+HaiGpEOCy&aM8nTl{1o;0YU2Y-7q5{1$|LVuoc z6-o5RDx!&sry5OxyIkrys4*f_xPP5lZHzh3%kw;&lroY-p8UXi=3ANUo2Jacpm5u; zumR9lV(|iM-^bD=6sWf>@?r5o4;;&M{!IN>s^vS1$9&CtC}srZpYHB>XPc(D=jDn4 e7ekrPd!*{FHBXasxEo$UV7vRyE#*JZPX7)S6tjN- literal 0 HcmV?d00001 diff --git a/gamefi/public/assets/vagabond/block/block.png b/gamefi/public/assets/vagabond/block/block.png new file mode 100644 index 0000000000000000000000000000000000000000..d0331c807fe04b977486a84d1976f1e832a688ee GIT binary patch literal 539 zcmeAS@N?(olHy`uVBq!ia0vp^4M6O`!3HERU8}EWU|@XY>EaktG3V_~-TXrV5^WFL zIn~6D{1LFwnW=P8DP3z;$islofB21BXDc}-sHIO25qu-V^oM2U3@hU;3oqp5aMpTP z$8&lH&)Ra{^8L>YEk>Zpc)M)jT z%m+4YoU6jRZ~3vRrJg%N9#l_S@-ipxm(q$~3W2eP;z0KS; z`dR&VVxCrRo@?=7!|lN2y+IGESM?v8v}FBq@n-i^v5O`zzPa8`O8zXz^EAV|DqIP- zbB@m4|NiH{b!&nXmG&=LY<9wU_fZ~!+h)--|MQB?_R?X^WL7x;MvPS;{CkPnbs+ls z*!fj!s(zCa55wo}4JS6-J{j}hdxwmO+U}b|7xKUNoeRxS^C)?x5;H5+{4Vp7m0p4( zsSF~^7}Opb*{$;uTyoO7I+5!^z}2n;SqviE7?!-@4T$Vch>vqk2x9nKc7E@^{c}rl zCA%M7`BRy)y=t!)ONW`u+S}(Bb1&{!j$Ek!Mf9Wp&+{|yR&lO)`@St)-h8HbT!#Dq z75CpQ-N!3q_1q`Hl6lF!-ygCQJnj4cY1c=!$Gpv;TqehLhV&4%NJQ8tnVMdJ=1+>Z-I|tGd&a zKqe9m9^CBR#N5#_!(aXPr@D>z!UToyMDxD3+k2x;eBlL_j9A^*|E@2#|1jrh)ofX& zJ9jreIzMUGWw{=QkI%oF-ZP&K)EDc=Xxh^vS#|1n$jAS;|NNTA02F^Ca7jk5XI5Ef z^()i&3pf2t{W15`%EB+l(px93JMJofG5_B2l-#;dUk2yBI(^*AiJPm={0=$y`K3xO zv(HS1b9et-Q*V54vh87|hkw;sYo+&Zl;3I}Sa|7YbPm&ht90v|#? zoH*#lhaQ z8QQG>K3w;I&3(rDP1V|USrhCSr##YMfBLSL@toDV*KS|j@VLHaU(L_?>E|cjK2^nI z@z(kI<&*y&e^#BgJM_%4e4vqTn?K&J+ZjEz;#=fK+XDqMZxrwA@B69aVtoB^(7u_x z3V%Hh1bu0Klph(%vG~Q7AIi71-o3Y&`aWr|?AJ2gwsWONv-o}2T}blVzRA8K_ip06 b%*y|)S!oYuFkVoq0>!nbtDnm{r-UW|Q@0>l literal 0 HcmV?d00001 diff --git a/gamefi/public/assets/vagabond/death/death.png b/gamefi/public/assets/vagabond/death/death.png new file mode 100644 index 0000000000000000000000000000000000000000..dd54ca196d9610956da511bf7f24719c87834597 GIT binary patch literal 745 zcmeAS@N?(olHy`uVBq!ia0y~yU_1b1J8-Z8$=*lHZc3Yf;-gyt=V+6Zrz2i zHM}uKMb!$aa?eD<7~1E_&pWmK{nDC0AC#*!SYFkBnmy|WJ3nKo{mYl1;$ly^zQ6AL zI>s(wl}BGZh{cK9G5? zx!(3%e&M_`b^HYt1@q`KVnZKzPws}d+PlgoiXbFCm+4?yJ~{%zp&jL8ATJFtS_d%tZ6%zbne64 z7uR;K{SZA*d~<2T^5#hHJ4&y+_RF1dd_MV^ioR<3pV@EgF0QL_7h_yG?~nG=@39SU hWDAbnP!_kdXH0*Ucqr_~BtKAk^K|udS?83{1OULTOo{*i literal 0 HcmV?d00001 diff --git a/gamefi/public/assets/vagabond/idle/idle.png b/gamefi/public/assets/vagabond/idle/idle.png new file mode 100644 index 0000000000000000000000000000000000000000..76f03e2a4b0cbbafee7b505e76f5d182e3b88d70 GIT binary patch literal 375 zcmeAS@N?(olHy`uVBq!ia0vp^4M6O`!3HERU8}EWU|_WKba4!+nDh4L#@xdO0;~a6 zCk*o5o@*H(SF46d7LbXQ~QSWzgi^5Lz>p^<}TDg5y$#7V`s} zo%DYffAA>^S$&`H!p;wD5oJ~SE8|y%)!*VX5RXq3GzwX1zlL$!x{Ce#-tS)fJp4-a z-?dxs-`;TgpUu{5*S06c{t=DY`0s=Af^NV6&hNjTKc%AJIrCRN!}|&K33?mO)qq06 M)78&qol`;+0Gh_4+W-In literal 0 HcmV?d00001 diff --git a/gamefi/public/assets/vagabond/jump-attack/jump-attack.png b/gamefi/public/assets/vagabond/jump-attack/jump-attack.png new file mode 100644 index 0000000000000000000000000000000000000000..a7b72995949f6d460a4a7308c03ec4dad5422e75 GIT binary patch literal 2997 zcmd5-`BM|w7Va1j5D)|hlvNaTPy}R#O^~oCf`UX51r$AtGT>mIOi|kkI`aoT+;Mz^i)qhpt=Sy98^qu(pq3>N@Ur}=L6*c+EK`Zp^>&(}od^KJD5O3vH0 z^>^h2Z)>{iQ|hD9d3DV?&K=cE2(xo{pSHfW@VrO3uXm$)G5Mm`2?vk-*!G0*o(p+- z)AU;TsOc{sq^@deKb3lkoMOEi|Xb7`ch0n(cMyHsLVb%T~Q$=Y4m&81T>G>;EWb)-ks7xd{K zSbi`NE>At;+=vpY4ysX+=|g6+I*S3DzA@Lc)yE_H3B);ZOLUx9ZT+sTGbHq5;{I%ldWi5iL+1{b*(mbeW%i6RZG6_B6y_#RXmk6ARbF`@@efvR!;@pTI%8$%)>;X0H~_ zNRMD=5#lwv0jwhj*v^~X)XZ|WthJiBqwR4MN4ySp3JDG~41bt-1MCXxsY%?8*mJnu z`xO2yI;P1`#`_7937$dVCuX98S>O{+1%6MGlaTvK2x&y5tJJ*06#m#_fPL;bWklXz zIFYx%xfU99TCQV(e4S6+%~>HbBr{h`GYCzrX47W{7n`5c3^Eeut|6n@#RYvg#ArIS zJ*&i3PMN*pXN+HhrZG}QgjV~AM()SVTDR;$NJFpWKEgnn=Ht%g7oG}Wlm#!{h7>;2 zBJAV*HrSDc1TpFSwZKa1Q#@S6%}detlno5=%L?k|kvF`6!rnrw#$QBxzFz!fkS(lRjTfR5ki}K7gXhdbnx4=4* zwbH&BLL!Yd{h8G6kCifsWT!l~FF2=g1cC}fPvmzZ6@L7#Bn5*z10C-e51?D!jOb-1 z#`c?fLJqdmpZGyw6KL2ASn+`H#%_Q+bSdNix{hK_Xl+;{ZOexU^5!vXpc?*0w1O9;S^gTjr;ZGL$fQzlUj1;Zti#JzPa@v`7Bdv*Z zg96Y7A;!SX`g1=3{Ke;`i^~le`RB>HRwDYTanAsJ6X& z*}Yk?Y}r9K%YJTU01n9ttI&K28Od`HCKQ%666Yg$or_2}b*-TM5K%v831h7?(qoAR zb|$}OjQ&bmvIiSf_)x-IcfZ(yMS=BqAg22#H35IU1c}|`B7QeeZi$>37u*dVFmbDb zX4x?PjEehT6al+2A{SY&K~qi%Z94Vh6|+i6V5e%0u{>3KgRkPEx+WZ_g0HN2At>X} zIB@_uZ?z$I?}@1Wo5Y{Lr5`I6Thf@=eUujMIvpoUfe`w7!D=o*F9$*Y&8>SJfy%$t z_6ekimXT*-`|=V*LwO8?DsDwW?PrD(Sinl-ShyA_y$uE#o&s&*4qisv7>29X@ zq!c6NJQ07BW~+mQaVCyXrc;YARS&if#;^M z8XiCWQyo`ZBdJ&q`*qwR$L^6ZsHY2rf~oN04id81$S5a3&kpL4CDQ$EmCXrptGnR!f(U%_pq z_agY=CBS3qz$K}wNiGeYkOcP3P&T+GcpKDiFCjTov*X)vKViAkHD{-~Je-AL|Bj}$ z4(U?wTiI>6HL0fckG;b(zHU*;Ih+3G?7PQz2W>HXFEzLqCu1pwH+&56s3#sC0i<<}>Xkvq&vkE2fG zorQu|sVIuB$d-34t%ce_?Db$4!xvTle^~C77&m%<`T4 z`KH|~=If8Psm4v5J!96NS-NvScbNF-CGq_!yHr`-aX01nl<%i6iO-n*=li_m$#tL3 zZ~S^=`H9t4Cg)6icDet`U$;I;yy))7l7PnhtM;tY?@KQ%xoXzE_}n!0C+VkGNBym; z3$yq4f1d2jIls*_+~nz_+6^zHA2eUTAFAYITh86J>^Bo} z7IS~~ef$6R{^@O92Sk&T*G`UG`7rZgPy{mv=by3yt|wZ? z4^2-VxqgJ}z?z!RoDn8ZwHj|9S^A@NO|TiWiW$?9>kNOd|G&p>-@W)Ra6UE#Y z*D9L+QwmlnewY33EnD5{xO;Y89(RttdS>_a+XsOSbAO1Om=eDAx!0%jTcFVdQ&MBb@040A%6951J literal 0 HcmV?d00001 From 777fbaf19e6caf311fadd4cd5d76ef5b578b1853 Mon Sep 17 00:00:00 2001 From: Yosgi Date: Sun, 16 Feb 2025 15:21:30 +1300 Subject: [PATCH 2/4] Update AI controller and add Vagabond sprite loader --- gamefi/app/components/BattleScene.ts | 17 ++++--- ...yerSpriteLoader.ts => HeroSpriteLoader.ts} | 0 .../components/assets/VagabondSpriteLoader.ts | 45 ++++++++++++++++++ .../attack1/{attack.png => attack1.png} | Bin gamefi/public/assets/vagabond/hurt/hurt.png | Bin 0 -> 580 bytes gamefi/public/assets/vagabond/jump/jump.png | Bin 0 -> 575 bytes gamefi/public/assets/vagabond/run/run.png | Bin 0 -> 1001 bytes 7 files changed, 55 insertions(+), 7 deletions(-) rename gamefi/app/components/assets/{PlayerSpriteLoader.ts => HeroSpriteLoader.ts} (100%) create mode 100644 gamefi/app/components/assets/VagabondSpriteLoader.ts rename gamefi/public/assets/vagabond/attack1/{attack.png => attack1.png} (100%) create mode 100644 gamefi/public/assets/vagabond/hurt/hurt.png create mode 100644 gamefi/public/assets/vagabond/jump/jump.png create mode 100644 gamefi/public/assets/vagabond/run/run.png diff --git a/gamefi/app/components/BattleScene.ts b/gamefi/app/components/BattleScene.ts index f404181..2054260 100644 --- a/gamefi/app/components/BattleScene.ts +++ b/gamefi/app/components/BattleScene.ts @@ -1,6 +1,7 @@ import Phaser from 'phaser'; import { PlayerController } from './controllers/PlayerController'; -import { loadPlayerSpriteSheets, createPlayerAnimations } from './assets/PlayerSpriteLoader'; +import { loadPlayerSpriteSheets, createPlayerAnimations } from './assets/HeroSpriteLoader'; +import { loadVagabondMaterials , createVagabondAnimations } from './assets/VagabondSpriteLoader'; import { AIController } from './controllers/AI/AIController'; import { CharState } from './controllers/CharState'; @@ -30,7 +31,7 @@ export class BattleScene extends Phaser.Scene { // 分别加载“player”资源 & “monster”资源 loadPlayerSpriteSheets(this, 'assets/hero', 'hero', { width: 64, height: 44 }); - loadPlayerSpriteSheets(this, 'assets/hero', 'hero', { width: 64, height: 44 }); + loadVagabondMaterials(this, 'assets/vagabond', 'AI', { width: 64, height: 64 }); } public create(): void { @@ -43,10 +44,10 @@ export class BattleScene extends Phaser.Scene { // 创建动画 (player / monster) createPlayerAnimations(this, 'hero'); - createPlayerAnimations(this, 'hero'); + createVagabondAnimations(this, 'AI'); // ============ 创建玩家 ============ - // 1) 用 PlayerController, 传入初始纹理 (如 'player_idle') + // 1) 用 PlayerController, 传入初始纹理 this.playerCtrl = new PlayerController(this, 100, 300, 'hero_idle'); this.playerSprite = this.playerCtrl.sprite as SpriteWithHP; this.playerSprite.setScale(1.5); @@ -62,16 +63,18 @@ export class BattleScene extends Phaser.Scene { // ============ 创建怪物 ============ // ============ 创建对手(怪物/AI) ============ - this.monsterCtrl = new AIController(this, 600, 300, 'hero_idle', { + this.monsterCtrl = new AIController(this, 600, 300, 'AI_idle', { hp: 100, scaleFactor: 1.5, debug: true, // 可传入 AI 专用参数,如 dashAttackInitialSpeed、dashAttackDeceleration 等 dashAttackInitialSpeed: 700, - dashAttackDeceleration: 0.95 + dashAttackDeceleration: 0.95, + animPrefix: 'AI', }); this.monsterSprite = this.monsterCtrl.sprite as SpriteWithHP; this.monsterSprite.hp = 100; + this.monsterSprite.setScale(2.5); this.monsterSprite.setCollideWorldBounds(true); this.physics.add.collider(this.monsterSprite, ground); @@ -82,7 +85,7 @@ export class BattleScene extends Phaser.Scene { // 播放 Idle 动画 this.playerSprite.play('hero-idle'); - this.monsterSprite.play('hero-idle'); + this.monsterSprite.play('AI-idle'); } public update(time: number, delta: number): void { diff --git a/gamefi/app/components/assets/PlayerSpriteLoader.ts b/gamefi/app/components/assets/HeroSpriteLoader.ts similarity index 100% rename from gamefi/app/components/assets/PlayerSpriteLoader.ts rename to gamefi/app/components/assets/HeroSpriteLoader.ts diff --git a/gamefi/app/components/assets/VagabondSpriteLoader.ts b/gamefi/app/components/assets/VagabondSpriteLoader.ts new file mode 100644 index 0000000..247a13b --- /dev/null +++ b/gamefi/app/components/assets/VagabondSpriteLoader.ts @@ -0,0 +1,45 @@ +// AILoader.ts +import Phaser from 'phaser'; + +export function loadVagabondMaterials(scene: Phaser.Scene, folder: string, prefix: string, { + width = 64, + height = 64, +}) { + const actions = [ + 'attack1', 'attack2', 'block', 'dash', 'death', 'hurt', + 'idle', 'jump', 'jump-attack', 'jump-flip', 'run' + ]; + + actions.forEach(action => { + scene.load.spritesheet(`${prefix}_${action}`, `${folder}/${action}/${action}.png`, { + frameWidth: width, + frameHeight: height, + }); + }); +} + + +export function createVagabondAnimations(scene: Phaser.Scene, prefix: string) { + const anims = { + 'idle': { frames: 6, frameRate: 6, repeat: -1 }, + 'run': { frames: 8, frameRate: 10, repeat: -1 }, + 'attack1': { frames: 6, frameRate: 12, repeat: 0 }, + 'attack2': { frames: 6, frameRate: 12, repeat: 0 }, + 'block': { frames: 4, frameRate: 8, repeat: 0 }, + 'dash': { frames: 5, frameRate: 10, repeat: 0 }, + 'death': { frames: 7, frameRate: 8, repeat: 0 }, + 'hurt': { frames: 4, frameRate: 8, repeat: 0 }, + 'jump': { frames: 3, frameRate: 8, repeat: 0 }, + 'jump-attack': { frames: 6, frameRate: 12, repeat: 0 }, + 'jump-flip': { frames: 6, frameRate: 12, repeat: 0 } + }; + + Object.entries(anims).forEach(([key, { frames, frameRate, repeat }]) => { + scene.anims.create({ + key: `${prefix}-${key}`, + frames: scene.anims.generateFrameNumbers(`${prefix}_${key}`, { start: 0, end: frames - 1 }), + frameRate, + repeat + }); + }); +} diff --git a/gamefi/public/assets/vagabond/attack1/attack.png b/gamefi/public/assets/vagabond/attack1/attack1.png similarity index 100% rename from gamefi/public/assets/vagabond/attack1/attack.png rename to gamefi/public/assets/vagabond/attack1/attack1.png diff --git a/gamefi/public/assets/vagabond/hurt/hurt.png b/gamefi/public/assets/vagabond/hurt/hurt.png new file mode 100644 index 0000000000000000000000000000000000000000..9e99c24fcf0462f8600a0941ad50484b364b4487 GIT binary patch literal 580 zcmeAS@N?(olHy`uVBq!ia0y~yU<5K595~p3J8~-z)m-wq84}U^aV0;eiuQV)tr3#ul_% z9sa0OU+`}kYr>M)e{zv!jU4*RgTDwkrJlUMg|pC~@x@ljirAOSV;?*%(fWPY%+)zV z_y4V@Rp;Wo-u*c{kHPKU-~77_Ky9Y3_K)07&x_|*I8nEKZ;hKt{oj-OJg!Yp-OsdP z(|Wb?D{=>>MF0Eohs$9?=BN69zvOHtMJ#@Le#49BA`J|eeLwv95aK17EqF%!z?AtG zTn<9#`TY;?Wk270fj#2Z-^JbgnH+)_o7rv-Vqn_4Z@(+Q;*}}(RpL3S$sdCm!nT#1 zP=4IILG0)MbMtkpH#2Q0Ih6k|cD*`-_s;)I!q?X}-1GnSw_k_%!iL2MKC{MWueB9# z2%0uKrv35H%e^0d{k!(`{==|;LO=X7qh>vyA6NNr4-@ai{Zl>#GOX)oz~ut6=!{8sJj33{T5AmVf+1ZM_>F5{>gjn=>3c(v*M*dk?HB`=d#Wzp$Pz5tOO0q@5rzjJ zyZXA6FI;qLcR9`bjYmc+{f6`frKQTccjXebU*&8x?AgPovS3eo^*(QYt3K&oPLjC+Uvzn#G6HJRRr90hY;|2X#O{>%HDbs6UeYc{YP4t)RbRo?eEruz&Hw=JEruB$pH z!Q=_3YPyU~pou0C3c@)=!mVL!@u3rkwP-87f zI<8W*|Ifrfg+bpLyzQCZ+U~O{T{@+xzI6NdkQbjGg+5aEn9F$2-~QI6$aZ>s2i_;SNKY;k2 Lu6{1-oD!M literal 0 HcmV?d00001 diff --git a/gamefi/public/assets/vagabond/run/run.png b/gamefi/public/assets/vagabond/run/run.png new file mode 100644 index 0000000000000000000000000000000000000000..387d2349ebb1a1db643be6f76f4c9650d105328e GIT binary patch literal 1001 zcmeAS@N?(olHy`uVBq!ia0y~yU;;8395~p3WX}Hc`xzLRH+Z@@hE&XXd)Kk(mVpRc z!qUs!s=MzjPCv2G!ukEdbuyiLE7aOTr}6)) zBc7gkI4xe5h|1aICJO>UP z-9M$F`Tw2{JS4#`JewjLke%5=IO)oh2QH}dpu6icwFs}SM#d=+1ebZDSz&7{@H28 z7iasQ|1QIwoj>xe7{vY;bBi@z$qn%8QD0y!_CI86c;NAWObc%%Xsavm|CUI2cC>!w ziig{OJh$OIz2}F%VCI|qKflN?;$3BJ*0j3%2HS&aej@)Qg#YbT@@;VDRzK{!y?K7^ z_SV519iyj|lc~GP@|3|X=>$?}YyX+X#Y<}%O>a%yYJp1)e@;lc@ z%Qq-(KPa@<{6GKxio=V-*H`}B<=b9=>gf9_xoXcHyTt#jIxmnr;b*M@xBvcQ&zgL< zAMV-tjWhJ~*7LjjIfDORyZ3*~v7_r-t(||Y7MVRSE9tZG8q1LT_kVuee)f9&**`Py z@BC-y_orUvu$1wY+n*RhycU>6RB&Bd`_I&zq4>I&VB4e|W&?xk`xlxqhCWuR(DeDM z93{tMbS3_{!;`4xJ-v++itC;KIbV;LJ^iPpJg34}B=VJvRooxz@4MFI2Ji2SsXuKa z5c%cTGoI%SE6X^n|Ed2Idb9Pt^9i{szo_4qZ&VDD)|@-BbvAoZ_Q|qog%i>~wnwMR mnooS)7bD$2HFr(P`tSPM56z~zxT~^&@}8%wpUXO@geCw|JkhKG literal 0 HcmV?d00001 From 474366c75b2707ee8883c50039ef617921e37a80 Mon Sep 17 00:00:00 2001 From: Yosgi Date: Sun, 16 Feb 2025 20:26:37 +1300 Subject: [PATCH 3/4] Update AI controller and add Vagabond sprite loader --- gamefi/app/components/BattleScene.ts | 29 +- .../components/assets/VagabondSpriteLoader.ts | 10 +- .../components/controllers/BaseController.ts | 62 ++- .../app/components/controllers/CharState.ts | 12 + .../controllers/Player/PlayerController.ts | 377 ++++++++++++++++-- .../controllers/PlayerAnimationManager.ts | 2 +- .../components/controllers/PlayerAttack.ts | 2 +- .../controllers/PlayerController.ts | 365 ----------------- .../app/components/controllers/PlayerJump.ts | 2 +- .../components/controllers/PlayerMovement.ts | 2 +- .../controllers/PlayerStateManager.ts | 2 +- .../assets/vagabond/attack3/attack3.png | Bin 0 -> 2997 bytes .../vagabond/dash_attack/dash_attack.png | Bin 0 -> 2776 bytes 13 files changed, 440 insertions(+), 425 deletions(-) delete mode 100644 gamefi/app/components/controllers/PlayerController.ts create mode 100644 gamefi/public/assets/vagabond/attack3/attack3.png create mode 100644 gamefi/public/assets/vagabond/dash_attack/dash_attack.png diff --git a/gamefi/app/components/BattleScene.ts b/gamefi/app/components/BattleScene.ts index 2054260..e63419a 100644 --- a/gamefi/app/components/BattleScene.ts +++ b/gamefi/app/components/BattleScene.ts @@ -1,5 +1,5 @@ import Phaser from 'phaser'; -import { PlayerController } from './controllers/PlayerController'; +import { PlayerController } from './controllers/Player/PlayerController'; import { loadPlayerSpriteSheets, createPlayerAnimations } from './assets/HeroSpriteLoader'; import { loadVagabondMaterials , createVagabondAnimations } from './assets/VagabondSpriteLoader'; import { AIController } from './controllers/AI/AIController'; @@ -50,7 +50,7 @@ export class BattleScene extends Phaser.Scene { // 1) 用 PlayerController, 传入初始纹理 this.playerCtrl = new PlayerController(this, 100, 300, 'hero_idle'); this.playerSprite = this.playerCtrl.sprite as SpriteWithHP; - this.playerSprite.setScale(1.5); + this.playerSprite.setScale(1); this.playerSprite.hp = 100; this.playerSprite.setCollideWorldBounds(true); this.physics.add.collider(this.playerSprite, ground); @@ -74,7 +74,7 @@ export class BattleScene extends Phaser.Scene { }); this.monsterSprite = this.monsterCtrl.sprite as SpriteWithHP; this.monsterSprite.hp = 100; - this.monsterSprite.setScale(2.5); + this.monsterSprite.setScale(1.5); this.monsterSprite.setCollideWorldBounds(true); this.physics.add.collider(this.monsterSprite, ground); @@ -102,20 +102,27 @@ export class BattleScene extends Phaser.Scene { this.checkAttackCollision(); } - // 示例:如果要做攻击命中检测,就这么写 + private checkAttackCollision(): void { // 如果玩家正在攻击 - const attackStates = [CharState.Attack1, CharState.Attack2, CharState.Attack3, CharState.DashAttack]; + const attackStates = [ + CharState.Attack1, + CharState.Attack2, + CharState.Attack3, + CharState.DashAttack + ]; if (attackStates.includes(this.playerCtrl.state)) { - // 使用 Phaser 的 overlap 检测两个精灵的重叠 + // 使用 Phaser.Physics.Arcade.overlap 检测玩家与怪物是否重叠 if (this.physics.overlap(this.playerSprite, this.monsterSprite)) { - // 命中:减少对手 HP(这里仅示例减少 10 点) - this.monsterSprite.hp -= 10; - console.log('Hit! Monster HP:', this.monsterSprite.hp); - // 你可以在这里添加其他效果,如播放受击动画、生成粒子特效等 + // 根据双方位置确定击退方向 + const hitDirection = this.playerSprite.x < this.monsterSprite.x ? 'right' : 'left'; + // 调用 AI 角色的 onHit 方法,减少一定伤害(例如10) + this.monsterCtrl.onHit(10 / 100, hitDirection); } } + // + } } @@ -129,7 +136,7 @@ export const config: Phaser.Types.Core.GameConfig = { default: 'arcade', arcade: { gravity: { x: 0, y: 1400 }, - debug: true + debug: false } }, scene: [BattleScene] diff --git a/gamefi/app/components/assets/VagabondSpriteLoader.ts b/gamefi/app/components/assets/VagabondSpriteLoader.ts index 247a13b..5ecef92 100644 --- a/gamefi/app/components/assets/VagabondSpriteLoader.ts +++ b/gamefi/app/components/assets/VagabondSpriteLoader.ts @@ -1,18 +1,18 @@ // AILoader.ts import Phaser from 'phaser'; - +const isAttack = (action:string) => action.includes('attack'); export function loadVagabondMaterials(scene: Phaser.Scene, folder: string, prefix: string, { width = 64, height = 64, }) { const actions = [ 'attack1', 'attack2', 'block', 'dash', 'death', 'hurt', - 'idle', 'jump', 'jump-attack', 'jump-flip', 'run' + 'idle', 'jump', 'jump-attack', 'jump-flip', 'run','attack3','dash_attack' ]; actions.forEach(action => { scene.load.spritesheet(`${prefix}_${action}`, `${folder}/${action}/${action}.png`, { - frameWidth: width, + frameWidth:isAttack(action) ? width * 2 : width, frameHeight: height, }); }); @@ -31,7 +31,9 @@ export function createVagabondAnimations(scene: Phaser.Scene, prefix: string) { 'hurt': { frames: 4, frameRate: 8, repeat: 0 }, 'jump': { frames: 3, frameRate: 8, repeat: 0 }, 'jump-attack': { frames: 6, frameRate: 12, repeat: 0 }, - 'jump-flip': { frames: 6, frameRate: 12, repeat: 0 } + 'jump-flip': { frames: 6, frameRate: 12, repeat: 0 }, + 'attack3': { frames: 13, frameRate: 12, repeat: 0 }, + 'dash_attack': { frames: 10, frameRate: 12, repeat: 0 }, }; Object.entries(anims).forEach(([key, { frames, frameRate, repeat }]) => { diff --git a/gamefi/app/components/controllers/BaseController.ts b/gamefi/app/components/controllers/BaseController.ts index 27978fb..9ef1a5e 100644 --- a/gamefi/app/components/controllers/BaseController.ts +++ b/gamefi/app/components/controllers/BaseController.ts @@ -1,7 +1,7 @@ // BaseController.ts import Phaser from 'phaser'; import { CharState } from './CharState'; -import { PlayerConfig } from './PlayerController'; +import { PlayerConfig } from './Player/PlayerController'; import { PlayerStateManager } from './PlayerStateManager'; import { PlayerAnimationManager } from './PlayerAnimationManager'; import { PlayerMovement } from './PlayerMovement'; @@ -139,7 +139,9 @@ export abstract class BaseController { console.debug(`Playing animation: ${animKey}`); } } - + + + public isJumping(): boolean { return ( this.state === CharState.Jump || @@ -150,10 +152,56 @@ export abstract class BaseController { } public isAttacking(): boolean { return ( - this.state === CharState.Attack1 || - this.state === CharState.Attack2 || - this.state === CharState.Attack3 || - this.state === CharState.DashAttack + this.state === CharState.Attack1 || + this.state === CharState.Attack2 || + this.state === CharState.Attack3 || + this.state === CharState.DashAttack ); -} + } + + /** + * 当角色受到攻击时调用,执行受击反馈 + * @param damage 伤害值 + * @param hitDirection 击退方向('left' 或 'right') + */ + public onHit(damage: number, hitDirection: 'left' | 'right'): void { + // 如果已经在受击状态,则不重复扣血 + if (this.state === CharState.Hurt) return; + + this.hp -= damage; + (this.sprite as any).hp = Math.floor(this.hp); + + if (this.hp <= 0) { + this.die(); + return; + } + + this.stateManager.changeState(CharState.Hurt); + this.playAnimationIfNotPlaying(`${this.animPrefix}-hurt`); + + const knockbackSpeed = 200; + if (hitDirection === 'left') { + this.sprite.setVelocityX(-knockbackSpeed); + } else { + this.sprite.setVelocityX(knockbackSpeed); + } + + this.sprite.setTint(0xff0000); + this.scene.time.delayedCall(200, () => { + this.sprite.clearTint(); + }); + } + + + /** + * 当血量耗尽时调用,处理角色死亡 + */ + public die(): void { + this.stateManager.changeState(CharState.Death); + this.playAnimationIfNotPlaying(`${this.animPrefix}-death`); + // 禁用碰撞、输入、动作更新等 + this.isDead = true; + this.sprite.setVelocity(0); + // 这里可以进一步处理死亡后的逻辑(例如重启关卡) + } } diff --git a/gamefi/app/components/controllers/CharState.ts b/gamefi/app/components/controllers/CharState.ts index f7d3c81..acd1f7d 100644 --- a/gamefi/app/components/controllers/CharState.ts +++ b/gamefi/app/components/controllers/CharState.ts @@ -5,6 +5,8 @@ export enum CharState { Jump = 'Jump', UpToFall = 'UpToFall', Fall = 'Fall', + Hurt = 'Hurt', + Death = 'Death', Attack1 = 'Attack1', Attack2 = 'Attack2', Attack3 = 'Attack3', @@ -13,4 +15,14 @@ export enum CharState { Slide = 'Slide', Stunned = 'Stunned', AirRun = 'AirRun', +} + + +export enum AIState { + Idle = 'Idle', + Run = 'Run', + Attack1 = 'Attack1', + Attack2 = 'Attack2', + JumpAttack = 'JumpAttack', + JumpFlip = 'JumpFlip', } \ No newline at end of file diff --git a/gamefi/app/components/controllers/Player/PlayerController.ts b/gamefi/app/components/controllers/Player/PlayerController.ts index 1be6d18..a0d69d3 100644 --- a/gamefi/app/components/controllers/Player/PlayerController.ts +++ b/gamefi/app/components/controllers/Player/PlayerController.ts @@ -1,50 +1,361 @@ -// PlayerController.ts import Phaser from 'phaser'; -import { BaseController } from '../BaseController'; -import { CharState } from '../CharState'; import { PlayerMovement } from '../PlayerMovement'; import { PlayerJump } from '../PlayerJump'; import { PlayerAttack } from '../PlayerAttack'; +import { PlayerStateManager } from "../PlayerStateManager"; +import { PlayerAnimationManager } from "../PlayerAnimationManager"; +import { CharState } from '../CharState'; +import { BaseController } from '../BaseController'; + +export interface PlayerConfig { + runSpeed?: number; // 普通移动速度(Run状态) + dashSpeed?: number; // 冲刺速度(Dash状态) + slideSpeed?: number; // 闪避时水平速度(Slide状态) + jumpVelocity?: number; // 起跳力度 + dashDuration?: number; // Dash 持续时间(毫秒) + doubleTapThreshold?: number; // 双击检测阈值(毫秒) + slideDuration?: number; // Slide 持续时间(毫秒) + slideCooldown?: number; // Slide 冷却时间(毫秒) + slideInvincibleDuration?: number; // Slide 无敌时长(毫秒) + animPrefix?: string; // 动画前缀,例如 'player' + hp?: number; // 初始血量 + scaleFactor?: number; // 精灵缩放因子 + coyoteTime?: number; // 离地后仍能跳跃的缓冲时间(毫秒),例如 150 + jumpCutMultiplier?: number; // 释放跳跃键后,减少上升速度的比例(0~1),例如 0.9 + debug?: boolean; // 是否输出调试信息 + // 新增 dashAttack 参数 + dashAttackInitialSpeed?: number; // DashAttack 初始速度(px/s) + dashAttackDeceleration?: number; // DashAttack 衰减系数(例如 0.95) +} export class PlayerController extends BaseController { - public cursors: Phaser.Types.Input.Keyboard.CursorKeys; - public attackKey: Phaser.Input.Keyboard.Key; - public blockKey: Phaser.Input.Keyboard.Key; - public slideKey: Phaser.Input.Keyboard.Key; + public hp: number; + public isDead: boolean = false; + /** 在 Slide 等无敌期间为 true */ + public isInvincible: boolean = false; + + public state: CharState = CharState.Idle; + public scene: Phaser.Scene; + public animPrefix: string; + public debug: boolean; + + // 速度与物理参数 + public runSpeed: number; + public dashSpeed: number; + public slideSpeed: number; + public jumpVelocity: number; + // Dash 与 Slide 的持续时间、冷却等 + public dashDuration: number; + public doubleTapThreshold: number; + public slideDuration: number; + public slideCooldown: number; + public slideInvincibleDuration: number; + + // 定时器变量(存储结束时间) + public dashEndTime: number = 0; + public slideEndTime: number = 0; + public lastSlideTime: number = 0; + + // 跳跃相关:用于支持二段跳 + public doubleJumpUsed: boolean = false; + public coyoteTime: number; + public jumpCutMultiplier: number; + public lastGroundedTime: number = 0; + public runStartTime: number = 0; // 记录进入 Run 状态的开始时间 + public isAirRun: boolean = false; // 标记是否为空中跑动状态 + public airRunEligible: boolean = false;// 记录最后一次更新 airRunEligible 的时间(用于超时重置资格) + public airRunEligibleTime: number = 0; + + + // 输入按键 + public cursors: Phaser.Types.Input.Keyboard.CursorKeys; + public attackKey: Phaser.Input.Keyboard.Key; + public blockKey: Phaser.Input.Keyboard.Key; + public slideKey: Phaser.Input.Keyboard.Key; + public lastDirection: 'left' | 'right' = 'right'; + + // 用于左右双击检测(触发 Dash) + public lastTap: { left: number; right: number } = { left: 0, right: 0 }; + + // 攻击连击系统 + public nextAttackRequested: boolean = false; + public attackComboStep: number = 0; // 0->attack1, 1->attack2, 2->attack3 + public normalAttackAnimations: string[]; + // dashAttack 参数 + public dashAttackInitialSpeed: number; + public dashAttackDeceleration: number; + + public dashAttackAnimation: string; + + // 子模块 + public movement: PlayerMovement; + public jump: PlayerJump; + public attack: PlayerAttack; + + // 新增:状态与动画管理模块 + public stateManager: PlayerStateManager; + public animationManager: PlayerAnimationManager; + public bufferedAction: (() => void) | null = null; + constructor( + scene: Phaser.Scene, + x: number, + y: number, + texture: string, + config?: PlayerConfig + ) { + super(scene, x, y, texture, config); + this.scene = scene; + this.animPrefix = config?.animPrefix ?? 'hero'; + this.hp = config?.hp ?? 100; + this.debug = config?.debug ?? false; + + // 配置参数(默认值) + this.runSpeed = config?.runSpeed ?? 150; + this.dashSpeed = config?.dashSpeed ?? 120; + this.slideSpeed = config?.slideSpeed ?? 300; + this.jumpVelocity = config?.jumpVelocity ?? -500; + this.dashDuration = config?.dashDuration ?? 250; + this.doubleTapThreshold = config?.doubleTapThreshold ?? 300; + this.slideDuration = config?.slideDuration ?? 500; + this.slideCooldown = config?.slideCooldown ?? 2000; + this.slideInvincibleDuration = config?.slideInvincibleDuration ?? 300; + // 离地缓冲和跳跃剪切 + const coyoteTimeDefault = 150; + const jumpCutMultiplierDefault = 0.9; + + this.coyoteTime = config?.coyoteTime ?? coyoteTimeDefault; + this.jumpCutMultiplier = config?.jumpCutMultiplier ?? jumpCutMultiplierDefault; + + // 新增属性,用于记录最近一次着地时间 + this.lastGroundedTime = 0; + + // 新增 dashAttack 参数 + this.dashAttackInitialSpeed = config?.dashAttackInitialSpeed ?? 700; + this.dashAttackDeceleration = config?.dashAttackDeceleration ?? 0.95; + + + + + // 注册输入 + this.cursors = scene.input.keyboard!.createCursorKeys(); + this.attackKey = scene.input.keyboard!.addKey(Phaser.Input.Keyboard.KeyCodes.F); + this.blockKey = scene.input.keyboard!.addKey(Phaser.Input.Keyboard.KeyCodes.D); + this.slideKey = scene.input.keyboard!.addKey(Phaser.Input.Keyboard.KeyCodes.SHIFT); + + // 设置攻击动画(连击)和 dash 攻击动画 + this.normalAttackAnimations = [ + `${this.animPrefix}-attack1`, + `${this.animPrefix}-attack2`, + `${this.animPrefix}-attack3` + ]; + this.dashAttackAnimation = `${this.animPrefix}-dash_attack`; + // 监听动画完成事件,用于处理攻击连击、dash_attack、slide 等状态结束 + // 初始化子模块 + this.movement = new PlayerMovement(this); + this.jump = new PlayerJump(this); + this.attack = new PlayerAttack(this); + + // 初始化状态与动画管理模块 + this.animationManager = new PlayerAnimationManager(this); + this.stateManager = new PlayerStateManager(this, this.animationManager); - constructor( - scene: Phaser.Scene, - x: number, - y: number, - texture: string, - config?: any - ) { - super(scene, x, y, texture, config); + this.setupAnimationEvents(); + } - // 初始化玩家专用输入 - this.cursors = scene.input.keyboard!.createCursorKeys(); - this.attackKey = scene.input.keyboard!.addKey(Phaser.Input.Keyboard.KeyCodes.F); - this.blockKey = scene.input.keyboard!.addKey(Phaser.Input.Keyboard.KeyCodes.D); - this.slideKey = scene.input.keyboard!.addKey(Phaser.Input.Keyboard.KeyCodes.SHIFT); + /** + * 监听动画完成事件,根据动画完成时机处理攻击连击等状态切换 + */ + private setupAnimationEvents(): void { + this.sprite.on( + Phaser.Animations.Events.ANIMATION_COMPLETE, + (anim: Phaser.Animations.Animation) => { + // 处理普通攻击连击 + if ( + ((anim.key === this.normalAttackAnimations[0] && this.state === CharState.Attack1) || + (anim.key === this.normalAttackAnimations[1] && this.state === CharState.Attack2) || + (anim.key === this.normalAttackAnimations[2] && this.state === CharState.Attack3)) + ) { + if (this.nextAttackRequested && this.attackComboStep < 2) { + this.attackComboStep++; + if (this.attackComboStep === 1) { + this.stateManager.changeState(CharState.Attack2); + } else if (this.attackComboStep === 2) { + this.stateManager.changeState(CharState.Attack3); + } + this.nextAttackRequested = false; + } else { + // 连击结束后,根据是否有移动输入返回 Run 或 Idle 状态 + if (this.cursors.left?.isDown || this.cursors.right?.isDown) { + this.stateManager.changeState(CharState.Run); + } else { + this.stateManager.changeState(CharState.Idle); + } + this.attackComboStep = 0; + this.nextAttackRequested = false; + } + } + // Dash 攻击结束后 + else if (anim.key === this.dashAttackAnimation && this.state === CharState.DashAttack) { + if (this.nextAttackRequested) { + // 如果在 DashAttack 期间玩家请求了连击, + // 则切换到普通攻击连击的第2段 + this.stateManager.changeState(CharState.Attack2); + this.nextAttackRequested = false; + // 设置连击步数(例如从 1 开始) + this.attackComboStep = 1; + } else { + if (this.cursors.left?.isDown || this.cursors.right?.isDown) { + this.stateManager.changeState(CharState.Run); + } else { + this.stateManager.changeState(CharState.Idle); + } + } + } + // Slide 动作完成后 + else if (anim.key === `${this.animPrefix}-slide` && this.state === CharState.Slide) { + this.stateManager.changeState(CharState.Idle); + } + // 对于 up_to_fall,交由 update() 检测动画进度转换到 Fall 状态 + if (this.bufferedAction) { + const action = this.bufferedAction; + this.bufferedAction = null; + action(); + } + } + ); + } - // 初始化玩家的子模块:移动、跳跃、攻击 - this.movement = new PlayerMovement(this); - this.jump = new PlayerJump(this); - this.attack = new PlayerAttack(this); - } + /** + * 辅助方法:如果当前精灵动画与目标动画不一致,则播放目标动画 + */ + public playAnimationIfNotPlaying(animKey: string): void { + if (this.sprite.anims.currentAnim && this.sprite.anims.currentAnim.key === animKey) return; + this.sprite.play(animKey, true); + if (this.debug) { + console.debug(`Playing animation: ${animKey}`); + } + } + /** + * 每帧调用,更新状态、检测输入、处理各状态之间的转换 + */ + public update(time: number, delta: number): void { + if (this.isDead) return; - public update(time: number, delta: number): void { - // 执行基础更新(例如缓冲动作处理) - super.update(time, delta); - // 调用各模块处理玩家输入 - this.movement.handleMovementInput(time); - this.jump.handleJumpInput(time); - this.attack.handleAttackInput(); - } + // 跳跃阶段转换: + // 当处于 Jump(起跳)状态且垂直速度 >= 0 时转换到 UpToFall + if (this.state === CharState.Jump && this.sprite.body!.velocity.y >= 0) { + this.stateManager.changeState(CharState.UpToFall); + } + // 当处于 UpToFall 且动画播放完毕时转换到 Fall(下落) + else if (this.state === CharState.UpToFall) { + if (this.sprite.anims.currentAnim && this.sprite.anims.getProgress() >= 1) { + this.stateManager.changeState(CharState.Fall); + } + } + // 着地检测:当角色触地时,若处于跳跃状态则重置二段跳标记,并根据是否有水平输入切换到 Run 或 Idle + if (this.sprite.body!.blocked.down) { + if ( + this.state === CharState.Jump || + this.state === CharState.UpToFall || + this.state === CharState.Fall + ) { + this.doubleJumpUsed = false; + if (this.cursors.left?.isDown || this.cursors.right?.isDown) { + this.stateManager.changeState(CharState.Run); + } else { + this.stateManager.changeState(CharState.Idle); + } + } + } + // Dash 状态:Dash 持续时间结束后恢复 Idle 状态(或根据需求调整为 Idle/Run) + if (this.state === CharState.Dash && time > this.dashEndTime) { + this.stateManager.changeState(CharState.Idle); + this.sprite.setVelocityX(0); + } + // Slide 状态:Slide 结束后恢复 Idle + if (this.state === CharState.Slide && time > this.slideEndTime) { + this.stateManager.changeState(CharState.Idle); + } + // DashAttack 状态:更新惯性推进(如果处于 dash_attack 状态) + if (this.state === CharState.DashAttack) { + // 逐帧衰减水平速度 + console.log('this.sprite.body!.velocity.x', this.sprite.body!.velocity.x); + const newVelocityX = this.sprite.body!.velocity.x * this.dashAttackDeceleration + this.sprite.setVelocityX(newVelocityX); + } + // 非攻击、非 Slide、非 DashAttack状态下,处理移动输入 + else if (!this.isAttacking()) { + if (this.state !== CharState.Slide) { + // 当不处于 Slide 状态时,调用移动模块更新速度 + this.movement.handleMovementInput(time); + } + } else { + // 攻击、闪避期间禁止水平移动(DashAttack 状态单独处理) + this.sprite.setVelocityX(0); + } + if (this.bufferedAction) { + console.log('bufferedAction'); + const action = this.bufferedAction; + this.bufferedAction = null; + action(); + } + // 分别处理跳跃、攻击和闪避输入 + this.jump.handleJumpInput(time); + this.attack.handleAttackInput(); + this.handleSlideInput(time); + } + /** + * 处理闪避(Slide)输入:按下 Slide 键且冷却已结束时触发闪避, + * 在闪避期间赋予短暂无敌效果。 + */ + private handleSlideInput(time: number): void { + if (Phaser.Input.Keyboard.JustDown(this.slideKey)) { + if (this.state === CharState.Slide || this.isJumping() || this.isAttacking()) { + return + } + if (time >= this.lastSlideTime + this.slideCooldown) { + this.lastSlideTime = time; + this.stateManager.changeState(CharState.Slide); + // 根据角色朝向设置闪避水平速度 + this.sprite.setVelocityX(this.sprite.flipX ? -this.slideSpeed : this.slideSpeed); + this.slideEndTime = time + this.slideDuration; + // 设置无敌状态,并在 slideInvincibleDuration 后取消 + this.isInvincible = true; + this.scene.time.addEvent({ + delay: this.slideInvincibleDuration, + callback: () => { + this.isInvincible = false; + } + }); + } + } + } + public isJumping(): boolean { + return ( + this.state === CharState.Jump || + this.state === CharState.UpToFall || + this.state === CharState.Fall || + this.state === CharState.AirRun + ) + } + /** + * 辅助方法:判断当前是否处于攻击状态 + */ + public isAttacking(): boolean { + return ( + this.state === CharState.Attack1 || + this.state === CharState.Attack2 || + this.state === CharState.Attack3 || + this.state === CharState.DashAttack + ); + } + public bufferAction(action: () => void): void { + this.bufferedAction = action; + } } diff --git a/gamefi/app/components/controllers/PlayerAnimationManager.ts b/gamefi/app/components/controllers/PlayerAnimationManager.ts index a2656f8..4e23520 100644 --- a/gamefi/app/components/controllers/PlayerAnimationManager.ts +++ b/gamefi/app/components/controllers/PlayerAnimationManager.ts @@ -1,5 +1,5 @@ // PlayerAnimationManager.ts -import { PlayerController } from "./PlayerController"; +import { PlayerController } from "./Player/PlayerController"; import { CharState } from "./CharState"; import { BaseController } from "./BaseController"; export class PlayerAnimationManager { diff --git a/gamefi/app/components/controllers/PlayerAttack.ts b/gamefi/app/components/controllers/PlayerAttack.ts index a97587a..8940e20 100644 --- a/gamefi/app/components/controllers/PlayerAttack.ts +++ b/gamefi/app/components/controllers/PlayerAttack.ts @@ -1,6 +1,6 @@ // PlayerAttack.ts import Phaser from 'phaser'; -import { PlayerController } from './PlayerController'; +import { PlayerController } from './Player/PlayerController'; import { CharState } from './CharState'; import { BaseController } from './BaseController'; diff --git a/gamefi/app/components/controllers/PlayerController.ts b/gamefi/app/components/controllers/PlayerController.ts deleted file mode 100644 index 643c479..0000000 --- a/gamefi/app/components/controllers/PlayerController.ts +++ /dev/null @@ -1,365 +0,0 @@ -import Phaser from 'phaser'; -import { PlayerMovement } from './PlayerMovement'; -import { PlayerJump } from './PlayerJump'; -import { PlayerAttack } from './PlayerAttack'; -import { PlayerStateManager } from "./PlayerStateManager"; -import { PlayerAnimationManager } from "./PlayerAnimationManager"; -import { CharState } from './CharState'; - - -export interface PlayerConfig { - runSpeed?: number; // 普通移动速度(Run状态) - dashSpeed?: number; // 冲刺速度(Dash状态) - slideSpeed?: number; // 闪避时水平速度(Slide状态) - jumpVelocity?: number; // 起跳力度 - dashDuration?: number; // Dash 持续时间(毫秒) - doubleTapThreshold?: number; // 双击检测阈值(毫秒) - slideDuration?: number; // Slide 持续时间(毫秒) - slideCooldown?: number; // Slide 冷却时间(毫秒) - slideInvincibleDuration?: number; // Slide 无敌时长(毫秒) - animPrefix?: string; // 动画前缀,例如 'player' - hp?: number; // 初始血量 - scaleFactor?: number; // 精灵缩放因子 - coyoteTime?: number; // 离地后仍能跳跃的缓冲时间(毫秒),例如 150 - jumpCutMultiplier?: number; // 释放跳跃键后,减少上升速度的比例(0~1),例如 0.9 - debug?: boolean; // 是否输出调试信息 - // 新增 dashAttack 参数 - dashAttackInitialSpeed?: number; // DashAttack 初始速度(px/s) - dashAttackDeceleration?: number; // DashAttack 衰减系数(例如 0.95) -} - -export class PlayerController { - public sprite: Phaser.Physics.Arcade.Sprite; - public hp: number; - public isDead: boolean = false; - /** 在 Slide 等无敌期间为 true */ - public isInvincible: boolean = false; - - public state: CharState = CharState.Idle; - public scene: Phaser.Scene; - public animPrefix: string; - public debug: boolean; - - // 速度与物理参数 - public runSpeed: number; - public dashSpeed: number; - public slideSpeed: number; - public jumpVelocity: number; - // Dash 与 Slide 的持续时间、冷却等 - public dashDuration: number; - public doubleTapThreshold: number; - public slideDuration: number; - public slideCooldown: number; - public slideInvincibleDuration: number; - - // 定时器变量(存储结束时间) - public dashEndTime: number = 0; - public slideEndTime: number = 0; - public lastSlideTime: number = 0; - - // 跳跃相关:用于支持二段跳 - public doubleJumpUsed: boolean = false; - public coyoteTime: number; - public jumpCutMultiplier: number; - public lastGroundedTime: number = 0; - public runStartTime: number = 0; // 记录进入 Run 状态的开始时间 - public isAirRun: boolean = false; // 标记是否为空中跑动状态 - public airRunEligible: boolean = false;// 记录最后一次更新 airRunEligible 的时间(用于超时重置资格) - public airRunEligibleTime: number = 0; - - - // 输入按键 - public cursors: Phaser.Types.Input.Keyboard.CursorKeys; - public attackKey: Phaser.Input.Keyboard.Key; - public blockKey: Phaser.Input.Keyboard.Key; - public slideKey: Phaser.Input.Keyboard.Key; - public lastDirection: 'left' | 'right' = 'right'; - - // 用于左右双击检测(触发 Dash) - public lastTap: { left: number; right: number } = { left: 0, right: 0 }; - - // 攻击连击系统 - public nextAttackRequested: boolean = false; - public attackComboStep: number = 0; // 0->attack1, 1->attack2, 2->attack3 - public normalAttackAnimations: string[]; - // dashAttack 参数 - public dashAttackInitialSpeed: number; - public dashAttackDeceleration: number; - - public dashAttackAnimation: string; - - // 子模块 - public movement: PlayerMovement; - public jump: PlayerJump; - public attack: PlayerAttack; - - // 新增:状态与动画管理模块 - public stateManager: PlayerStateManager; - public animationManager: PlayerAnimationManager; - public bufferedAction: (() => void) | null = null; - constructor( - scene: Phaser.Scene, - x: number, - y: number, - texture: string, - config?: PlayerConfig - ) { - this.scene = scene; - this.animPrefix = config?.animPrefix ?? 'hero'; - this.hp = config?.hp ?? 100; - this.debug = config?.debug ?? false; - - // 配置参数(默认值) - this.runSpeed = config?.runSpeed ?? 150; - this.dashSpeed = config?.dashSpeed ?? 120; - this.slideSpeed = config?.slideSpeed ?? 300; - this.jumpVelocity = config?.jumpVelocity ?? -500; - this.dashDuration = config?.dashDuration ?? 250; - this.doubleTapThreshold = config?.doubleTapThreshold ?? 300; - this.slideDuration = config?.slideDuration ?? 500; - this.slideCooldown = config?.slideCooldown ?? 2000; - this.slideInvincibleDuration = config?.slideInvincibleDuration ?? 300; - // 离地缓冲和跳跃剪切 - const coyoteTimeDefault = 150; - const jumpCutMultiplierDefault = 0.9; - - this.coyoteTime = config?.coyoteTime ?? coyoteTimeDefault; - this.jumpCutMultiplier = config?.jumpCutMultiplier ?? jumpCutMultiplierDefault; - - // 新增属性,用于记录最近一次着地时间 - this.lastGroundedTime = 0; - - // 新增 dashAttack 参数 - this.dashAttackInitialSpeed = config?.dashAttackInitialSpeed ?? 700; - this.dashAttackDeceleration = config?.dashAttackDeceleration ?? 0.95; - - - // 创建精灵,并设置边界碰撞和缩放 - this.sprite = scene.physics.add.sprite(x, y, texture); - this.sprite.setCollideWorldBounds(true); - const scaleFactor = config?.scaleFactor ?? 2; - this.sprite.setScale(scaleFactor); - - // 注册输入 - this.cursors = scene.input.keyboard!.createCursorKeys(); - this.attackKey = scene.input.keyboard!.addKey(Phaser.Input.Keyboard.KeyCodes.F); - this.blockKey = scene.input.keyboard!.addKey(Phaser.Input.Keyboard.KeyCodes.D); - this.slideKey = scene.input.keyboard!.addKey(Phaser.Input.Keyboard.KeyCodes.SHIFT); - - // 设置攻击动画(连击)和 dash 攻击动画 - this.normalAttackAnimations = [ - `${this.animPrefix}-attack1`, - `${this.animPrefix}-attack2`, - `${this.animPrefix}-attack3` - ]; - this.dashAttackAnimation = `${this.animPrefix}-dash_attack`; - // 监听动画完成事件,用于处理攻击连击、dash_attack、slide 等状态结束 - // 初始化子模块 - this.movement = new PlayerMovement(this); - this.jump = new PlayerJump(this); - this.attack = new PlayerAttack(this); - - // 初始化状态与动画管理模块 - this.animationManager = new PlayerAnimationManager(this); - this.stateManager = new PlayerStateManager(this, this.animationManager); - - this.setupAnimationEvents(); - } - - /** - * 监听动画完成事件,根据动画完成时机处理攻击连击等状态切换 - */ - private setupAnimationEvents(): void { - this.sprite.on( - Phaser.Animations.Events.ANIMATION_COMPLETE, - (anim: Phaser.Animations.Animation) => { - // 处理普通攻击连击 - if ( - ((anim.key === this.normalAttackAnimations[0] && this.state === CharState.Attack1) || - (anim.key === this.normalAttackAnimations[1] && this.state === CharState.Attack2) || - (anim.key === this.normalAttackAnimations[2] && this.state === CharState.Attack3)) - ) { - if (this.nextAttackRequested && this.attackComboStep < 2) { - this.attackComboStep++; - if (this.attackComboStep === 1) { - this.stateManager.changeState(CharState.Attack2); - } else if (this.attackComboStep === 2) { - this.stateManager.changeState(CharState.Attack3); - } - this.nextAttackRequested = false; - } else { - // 连击结束后,根据是否有移动输入返回 Run 或 Idle 状态 - if (this.cursors.left?.isDown || this.cursors.right?.isDown) { - this.stateManager.changeState(CharState.Run); - } else { - this.stateManager.changeState(CharState.Idle); - } - this.attackComboStep = 0; - this.nextAttackRequested = false; - } - } - // Dash 攻击结束后 - else if (anim.key === this.dashAttackAnimation && this.state === CharState.DashAttack) { - if (this.nextAttackRequested) { - // 如果在 DashAttack 期间玩家请求了连击, - // 则切换到普通攻击连击的第2段 - this.stateManager.changeState(CharState.Attack2); - this.nextAttackRequested = false; - // 设置连击步数(例如从 1 开始) - this.attackComboStep = 1; - } else { - if (this.cursors.left?.isDown || this.cursors.right?.isDown) { - this.stateManager.changeState(CharState.Run); - } else { - this.stateManager.changeState(CharState.Idle); - } - } - } - // Slide 动作完成后 - else if (anim.key === `${this.animPrefix}-slide` && this.state === CharState.Slide) { - this.stateManager.changeState(CharState.Idle); - } - // 对于 up_to_fall,交由 update() 检测动画进度转换到 Fall 状态 - if (this.bufferedAction) { - const action = this.bufferedAction; - this.bufferedAction = null; - action(); - } - } - ); - } - - /** - * 辅助方法:如果当前精灵动画与目标动画不一致,则播放目标动画 - */ - public playAnimationIfNotPlaying(animKey: string): void { - if (this.sprite.anims.currentAnim && this.sprite.anims.currentAnim.key === animKey) return; - this.sprite.play(animKey, true); - if (this.debug) { - console.debug(`Playing animation: ${animKey}`); - } - } - /** - * 每帧调用,更新状态、检测输入、处理各状态之间的转换 - */ - public update(time: number, delta: number): void { - if (this.isDead) return; - - - // 跳跃阶段转换: - // 当处于 Jump(起跳)状态且垂直速度 >= 0 时转换到 UpToFall - if (this.state === CharState.Jump && this.sprite.body!.velocity.y >= 0) { - this.stateManager.changeState(CharState.UpToFall); - } - // 当处于 UpToFall 且动画播放完毕时转换到 Fall(下落) - else if (this.state === CharState.UpToFall) { - if (this.sprite.anims.currentAnim && this.sprite.anims.getProgress() >= 1) { - this.stateManager.changeState(CharState.Fall); - } - } - // 着地检测:当角色触地时,若处于跳跃状态则重置二段跳标记,并根据是否有水平输入切换到 Run 或 Idle - if (this.sprite.body!.blocked.down) { - if ( - this.state === CharState.Jump || - this.state === CharState.UpToFall || - this.state === CharState.Fall - ) { - this.doubleJumpUsed = false; - if (this.cursors.left?.isDown || this.cursors.right?.isDown) { - this.stateManager.changeState(CharState.Run); - } else { - this.stateManager.changeState(CharState.Idle); - } - } - } - - // Dash 状态:Dash 持续时间结束后恢复 Idle 状态(或根据需求调整为 Idle/Run) - if (this.state === CharState.Dash && time > this.dashEndTime) { - this.stateManager.changeState(CharState.Idle); - this.sprite.setVelocityX(0); - } - - // Slide 状态:Slide 结束后恢复 Idle - if (this.state === CharState.Slide && time > this.slideEndTime) { - this.stateManager.changeState(CharState.Idle); - } - - // DashAttack 状态:更新惯性推进(如果处于 dash_attack 状态) - if (this.state === CharState.DashAttack) { - // 逐帧衰减水平速度 - console.log('this.sprite.body!.velocity.x', this.sprite.body!.velocity.x); - const newVelocityX = this.sprite.body!.velocity.x * this.dashAttackDeceleration - this.sprite.setVelocityX(newVelocityX); - } - // 非攻击、非 Slide、非 DashAttack状态下,处理移动输入 - else if (!this.isAttacking()) { - if (this.state !== CharState.Slide) { - // 当不处于 Slide 状态时,调用移动模块更新速度 - this.movement.handleMovementInput(time); - } - } else { - // 攻击、闪避期间禁止水平移动(DashAttack 状态单独处理) - this.sprite.setVelocityX(0); - } - if (this.bufferedAction) { - console.log('bufferedAction'); - const action = this.bufferedAction; - this.bufferedAction = null; - action(); - } - // 分别处理跳跃、攻击和闪避输入 - this.jump.handleJumpInput(time); - this.attack.handleAttackInput(); - this.handleSlideInput(time); - } - - /** - * 处理闪避(Slide)输入:按下 Slide 键且冷却已结束时触发闪避, - * 在闪避期间赋予短暂无敌效果。 - */ - private handleSlideInput(time: number): void { - if (Phaser.Input.Keyboard.JustDown(this.slideKey)) { - if (this.state === CharState.Slide || this.isJumping() || this.isAttacking()) { - return - } - if (time >= this.lastSlideTime + this.slideCooldown) { - this.lastSlideTime = time; - this.stateManager.changeState(CharState.Slide); - // 根据角色朝向设置闪避水平速度 - this.sprite.setVelocityX(this.sprite.flipX ? -this.slideSpeed : this.slideSpeed); - this.slideEndTime = time + this.slideDuration; - // 设置无敌状态,并在 slideInvincibleDuration 后取消 - this.isInvincible = true; - this.scene.time.addEvent({ - delay: this.slideInvincibleDuration, - callback: () => { - this.isInvincible = false; - } - }); - } - } - } - public isJumping(): boolean { - return ( - this.state === CharState.Jump || - this.state === CharState.UpToFall || - this.state === CharState.Fall || - this.state === CharState.AirRun - ) - } - - /** - * 辅助方法:判断当前是否处于攻击状态 - */ - public isAttacking(): boolean { - return ( - this.state === CharState.Attack1 || - this.state === CharState.Attack2 || - this.state === CharState.Attack3 || - this.state === CharState.DashAttack - ); - } - public bufferAction(action: () => void): void { - this.bufferedAction = action; - } -} diff --git a/gamefi/app/components/controllers/PlayerJump.ts b/gamefi/app/components/controllers/PlayerJump.ts index a06a572..9833b1d 100644 --- a/gamefi/app/components/controllers/PlayerJump.ts +++ b/gamefi/app/components/controllers/PlayerJump.ts @@ -1,6 +1,6 @@ // PlayerJump.ts import Phaser from 'phaser'; -import { PlayerController } from './PlayerController'; +import { PlayerController } from './Player/PlayerController'; import { CharState } from './CharState'; import { BaseController } from './BaseController'; diff --git a/gamefi/app/components/controllers/PlayerMovement.ts b/gamefi/app/components/controllers/PlayerMovement.ts index 3bc107a..8bfe103 100644 --- a/gamefi/app/components/controllers/PlayerMovement.ts +++ b/gamefi/app/components/controllers/PlayerMovement.ts @@ -1,6 +1,6 @@ // PlayerMovement.ts import Phaser from 'phaser'; -import { PlayerController } from './PlayerController'; +import { PlayerController } from './Player/PlayerController'; import { CharState } from './CharState'; import { BaseController } from './BaseController'; diff --git a/gamefi/app/components/controllers/PlayerStateManager.ts b/gamefi/app/components/controllers/PlayerStateManager.ts index 44690e9..f4c9082 100644 --- a/gamefi/app/components/controllers/PlayerStateManager.ts +++ b/gamefi/app/components/controllers/PlayerStateManager.ts @@ -1,5 +1,5 @@ // PlayerStateManager.ts -import { PlayerController } from "./PlayerController"; +import { PlayerController } from "./Player/PlayerController"; import { PlayerAnimationManager } from "./PlayerAnimationManager"; import { CharState } from "./CharState"; import {BaseController } from "./BaseController"; diff --git a/gamefi/public/assets/vagabond/attack3/attack3.png b/gamefi/public/assets/vagabond/attack3/attack3.png new file mode 100644 index 0000000000000000000000000000000000000000..a7b72995949f6d460a4a7308c03ec4dad5422e75 GIT binary patch literal 2997 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 literal 0 HcmV?d00001 From 3424d34002470e2bd2fcf027f79814f7080eaa1c Mon Sep 17 00:00:00 2001 From: Yosgi Date: Sun, 16 Feb 2025 22:27:54 +1300 Subject: [PATCH 4/4] add blocking function --- gamefi/app/components/BattleScene.ts | 76 +++++++++--------- .../app/components/assets/HeroSpriteLoader.ts | 3 +- .../components/controllers/AI/AIController.ts | 4 +- .../components/controllers/BaseController.ts | 28 +++++-- .../app/components/controllers/CharState.ts | 2 +- .../controllers/Player/PlayerController.ts | 20 ++++- .../controllers/PlayerAnimationManager.ts | 2 +- gamefi/public/assets/hero/block/block.png | Bin 0 -> 1653 bytes 8 files changed, 83 insertions(+), 52 deletions(-) create mode 100644 gamefi/public/assets/hero/block/block.png diff --git a/gamefi/app/components/BattleScene.ts b/gamefi/app/components/BattleScene.ts index e63419a..9c37a1c 100644 --- a/gamefi/app/components/BattleScene.ts +++ b/gamefi/app/components/BattleScene.ts @@ -31,7 +31,7 @@ export class BattleScene extends Phaser.Scene { // 分别加载“player”资源 & “monster”资源 loadPlayerSpriteSheets(this, 'assets/hero', 'hero', { width: 64, height: 44 }); - loadVagabondMaterials(this, 'assets/vagabond', 'AI', { width: 64, height: 64 }); + // loadVagabondMaterials(this, 'assets/vagabond', 'AI', { width: 64, height: 64 }); } public create(): void { @@ -44,13 +44,13 @@ export class BattleScene extends Phaser.Scene { // 创建动画 (player / monster) createPlayerAnimations(this, 'hero'); - createVagabondAnimations(this, 'AI'); + // createVagabondAnimations(this, 'AI'); // ============ 创建玩家 ============ // 1) 用 PlayerController, 传入初始纹理 this.playerCtrl = new PlayerController(this, 100, 300, 'hero_idle'); this.playerSprite = this.playerCtrl.sprite as SpriteWithHP; - this.playerSprite.setScale(1); + this.playerSprite.setScale(1.5); this.playerSprite.hp = 100; this.playerSprite.setCollideWorldBounds(true); this.physics.add.collider(this.playerSprite, ground); @@ -63,40 +63,40 @@ export class BattleScene extends Phaser.Scene { // ============ 创建怪物 ============ // ============ 创建对手(怪物/AI) ============ - this.monsterCtrl = new AIController(this, 600, 300, 'AI_idle', { - hp: 100, - scaleFactor: 1.5, - debug: true, - // 可传入 AI 专用参数,如 dashAttackInitialSpeed、dashAttackDeceleration 等 - dashAttackInitialSpeed: 700, - dashAttackDeceleration: 0.95, - animPrefix: 'AI', - }); - this.monsterSprite = this.monsterCtrl.sprite as SpriteWithHP; - this.monsterSprite.hp = 100; - this.monsterSprite.setScale(1.5); - this.monsterSprite.setCollideWorldBounds(true); - this.physics.add.collider(this.monsterSprite, ground); - - this.monsterHpText = this.add.text(600, 20, `MONSTER HP: ${this.monsterSprite.hp}`, { - fontSize: '16px', - color: '#ffffff' - }); + // this.monsterCtrl = new AIController(this, 600, 300, 'AI_idle', { + // hp: 100, + // scaleFactor: 1.5, + // debug: true, + // // 可传入 AI 专用参数,如 dashAttackInitialSpeed、dashAttackDeceleration 等 + // dashAttackInitialSpeed: 700, + // dashAttackDeceleration: 0.95, + // animPrefix: 'AI', + // }); + // this.monsterSprite = this.monsterCtrl.sprite as SpriteWithHP; + // this.monsterSprite.hp = 100; + // this.monsterSprite.setScale(1.5); + // this.monsterSprite.setCollideWorldBounds(true); + // this.physics.add.collider(this.monsterSprite, ground); + + // this.monsterHpText = this.add.text(600, 20, `MONSTER HP: ${this.monsterSprite.hp}`, { + // fontSize: '16px', + // color: '#ffffff' + // }); // 播放 Idle 动画 this.playerSprite.play('hero-idle'); - this.monsterSprite.play('AI-idle'); + // this.monsterSprite.play('AI-idle'); } public update(time: number, delta: number): void { // 更新玩家 this.playerCtrl.update(time, delta); // 更新怪物 - this.monsterCtrl.update(time, delta); + // this.monsterCtrl.update(time, delta); // 刷新 HP 文本 this.playerHpText.setText(`PLAYER HP: ${this.playerSprite.hp}`); - this.monsterHpText.setText(`MONSTER HP: ${this.monsterSprite.hp}`); + // this.monsterHpText.setText(`MONSTER HP: ${this.monsterSprite.hp}`); // 如果你需要碰撞检测(攻击命中等),可以在这里 this.checkAttackCollision(); @@ -105,24 +105,20 @@ export class BattleScene extends Phaser.Scene { private checkAttackCollision(): void { - // 如果玩家正在攻击 - const attackStates = [ - CharState.Attack1, - CharState.Attack2, - CharState.Attack3, - CharState.DashAttack - ]; + const attackStates = [CharState.Attack1, CharState.Attack2, CharState.Attack3, CharState.DashAttack]; if (attackStates.includes(this.playerCtrl.state)) { - // 使用 Phaser.Physics.Arcade.overlap 检测玩家与怪物是否重叠 if (this.physics.overlap(this.playerSprite, this.monsterSprite)) { - // 根据双方位置确定击退方向 - const hitDirection = this.playerSprite.x < this.monsterSprite.x ? 'right' : 'left'; - // 调用 AI 角色的 onHit 方法,减少一定伤害(例如10) - this.monsterCtrl.onHit(10 / 100, hitDirection); + // 如果怪物处于 Blocking 状态,则触发弹反(仅对瞬间防御有效) + if (this.monsterCtrl.state === CharState.Blocking) { + this.monsterCtrl.onBlocked(this.playerCtrl); + console.log('Block! Player stunned.'); + } else { + // 否则正常受伤 + const hitDirection = this.playerSprite.x < this.monsterSprite.x ? 'right' : 'left'; + this.monsterCtrl.onHit(10, hitDirection); + } } } - // - } } @@ -136,7 +132,7 @@ export const config: Phaser.Types.Core.GameConfig = { default: 'arcade', arcade: { gravity: { x: 0, y: 1400 }, - debug: false + debug: true } }, scene: [BattleScene] diff --git a/gamefi/app/components/assets/HeroSpriteLoader.ts b/gamefi/app/components/assets/HeroSpriteLoader.ts index d867f77..32de9c7 100644 --- a/gamefi/app/components/assets/HeroSpriteLoader.ts +++ b/gamefi/app/components/assets/HeroSpriteLoader.ts @@ -17,7 +17,7 @@ export function loadPlayerSpriteSheets(scene: Phaser.Scene, const actions = [ 'attack1','attack2','attack3', 'crouch', 'dash', 'dash_attack', 'death', 'fall', 'hurt', - 'idle', 'jump', 'run', 'slide', 'up_to_fall', + 'idle', 'jump', 'run', 'slide', 'up_to_fall', 'block' ]; actions.forEach(action => { @@ -52,6 +52,7 @@ export function createPlayerAnimations(scene: Phaser.Scene, prefix = 'player') { 'jump': { frames: 3, frameRate: 8, repeat: 0 }, 'up_to_fall': { frames: 2, frameRate: 8, repeat: 0 }, 'slide': { frames: 5, frameRate: 10, repeat: 0 }, + 'block': { frames: 4, frameRate: 8, repeat: 0 }, }; Object.entries(animations).forEach(([key, { frames, frameRate, repeat }]) => { diff --git a/gamefi/app/components/controllers/AI/AIController.ts b/gamefi/app/components/controllers/AI/AIController.ts index 4c44d50..15b27f4 100644 --- a/gamefi/app/components/controllers/AI/AIController.ts +++ b/gamefi/app/components/controllers/AI/AIController.ts @@ -13,11 +13,11 @@ export class AIController extends BaseController { // 跳跃冷却(避免连续跳跃) public lastJumpTime: number = 0; - public jumpCooldown: number = 500; // 毫秒 + public jumpCooldown: number = 2500; // 毫秒 // 决策更新间隔与反应延迟 private lastDecisionTime: number = 0; - private decisionInterval: number = 150; // 每 150ms 更新一次决策 + private decisionInterval: number = 500; // 每 150ms 更新一次决策 private reactionDelay: number = 0; // 随机反应延迟(毫秒) private lastReactionTime: number = 0; diff --git a/gamefi/app/components/controllers/BaseController.ts b/gamefi/app/components/controllers/BaseController.ts index 9ef1a5e..c36ae31 100644 --- a/gamefi/app/components/controllers/BaseController.ts +++ b/gamefi/app/components/controllers/BaseController.ts @@ -73,6 +73,9 @@ export abstract class BaseController { // 输入缓冲(用于存储命令,在当前动作结束后执行) public bufferedAction: (() => void) | null = null; + public blockStartTime: number = 0; + public continuousBlock: boolean = false; + constructor( scene: Phaser.Scene, x: number, @@ -167,31 +170,31 @@ export abstract class BaseController { public onHit(damage: number, hitDirection: 'left' | 'right'): void { // 如果已经在受击状态,则不重复扣血 if (this.state === CharState.Hurt) return; - + this.hp -= damage; (this.sprite as any).hp = Math.floor(this.hp); - + if (this.hp <= 0) { this.die(); return; } - + this.stateManager.changeState(CharState.Hurt); this.playAnimationIfNotPlaying(`${this.animPrefix}-hurt`); - + const knockbackSpeed = 200; if (hitDirection === 'left') { this.sprite.setVelocityX(-knockbackSpeed); } else { this.sprite.setVelocityX(knockbackSpeed); } - + this.sprite.setTint(0xff0000); this.scene.time.delayedCall(200, () => { this.sprite.clearTint(); }); } - + /** * 当血量耗尽时调用,处理角色死亡 @@ -204,4 +207,17 @@ export abstract class BaseController { this.sprite.setVelocity(0); // 这里可以进一步处理死亡后的逻辑(例如重启关卡) } + + public onBlocked(attacker: BaseController): void { + // 只有瞬间防御(连续防御不触发弹反) + if (!this.continuousBlock) { + attacker.stateManager.changeState(CharState.Stunned); + attacker.sprite.setVelocity(0); + this.scene.time.delayedCall(1000, () => { + if (attacker.sprite.body!.blocked.down) { + attacker.stateManager.changeState(CharState.Idle); + } + }); + } + } } diff --git a/gamefi/app/components/controllers/CharState.ts b/gamefi/app/components/controllers/CharState.ts index acd1f7d..ccf12b0 100644 --- a/gamefi/app/components/controllers/CharState.ts +++ b/gamefi/app/components/controllers/CharState.ts @@ -11,7 +11,7 @@ export enum CharState { Attack2 = 'Attack2', Attack3 = 'Attack3', DashAttack = 'DashAttack', - Blocking = 'Blocking', + Blocking = 'Block', Slide = 'Slide', Stunned = 'Stunned', AirRun = 'AirRun', diff --git a/gamefi/app/components/controllers/Player/PlayerController.ts b/gamefi/app/components/controllers/Player/PlayerController.ts index a0d69d3..41ec18c 100644 --- a/gamefi/app/components/controllers/Player/PlayerController.ts +++ b/gamefi/app/components/controllers/Player/PlayerController.ts @@ -158,10 +158,27 @@ export class PlayerController extends BaseController { // 初始化状态与动画管理模块 this.animationManager = new PlayerAnimationManager(this); this.stateManager = new PlayerStateManager(this, this.animationManager); - + this.setupAnimationEvents(); } + private handleBlockInput(time: number): void { + // 如果刚按下防御键,则进入 Blocking 状态,并记录开始时间 + if (Phaser.Input.Keyboard.JustDown(this.blockKey) ) { + this.stateManager.changeState(CharState.Blocking); + this.blockStartTime = time; + this.continuousBlock = false; // 瞬间防御 + } + // 如果防御键一直按下,则标记为持续防御 + if (this.blockKey.isDown) { + this.continuousBlock = true; + } + // 如果防御键已释放且已进入 Blocking 状态,并且已超过 1 秒,则退出 Blocking 状态 + if (this.state === CharState.Blocking && !this.blockKey.isDown && time - this.blockStartTime >= 500) { + this.stateManager.changeState(CharState.Idle); + } + } + /** * 监听动画完成事件,根据动画完成时机处理攻击连击等状态切换 */ @@ -307,6 +324,7 @@ export class PlayerController extends BaseController { this.jump.handleJumpInput(time); this.attack.handleAttackInput(); this.handleSlideInput(time); + this.handleBlockInput(time); } /** diff --git a/gamefi/app/components/controllers/PlayerAnimationManager.ts b/gamefi/app/components/controllers/PlayerAnimationManager.ts index 4e23520..ee9b558 100644 --- a/gamefi/app/components/controllers/PlayerAnimationManager.ts +++ b/gamefi/app/components/controllers/PlayerAnimationManager.ts @@ -55,7 +55,7 @@ export class PlayerAnimationManager { this.controller.playAnimationIfNotPlaying(`${this.controller.animPrefix}-slide`); break; case CharState.Blocking: - this.controller.playAnimationIfNotPlaying(`${this.controller.animPrefix}-crouch`); + this.controller.playAnimationIfNotPlaying(`${this.controller.animPrefix}-block`); break; case CharState.Stunned: this.controller.playAnimationIfNotPlaying(`${this.controller.animPrefix}-hurt`); diff --git a/gamefi/public/assets/hero/block/block.png b/gamefi/public/assets/hero/block/block.png new file mode 100644 index 0000000000000000000000000000000000000000..4108cbae28d879c1c4471e965b3e763ab5822854 GIT binary patch literal 1653 zcmV-*28#KKP)Px*FG)l}RCr$PTyJQVRUAJ1(8$6+7zK$@4DE}n<;K1=bZHF(GcyD$ikcsaG!LlA~UpeRL|(3)j3vJcByIx(6ogRlrJ(JZ)rSUhL^Ud}z9_w|*%=e_TH ze!uf&ySsOH_j!KL^Zb72-1n|d$r1*H0k#a(u|+Pxg#lqeNdSllgaO73NB}S{zCafS zBmhJM!T@6iBmfu}U!V&E5&)tBVSq6M5&(>gFVKYn2>{W6Fu<4r2>`~$7wE!(1b}Ej z7+}nR1OVgW3v^*X0zfn%3@~Ou0)TPx1-dXG0U#O>1{gCS0l>KU0$mu801yob1B@Av z0AO5vfi4V40Eh;J0mckS05C4TKo1EA;x_znQUe`V)~`Dq~pKDj(y->m<+URCa_ zsNvyZ@4EC|cY1zT{cZfU3_$Nh7o7l~LP#<{2Lr_6U-#tA5$&BlBkHAtKkD1hcP`T* zFjN`xu1lYFPclF5v+Hy#L%~n$u?D6`#YFT`j075iCQthWL zT_2U;yT9A?_h0Wms`mEv>hJS5fe$^T#lNg&l`{38_XOn4XxBo37=VWXb{xB2d+pED zoAp=I{0kpziKc*11Hi_A%d8&NHuaC1PC&T^fQx`n2m6BS0CC~R#Q-k+7<;F7?N=?2 zf24+bZ*`h~UE7Kv#{V?>(MT?wF|#ANb6RE`5ypuIG$v0EC}@rwID@LUbAe!~o-CKaIX2 z8Q{X9714YCZ*~nt9>ElV{Xf;7?)dWAcKudh`{IYA-z#$nK>w})B>ZvPpYAOiat}Xm z0gyz1EdYHm7ElM^Y=FkbMs4CF+vaG0FL~=f{dNA?@Ac{Tsrmb=f)D1edumfvBR%|8 zf9^)eayl^U5B%--cc`%sUyn}z!2y=p0APMvd4`{t07y#!0iM@7TfdGncYw`Xw`t*j zyz@N`iwtn@nv?3L+Z$pHaBlk&HPp1a^ail;n}C2HCg_;=V3p|m2fm2)T~F5bJ4ha?$=TMW8&z%&VumdxN zps4`_pxyoRZU7SwfFuH%>zlO!-u-ru^S}cHzyNt3dSpEck^yY<}Ju$zlIzuhJ2 zF=gW-2|o;A9(0*gPiXj2KU)K){_W|H@Ygy3CmaBA9RT3ZRL(29(1!$Wis18&9|ZT| z55k#betHb>hjQJ!9jvzbm$oj_1~FF%_~QaFt^QH}S{{C9764}Ync&S101-TJW4$_k z`38k+{_k5fqV*7(2~6`7ejIkL+*M(L-!?z6V{yS>CjC!10PN(C1K;#dx4L7&pf&*3 z6U)a1QN}}`q-_M5AI8VRg+9QJ#R0#|{0pCHVuQbI`u7q5_MYEm04U<%rSSj=DFp08 zFT!pIK#2Hl^W*Sq|BI8N8k+$aB7R_UZT*U@|4akG?0$5Kt0{sc0fZ0&WB}^?bmC1W z2pPW}eAw>YwYX86p9B6l^A}zJnFfIC)EDoKW6@hYv<0v`z|N<~w+4^w`YF@blr*kq zd7o_nI_%_#AD4AM^hT$qmkWMiwHp95P;~s6nJvx$IO(M|>$-oh@Eo=QFhA`R%lgki zO#Jpc9USn}TVB9Q=EwIO>kr(dfuiHjBmnGv4~@PT`+rL`KTQE=4z)&)D`Nnd;s+3X zq!ml>^Qpgiy+@h!pGg2@IZDfO2?N4FehmB%@w@G5HENU*00000NkvXXu0mjf8rKY8 literal 0 HcmV?d00001