游戏角色开发
本课属于 Coddy PHP 学习旅程的“面向对象编程”单元。第 90 课,共 91 课。
挑战
简单让我们构建一个游戏角色成长系统,让不同角色职业使用独特技能进行战斗。你将创建一个包含经验值和升级系统的角色层级结构,展示继承、接口、trait 和封装如何在游戏中协同工作。
你将把代码分布在 6 个文件中:
Ability.php:定义一个Ability接口,包含两个方法:getName(): string和use(Character $target): string。这个契约可以确保所有技能都能以一致的方式使用,而不受其具体效果影响。CombatLogger.php:创建一个CombatLoggertrait,其中提供一个logAction(string $action): string方法。此方法应返回前缀为"[COMBAT] "的动作字符串。角色将使用这个 trait,以一致的格式生成战斗消息。Character.php:引入 Ability 和 CombatLogger 文件。创建一个使用CombatLoggertrait 的抽象Character类。使用构造函数属性提升来声明name(string,public readonly)。添加私有属性:health(int,初始值为 100)、level(int,初始值为 1)和experience(int,初始值为 0)。实现以下内容:getHealth(): int和getLevel(): int:获取私有属性的 gettertakeDamage(int $amount): void:减少生命值,但不会低于 0heal(int $amount): void:增加生命值,但不会高于 100gainExperience(int $xp): string:增加经验值;如果经验值达到或超过 100,则升级(将经验值重置为 0,等级加 1,恢复 20 HP),并返回"[name] leveled up to [level]!";否则返回"[name] gained [xp] XP"isAlive(): bool:如果生命值大于 0,则返回 trueabstract getSpecialAbility(): Ability:每种角色类型都提供自己的独特技能attack(Character $target): string:对目标造成 10 点伤害,并使用logAction()返回"[COMBAT] [name] attacks [target name] for 10 damage"
Warrior.php:引入 Character 文件。创建一个继承Character的Warrior类。实现getSpecialAbility(),使其返回一个实现Ability的匿名类:getName()返回"Shield Bash"use()造成 25 点伤害,并返回"[COMBAT] Shield Bash hits [target name] for 25 damage!"(使用 trait 的logAction())
Mage.php:引入 Character 文件。创建一个继承Character的Mage类。实现getSpecialAbility(),使其返回一个实现Ability的匿名类:getName()返回"Fireball"use()造成 35 点伤害,并返回"[COMBAT] Fireball engulfs [target name] for 35 damage!"
main.php:引入 Warrior 和 Mage 文件。你将收到两个输入:角色数据(JSON)和一系列战斗动作(JSON)。角色 JSON 格式:
[{"type": "warrior", "name": "Thorin"}, {"type": "mage", "name": "Gandalf"}]动作 JSON 格式:
[{"action": "attack", "attacker": 0, "target": 1}, {"action": "special", "attacker": 1, "target": 0}, {"action": "xp", "character": 0, "amount": 100}, {"action": "status", "character": 0}]创建所有角色,并将它们存储在一个数组中(索引为 0、1 等)。处理每个动作:
"attack":索引为 attacker 的角色攻击目标;打印结果"special":角色对目标使用特殊技能;打印结果"xp":角色获得经验值;打印结果"heal":角色按给定数量恢复生命值;打印"[name] healed to [health] HP""status":打印"[name] - Level [level], HP: [health], Alive: [Yes/No]"
将每个结果打印在新的一行。
这个系统展示了抽象类如何定义角色的共同行为,接口如何确保技能遵循一致的契约,trait 如何提供可复用的日志记录功能,以及匿名类如何创建独特的技能实现,而不让只使用一次的类弄乱你的代码库。
亲手试试
<?php
require_once 'Warrior.php';
require_once 'Mage.php';
// 读取输入
$charactersJson = trim(fgets(STDIN));
$actionsJson = trim(fgets(STDIN));
// 解析 JSON 输入
$charactersData = (array)json_decode($charactersJson, true);
$actionsData = (array)json_decode($actionsJson, true);
// TODO:创建一个数组来存储角色对象
$characters = [];
// TODO:遍历 $charactersData,创建 Warrior 或 Mage 对象
// 根据 "type" 字段,将它们存入 $characters 数组
// TODO:处理 $actionsData 中的每个操作
// 处理以下操作类型:
// “attack”:攻击者索引对应的角色攻击目标;输出结果
// “special”:角色对目标使用 getSpecialAbility()->use();输出结果
// “xp”:角色获得经验值;输出结果
// “heal”:角色恢复生命值;输出 "[name] healed to [health] HP"
// “status”:输出 "[name] - Level [level], HP: [health], Alive: [Yes/No]"
?>面向对象编程中的所有课
自己练习: PHP 在线编译器