之前在学习设计模式,很有感触,感觉之前写的代码真的是太挫了。于是就打算开发一个简单的RPG游戏练一练。

正所谓有了锤子看什么都像钉子,各个模块写之前都想一想能不能用一些设计模式来设计。

RPG游戏的战斗场景是RPG游戏关键的一个部分,其中涉及到很多复杂的状态转换,比如直接物理攻击,选择魔法攻击,使用物品。。。

如下图是我模仿《仙剑奇侠传》中的战斗场景,稍微简化了一点,比如使用物品只能使用药品,没有投掷道具的功能。

行动类型总体上包括三类:物理攻击、魔法攻击、使用物品,分别对应左下角的三个picturebox

战斗场景有明显的状态转换关系,比如,只有先点击物理攻击的按钮,才能选择攻击哪个敌人;点击魔法攻击后,需要先选择魔法,才能继续选择攻击哪个敌人。

状态转换图如下:

(图中少了两条线,一条从选择魔法状态指向选择敌人状态,一条相反,分别为选择魔法和返回)

状态比较复杂,如果按照传统的方式,每次需要判断当前的状态,需要使用很多if语句,如果需要加入新的状态,代码的扩展性不强,修改起来比较麻烦。

我考虑到可以使用状态模式来设计。

状态模式(State Pattern)是设计模式的一种,属于行为模式。

定义(源于Design Pattern):当一个对象的内在状态改变时允许改变其行为,这个对象看起来像是改变了其类。
状态模式主要解决的是当控制一个对象状态的条件表达式过于复杂时的情况。把状态的判断逻辑转移到表示不同状态的一系列类中,可以把复杂的判断逻辑简化。
意图:允许一个对象在其内部状态改变时改变它的行为
适用场景:
1.一个对象的行为取决于它的状态,并且它必须在运行时刻根据状态改变它的行为。
2.一个操作中含有庞大的多分支结构,并且这些分支决定于对象的状态。
(来自百度百科)

首先定义状态接口:

public interface State{void chooseAction(int action);void chooseMagic(Magic magic);//使用物品及使用药品void chooseDrug(Drug drug);void chooseEnemy(Fighter enemy);void choosePlayer(Player player);void goBack();}

五个子类继承State接口,分别为Start、ChooseMagic、ChooseDrug、ChooseEnemy、ChoosePlayer。

根据状态转换图,实现类中的函数,代码如下:

