OOP游戏开发中Mediator模式的实现困惑求助
用Mediator模式实现捕食者-猎物交互逻辑
先修正现有代码的小问题:Human类继承了Organism的isStomachFull和stomachCapacity,无需重复定义,直接移除这两个属性即可。
接下来通过Mediator模式让游戏区域(GameArea)作为中介,统一处理Alien和Human的交互,具体实现步骤如下:
1. 完善基础生物类
给Organism添加位置属性用于距离检测,同时补充饱腹值相关逻辑:
export abstract class Organism { abstract maxHP: number; abstract currentHP: number; abstract canHit: boolean; // 新增位置属性,用于距离计算 x: number = 0; y: number = 0; isStomachFull = false; stomachCapacity = 100; currentStomach = 0; // 当前饱腹值,判断是否能继续进食 reduceHp() { if (this.currentHP > 0) { this.currentHP -= 1; } } recoverHp() { // 修正回血逻辑:当前血量小于最大血量时才回血 if (this.currentHP < this.maxHP) { this.currentHP += 1; } } // 新增进食方法,Alien通过这个方法增加饱腹值 eat(foodValue: number) { if (!this.isStomachFull) { this.currentStomach += foodValue; if (this.currentStomach >= this.stomachCapacity) { this.currentStomach = this.stomachCapacity; this.isStomachFull = true; } } } }
2. 定义中介者接口与实现
创建IGameMediator接口规范中介者行为,再实现GameArea作为具体中介者,负责管理所有生物并处理交互:
中介者接口
import { Organism } from './Organism'; export interface IGameMediator { registerOrganism(organism: Organism): void; update(): void; // 每帧更新,处理生物间交互 }
游戏区域(中介者实现)
import { IGameMediator } from './IGameMediator'; import { Organism } from './Organism'; import { Alien } from './Alien'; import { Human } from './Human'; export class GameArea implements IGameMediator { private organisms: Organism[] = []; private readonly eatRange = 5; // Alien的有效进食范围 registerOrganism(organism: Organism): void { this.organisms.push(organism); } update(): void { // 筛选出所有Alien和可食用的Human const aliens = this.organisms.filter(o => o instanceof Alien) as Alien[]; const eatableHumans = this.organisms.filter( o => o instanceof Human && (o as Human).isEatable && o.currentHP > 0 ) as Human[]; aliens.forEach(alien => { if (alien.isStomachFull) return; // 饱腹状态下不进食 eatableHumans.forEach(human => { // 计算两者之间的欧氏距离 const distance = Math.sqrt( Math.pow(alien.x - human.x, 2) + Math.pow(alien.y - human.y, 2) ); // 距离在进食范围内时触发交互 if (distance <= this.eatRange) { human.reduceHp(); alien.eat(10); // 每次进食增加10点饱腹值 console.log(`Alien进食!人类剩余血量:${human.currentHP},Alien饱腹值:${alien.currentStomach}`); } }); }); } }
3. 修正Alien与Human类
移除Human中重复定义的继承属性,保持代码简洁:
// Alien类无需修改,保持原有结构即可 import { Organism } from '../abstract/Organism'; export class Alien extends Organism { maxHP: number; currentHP: number; canHit: boolean; constructor(hp: number, canHit: boolean) { super(); this.maxHP = hp; this.canHit = canHit; this.currentHP = this.maxHP; } }
// 修正后的Human类 import { Organism } from '../abstract/Organism'; import { IEatable } from '../interface/IEatable'; export class Human extends Organism implements IEatable { maxHP: number; currentHP: number; canHit: boolean; isEatable: boolean; constructor(hp: number, canHit: boolean, isEatable: boolean) { super(); this.maxHP = hp; this.canHit = canHit; this.currentHP = this.maxHP; this.isEatable = isEatable; } }
4. 模拟游戏运行示例
import { GameArea } from './GameArea'; import { Alien } from './Alien'; import { Human } from './Human'; // 创建游戏中介者 const gameArea = new GameArea(); // 创建捕食者和猎物 const alien = new Alien(100, true); alien.x = 0; alien.y = 0; const human1 = new Human(20, false, true); human1.x = 3; // 距离Alien 3单位,在进食范围内 human1.y = 0; const human2 = new Human(20, false, true); human2.x = 10; // 距离Alien 10单位,超出进食范围 human2.y = 0; // 将生物注册到游戏区域 gameArea.registerOrganism(alien); gameArea.registerOrganism(human1); gameArea.registerOrganism(human2); // 模拟游戏循环,每秒更新一次 const gameLoop = setInterval(() => { gameArea.update(); if (human1.currentHP <= 0) { console.log('人类已死亡,停止模拟'); clearInterval(gameLoop); } }, 1000);
核心逻辑说明
- 中介者解耦:Alien和Human无需直接引用彼此,所有交互由
GameArea统一处理,降低了类之间的耦合度。 - 扩展性强:后续新增其他生物类型(如新型捕食者/猎物),只需修改
GameArea的update逻辑,无需改动现有生物类。 - 集中管理:所有交互逻辑集中在中介者中,便于维护和调试。
内容的提问来源于stack exchange,提问作者thewebjackal
相关产品推荐
相关产品推荐