    public class Start:State{FightModel fightModel;public void chooseAction(int action){if (action == 0){fightModel.setState(fightModel.getCHOOSE_MAGIC());}else if (action == 1){fightModel.setState(fightModel.getCHOOSE_DRUG());}else if (action == 2){fightModel.setState(fightModel.getCHOOSE_ENEMY());}}public void chooseMagic(Magic magic){ }public void chooseDrug(Drug drug){ }public void chooseEnemy(Fighter fighter){ }public void choosePlayer(Player player){ }public void goBack(){ }}public class ChooseMagic : State{FightModel fightModel;public void chooseAction(int action){ }public void chooseMagic(Magic magic){fightModel.setChooseMagic(magic);if (magic.getAttackAll()){fightModel.getActionList().Add(new AttackNode(fightModel.getFightingPlayer(), magic.getID()));fightModel.setState(fightModel.getSTART());}else{fightModel.setState(fightModel.getCHOOSE_ENEMY());}}public void chooseDrug(Drug drug){ }public void chooseEnemy(Fighter fighter){ }public void choosePlayer(Player player){ }public void goBack(){fightModel.setState(fightModel.getSTART());}}public class ChooseDrug : State{FightModel fightModel;public void chooseAction(int action){ }public void chooseMagic(Magic magic){ }public void chooseDrug(Drug drug){fightModel.setChooseDrug(drug);fightModel.setState(fightModel.getCHOOSE_PLAYER());}public void chooseEnemy(Fighter fighter){ }public void choosePlayer(Player player){ }public void goBack(){fightModel.setState(fightModel.getSTART());}     }public class ChooseEnemy : State{FightModel fightModel;public void chooseAction(int action){ }public void chooseMagic(Magic magic){ }public void chooseDrug(Drug drug){ }public void chooseEnemy(Fighter enemy){fightModel.setAttackReceiver(enemy);fightModel.setState(fightModel.getSTART());int magicID;if (fightModel.getChooseMagic() != null){magicID = fightModel.getChooseMagic().getID();}else{magicID = -1;//普通攻击}fightModel.getActionList().Add(new AttackNode(fightModel.getFightingPlayer(), enemy, magicID));//保存信息后重新设置fightModel.setAttackReceiver(null);fightModel.setChooseDrug(null);fightModel.setChooseMagic(null);fightModel.setDrugReceiver(null);}public void choosePlayer(Player player){ }public void goBack(){if (fightModel.getChooseMagic() == null){fightModel.setState(fightModel.getSTART());}else{fightModel.setChooseMagic(null);fightModel.setState(fightModel.getCHOOSE_MAGIC());}}}public class ChoosePlayer : State{FightModel fightModel;public void chooseAction(int action){ }public void chooseMagic(Magic magic){ }public void chooseDrug(Drug drug){ }public void chooseEnemy(Fighter fighter){ }public void choosePlayer(Player player){fightModel.setDrugReceiver(player);fightModel.setState(fightModel.getSTART());fightModel.getActionList().Add(new TakeGrugNode(fightModel.getChooseDrug(), fightModel.getDrugReceiver()));//保存信息后重新设置fightModel.setAttackReceiver(null);fightModel.setChooseDrug(null);fightModel.setChooseMagic(null);fightModel.setDrugReceiver(null);}public void goBack(){fightModel.setState(fightModel.getCHOOSE_DRUG());fightModel.setChooseDrug(null);}}

这样在战斗时,根据具体的操作转换状态。状态图跟编译原理中的有限自动机的图有点类似。

如果不用状态模式设计也可以,但是将需要写大量的if语句,比如:(key指的是键盘的keycode,实际中我没使用鼠标点击,使用的是键盘的上下左右键来选择相应的操作)

if (fightModel.getState() == fightModel.getSTART()){if (key == "Left"){fightModel.redAction();}else if(key=="Right"){fightModel.addAction();}else if (key == "Up")//Up应该改为Enter{int action=fightModel.getAction();switch (action){case 0:if (fightModel.enemyList.Count < 2){fightModel.addAttackNode(fightModel.getFightingPlayer(), fightModel.enemyList[0], -1);//fightModel.setState(fightModel.getSTART());}else{fightModel.setState(fightModel.getCHOOSE_ENEMY());}break;case 1: fightModel.setState(fightModel.getCHOOSE_MAGIC());break;case 2:fightModel.setState(fightModel.getCHOOSE_DRUG());break;}}}else if (fightModel.getState() == fightModel.getCHOOSE_ENEMY()){if (key == "Left"){fightModel.redEnemy();}else if (key == "Right"){fightModel.addEnemy();}else if (key == "Up")//应该改为Enter{if (fightModel.getChooseMagic() == null){fightModel.addAttackNode(fightModel.getFightingPlayer(), fightModel.enemyList[fightModel.getEnemy()], -1);}else{fightModel.addAttackNode(fightModel.getFightingPlayer(), fightModel.enemyList[fightModel.getEnemy()], fightModel.getChooseMagic().getID());}fightModel.setAttackReceiver(fightModel.enemyList[fightModel.getEnemy()]);}}else if (fightModel.getState() == fightModel.getCHOOSE_MAGIC()){ //do something}else if (fightModel.getState() == fightModel.getCHOOSE_PLAYER()){//do something}else if (fightModel.getState() == fightModel.getCHOOSE_DRUG()){//do something}

如果状态不是很多,需要选择的动作也不多,其实也不需要使用设计模式,这样容易使简单问题复杂化。

文章有不正确的地方欢迎指正。

RPG游戏战斗场景的设计相关推荐

  1. 使用Wwise在3D RPG游戏中的声音设计思路

    使用Wwise在3D RPG游戏中的声音设计思路 https://blog.audiokinetic.com/zh/how-to-use-wwise-in-3d-rpg-game/ 大家好,随着Wwi ...

  2. RPG游戏-地图场景管理维护(服务器)

    (一)地图类 每个地图的管理需要保存在该地图的所有玩家信息以及他们的链接. using System; using System.Collections.Generic; using System.L ...

  3. 出海日本和美国市场的卡牌RPG,都是如何设计UI的?

    在日本和美国市场,卡牌RPG的UI设计有什么特点?和国内有什么不同之处?本文将设法找到一些专业的评价方式或者关注点,希望能为出海游戏的UI设计提供素材和建议. 1.1 研究背景 在我们接触的海外游戏的 ...

  4. 经典数值RPG游戏——《魔塔》调研报告

    目录 一.魔塔是什么? 二.游戏种类 三.世界观设定 四.核心要素--数值 五.为什么选择魔塔? 历史悠久,容易实现,可移植性强 素材来源丰富 ​编辑 容易实现 202031103199  李狄坤 2 ...

  5. c语言 rpg游戏,浅谈RPG游戏设计(一)

    Chapter:1什么是RPG游戏? 1.RPG游戏的定义 RPG全称为:Role Playing Game(角色扮演游戏),作为具有一定的情节.描述人物成长过程.表现事件始末的一种游戏,决定了角色扮 ...

  6. 《从零开始的RPG游戏制作教程》第三期:基础的数值设计

    目录 1. 前言 2. 第一期:制作基础场景 2. 第二期:让勇者和怪物登场 上期回顾 在[第二期:让勇者和怪物登场]中,我们已经制作了一个自定义的勇者克里夫. 很显然,相比我们先前所放置的怪物,我们 ...

  7. RPG游戏引擎的设计原理

    角色扮演游戏(RPG)是深受广大游戏迷们喜爱的一种游戏, 它以独特的互动性和故事性吸引了无数的玩家.它向人们提供了超出现实生活的广阔的虚拟世界,使人们能够尝试扮演不同的角色,去经历和体验各种不同的人生 ...

  8. 使用chatgpt设计了一个rpg游戏7万字的手稿

    引导句子 通过哪些方面去评价某个目标事件的好坏 通过哪些方面去评价游戏玩法的好坏 游戏玩法的好坏可以从下面几个方面来评价: 游戏平衡性:好的游戏玩法应该有良好的平衡性,意味着游戏中各种不同的玩法.角色 ...

  9. 游戏设计与计算机,RPG游戏设计与实现-数学与计算机系.doc

    RPG游戏设计与实现-数学与计算机系 XX学院 毕业论文(设计) RPG游戏设计与实现 院 系 :数学与计算机系专业(班级):计算机科学与技术专业2班姓名:XXX学号:20084011023指导教师: ...

最新文章

  1. VDI序曲二十一 APP-V 4.6 SP1服务器端部署
  2. ansible unarchive模块
  3. Web前端开发标准规范
  4. 根据实践经验,讲述些学习Java web能少走的弯路,内容摘自java web轻量级开发面试教程...
  5. 通讯接口应用笔记2:MAX3160实现多协议通讯
  6. 【C语言】在有序数组中插入一个数,保证它依然有序
  7. 计算机辅助翻译课怎么学的,计算机辅助翻译原理与实践
  8. 取得数组最大值与最小值
  9. asp程序ajax怎么写,ASP+AJAX+ACCESS数据库实例讲解三个步骤分享
  10. 特斯拉开始发布其汽车的开源Linux软件代码
  11. vue3.0脚手架搭建(vscode)
  12. 解决Ubuntu无法调节外接显示器亮度的问题
  13. 郑捷《机器学习算法原理与编程实践》学习笔记(第六章 神经网络初步)6.5 Boltzmann机算法...
  14. 电子印章系统基础“角色权限”分配攻略
  15. 【转】自己开发的iphone app打包为IPA包的方法
  16. 华为鸿蒙os和小米ov,稳了,华为鸿蒙手机 OS 发布!小米也能用?
  17. LeetCode 2315. 统计星号
  18. 利用php下载xls文件
  19. matlab 天空之城,matlab演奏天空之城
  20. C# (初入江湖)-几行代码也可以写个电脑屏保

热门文章

  1. PB中操作excel
  2. 使用Kali进行ARP断网攻击
  3. SAP BASIS ADM100 中文版 Unit 5(2)
  4. 编程找出1000以内的完数,完数是指一个数等于其他因子的和;并输出完数和它的因子;
  5. 前端自学笔记_json
  6. Android 蓝牙信号强度RSSI介绍
  7. linux卸载metasploit,Linux安装Metasploit
  8. view button 右边_【南华表白墙第30期】从体育馆后门往前数第二排右边第一个场的黑色衣服、裤子,扎马尾的小姐姐...
  9. L4操作系统(L4/Fiasco)
  10. 第二部分 实体、属性和关系