魔兽世界中的命令场景
笔者以前是个普通的魔兽世界玩家,每个魔兽世界玩家心中都比别人多一个世界。但同时笔者是一名程序员,经常又会在程序员的世界去思考游戏中各种场景是怎么实现的。今天心血来潮,准备使用“命令模式”为魔兽世界设计一套“技能释放”系统,包括:命令设计、宏命令、游戏外挂等具体实现过程。
在讲解命令模式之前,首先让我们来回味下魔兽世界中法师职业的技能:寒冰箭、火球术、奥术强化、气定神闲 等等,由于技能太多这里只列出4个技能。这些技能与普通游戏没什么两样,但魔兽世界的强大之处在于 可以让玩家根据自己的按键习惯,随意设置技能释放的快捷键。比如我个人的设置:数字键1--寒冰箭、数字键2--气定神闲、数字键3--奥术强化、数字键4--火球术等等。但另外一个玩家快捷键可能是:数字键1--寒冰箭、数字键2--气定神闲、字母键Q--奥术强化、字母键E--火球术等等。
这说明玩家的键盘和技能释放动作是完全解耦的,他们之间的桥梁就是每个技能释放动作都被封装为一个个命令,可以根据个人按键习惯随意设置。这其实就是命令模式的典型运用场景。今天我们就来自己设计下魔兽世界的“命令体系”,在此之前首先看下什么是命令模式。
命令模式介绍
命令模式的定义:将请求封装成对象,以便使用不同的请求、日志、队列等来参数化其他对象;命令模式也支持撤销操作。
以魔兽世界的“命令体系”为参照,定义中的“其他对象”就是键盘,“将请求封装成对象”这个对象就是命令对象,“请求”就是具体的技能释放动作。“命令对象”将“键盘”和“具体的技能释放动作”解耦。命令模式的类图如下:
如果把Client去掉,可以发现跟上一章讲的“适配器模式”类图是一样的,但二者的目的不一样导致最终的实现方式也不一样。命令模式的作用是把命令发出者和命令执行者的责任分开(解耦),而适配器模式的作用是转换接口。以魔兽世界的命令体系为例,命令把“键盘”和“具体的技能释放动作”分开,键盘不会去实现具体的技能。
魔兽世界的命令体系实现
在开始代码实现环节之前,首先以上述类图定义角色:
请求者角色:类图中的Invoker对应键盘类Keyboard;
命令接口角色:新建一个Command类与类图中的Command类对应;
具体的命令角色:新建一系列的命令实现类与类图中ConcreteCommand类对应:
接收着角色:新建一系列的“技能实现类”与类图中的Receiver对应。
下面是开始实现各个角色。
1、接受者角色
首先来看接收着角色,这里只模拟实现魔兽世界里法师技能列表中的4个技能:寒冰箭、气定神闲、奥术强化、火球术。
寒冰箭实现类Frostbolt,法师施放寒冰箭需要两秒的时间“吟唱咒语”,说得简单点就是“读条”,可以用一个线程来模拟。在释放技能“读条”期间,可以被打断(撤销)。具体实现如下:
/** * 寒冰箭操作类 * Created by gantianxing on 2017/11/6. */ public class Frostbolt { //释法线程 private Thread thread; //释放寒冰箭,具体实现 public void releaseSkill(){ if(this.getThread()!=null && this.getThread().isAlive()){ System.out.println("上一个释法正在进行中"); return; } //寒冰箭释放时长2秒 Thread thread = new Thread(new CastFrostbolt(2)); thread.start(); this.setThread(thread); } //打断 技能释放 public void cansel(){ if(this.getThread() !=null && this.getThread().isAlive()){ this.getThread().interrupt();//中断释法 }else { System.out.println("目前没有释放寒冰箭"); } } public Thread getThread() { return thread; } public void setThread(Thread thread) { this.thread = thread; } } /** * 模拟寒冰箭释放过程 * Created by gantianxing on 2017/11/6. */ public class CastFrostbolt implements Runnable{ private int time;//释法时长 public CastFrostbolt(int time) { this.time = time; } public void run() { System.out.println("+++开始释放寒冰箭+++"); System.out.println(time+"秒读条ing"); try { Thread.sleep(time*1000); System.out.println("+++完成释放寒冰箭+++"); System.out.println(" "); } catch (InterruptedException e) { //技能被取消 System.out.println("+++取消释放寒冰箭,读条结束+++"); System.out.println(" "); } } }
火球术实现类Fireball,法师施放火球术需要5秒的“读条”时间(记不太清了),也可以用一个线程来模拟。在释放技能“读条”期间,同样可以被打断(撤销)。具体实现与寒冰箭的实现类似,这里就不贴代码了,大家可以自行实现。
奥术强化实现类ArcanePower,该技能是瞬发技能,不需要读条,所有不会被打断(撤销)。实现比较简单:
public class ArcanePower { //释放奥术强化,具体实现 public void releaseSkill(){ System.out.println("释放:奥术强化,接下来30秒内的攻击 暴击率提高30%"); } }
气定神闲实现类PresenceOfMind,该技能同样是瞬发技能,不需要读条,所有也不会被打断(撤销)。该技能释放后的下一次“读条”技能 改为“瞬发”,所以需要记录状态:
public class PresenceOfMind { //是已经释放 气定神闲 private boolean isReleaseed = false; //释放气定神闲,具体实现 public void releaseSkill(){ this.setIsReleaseed(true); System.out.println("释放:气定神闲,接下来的一次读条技能变为瞬发"); } public boolean isReleaseed() { return isReleaseed; } public void setIsReleaseed(boolean isReleaseed) { this.isReleaseed = isReleaseed; } }
到这里,4个技能实现完毕。
2、命令接口角色
命令接口Command,只定义了一些统一的方法:
public interface Command { void execute();//执行命令 void undo();//撤销命令 }
3、具体的命令角色
具体命令角色实现了接口Command,是对上述4个具体的法师技能的封装。
寒冰箭命令类FrostboltCommand,封装寒冰箭技能施放:
public class FrostboltCommand implements Command { private Frostbolt frostbolt; public FrostboltCommand(Frostbolt frostbolt) { this.frostbolt = frostbolt; } public void execute() { frostbolt.releaseSkill(); } public void undo() { frostbolt.cansel(); } }
火球术命令类FireballCommand,与寒冰箭命令类 实现类似,这里就不贴出代码了。
奥术强化命令类ArcanePowerCommand,奥术强化技能cd时间为30秒,在技能cd期间无法使用该技能,这里使用一个线程模拟技能cd中,具体实现为:
public class ArcanePowerCommand implements Command { private static boolean cd = false;//技能是否进入cd private ArcanePower arcanePower; public ArcanePowerCommand(ArcanePower arcanePower) { this.arcanePower = arcanePower; } public void execute() { if(this.cd == false){ this.cd = true; arcanePower.releaseSkill(); //定时清除技能cd optCd(); }else { System.out.println("奥术强化技能cd中"); } } public void undo() { System.out.println("奥术强化 是瞬发技能,不能撤销"); } private void optCd(){ Thread thread = new Thread(new Runnable() { public void run() { try { Thread.sleep(30*1000);// 奥术强化cd时间 30秒 System.out.println("奥术强化cd结束"); ArcanePowerCommand.cd = false; } catch (InterruptedException e) { e.printStackTrace(); } } }); thread.start(); } }
气定神闲命令类PresenceOfMindCommand,该技能与奥术强化类似,技能cd时间同样为30秒,实现方式与ArcanePowerCommand类型,这里就不再贴出代码。
另外还有一个空命令实现类NoCommand,什么都不做,用于赋值给键盘上没有设置快捷键的按键。具体实现如下:
public class NoCommand implements Command{ public void execute() { } public void undo() { } }
4、请求者角色
这里的请求者角色,就是键盘Keyboard 。键盘的实现 主要完成上述5个命令的绑定,具体实现如下:
public class Keyboard { Command[] commands; //对应键盘上的10个数字键 0-9 Command undoCommand; //撤销按键,对应键盘上的空格键 public Keyboard() { commands = new Command[10]; //游戏刚开始没有设置快捷键,键盘上的这10个按键默认是空命令 Command noCommand = new NoCommand(); for (int i=0;i<10;i++){ commands[i] = noCommand; } } //为键盘上的指定按键 绑定命令 public void setCommand(int keyNum,Command command){ commands[keyNum] = command; } public void pushKeyNum(int keyNum){ commands[keyNum].execute(); undoCommand = commands[keyNum];//记录最近一次操作 } public void pushSpacekey(){ if(undoCommand != null){ undoCommand.undo(); } } }
到这里魔兽世界的“命令体系”设计和开发完成,下面可以开始玩游戏了。
游戏时间
在游戏开始前,玩家还需要按照各自习惯绑定下技能“命令”(当然真实的游戏中有默认按键设置),然后按下键盘上的指定按键,就可以开始“打怪”了。
public class Main { public static void main(String[] args) throws Exception{ //Step1 初始化技能 ArcanePower arcanePower = new ArcanePower();//奥术强化 PresenceOfMind presenceOfMind = new PresenceOfMind();//气定神闲 Frostbolt frostbolt = new Frostbolt();//寒冰箭 Fireball fireball = new Fireball(presenceOfMind);//火球术 //step2 初始化命令,对4个技能进行封装 ArcanePowerCommand arcanePowerCommand = new ArcanePowerCommand(arcanePower); PresenceOfMindCommand presenceOfMindCommand = new PresenceOfMindCommand(presenceOfMind); FrostboltCommand frostboltCommand = new FrostboltCommand(frostbolt); FireballCommand fireballCommand = new FireballCommand(fireball); //step3 初始化键盘,并为键盘绑定命令,玩家可以根据自己的喜好调整 命令位置 Keyboard keyboard = new Keyboard(); keyboard.setCommand(1,frostboltCommand);//按键1设置为寒冰箭命令 keyboard.setCommand(2,presenceOfMindCommand);//按键2设置为气定神闲命令 keyboard.setCommand(3,arcanePowerCommand);//按键3设置为奥术强化命令 keyboard.setCommand(4,fireballCommand);//按键4设置为火球术命令 //准备完毕,目前你我们只设置了4个快捷键,其他的就交个玩家自己去设置吧 //开始打boss啦 // 按1键 释放寒冰箭 keyboard.pushKeyNum(1); Thread.sleep(1999);//寒冰箭释法时长2秒 keyboard.pushKeyNum(1);//上一个释放还没有完成,再次释法无效 Thread.sleep(500);//按下一个键 人的反应时间,0.5秒 //按4键 释放火球术 keyboard.pushKeyNum(4); Thread.sleep(5000);//火球术释法时长5秒 Thread.sleep(500);//按下一个键 人的反应时间,0.5秒 } }
执行main方法,打印信息如下:
+++开始释放寒冰箭+++ 2秒读条ing 上一个释法正在进行中 +++完成释放寒冰箭+++ ---开始释放火球术--- 5秒读条ing ---完成火球术释放---
这次模拟分别施放了两次寒冰箭和一次次火球术,但有由于第一次寒冰箭,还没有施放结束,第二次施放没有成功。
火球术的伤害被寒冰箭高,但施法时间太长(读条),一般不会直接使用。但我们技能栏里,还有“气定神闲”技能。先施放“气定神闲”,再施法“火球术”就是瞬发(不用读条了),再加上“奥术强化”就更配了,这就是传说中的“气定 奥强 大火球”。具体操作如下(代码加在main方法后面):
//按1键 再次释放寒冰箭 keyboard.pushKeyNum(1); //0.5秒后 气定神闲和奥术强化cd时间到 Thread.sleep(500); keyboard.pushSpacekey();//取消寒冰箭 Thread.sleep(500); keyboard.pushKeyNum(2);//释放气定神闲 Thread.sleep(500); keyboard.pushKeyNum(3);//释放奥术强化 Thread.sleep(500); keyboard.pushKeyNum(4);//瞬发大火球 Thread.sleep(500); keyboard.pushKeyNum(2);//想再释放“气定神闲”还得等30秒cd
执行mian方法,打印信息如下:
+++开始释放寒冰箭+++ 2秒读条ing +++取消释放寒冰箭,读条结束+++ 释放:气定神闲,接下来的一次读条技能变为瞬发 释放:奥术强化,接下来30秒内的攻击 暴击率提高30% 瞬发火球术完成 气定神闲技能cd中 气定神闲cd结束 奥术强化cd结束
玩家在释放“寒冰箭”读条的过程中发现,气定神闲的cd结束,立即取消“寒冰箭”技能,开始释放“气定 奥强 大火球”组合技能。
这时玩家的操作顺序是,先按空格键 再依次按下2、3、4键。一次操作需要按4个键,对玩家手速是个巨大的考验,怎么办?别紧张“命令模式”中还有“宏命令”:
宏命令
所谓宏命令,就是把多个具体的动作放在一个命令中,动作发起者只需一个操作,就可以引发多个“接收者角色”执行多个动作。
在魔兽世界的场景中,就是玩家只需按下一个键,就可以完成“气定 奥强 大火球”的技能释放。下面来看宏命令的实现:
public class MacroCommand implements Command{ List<Command> commands = new ArrayList<Command>(); //添加命令 public void add(Command command){ commands.add(command); } //移除命令 public void remove(Command command){ commands.remove(command); } //批量执行命令 public void execute() { for(Command cmd : commands){ cmd.execute(); } } public void undo() { System.out.println("宏命令 暂不提供撤销功能"); } }
在main方法中,初始化宏命令,并放绑定到“数字键5”:
//宏命令初始化 MacroCommand macroCommand = new MacroCommand(); macroCommand.add(presenceOfMindCommand);//气定 macroCommand.add(arcanePowerCommand);//奥强 macroCommand.add(fireballCommand);//瞬发大火球 keyboard.setCommand(5,macroCommand);
气定、奥强的cd结束,玩家立即取消当前施法,再按下数字键5:
//按1键 再次释放寒冰箭 keyboard.pushKeyNum(1); //0.5秒后 气定神闲和奥术强化cd时间到 Thread.sleep(500); keyboard.pushSpacekey();//取消寒冰箭 keyboard.pushKeyNum(5);
执行mian方法,打印结果为:
+++开始释放寒冰箭+++ 2秒读条ing +++取消释放寒冰箭,读条结束+++ 释放:气定神闲,接下来的一次读条技能变为瞬发 释放:奥术强化,接下来30秒内的攻击 暴击率提高30% 瞬发火球术完成
游戏外挂
打boss的时候 一打就是好几分钟,一直不停的按键是件很累的事情。别紧张,我们可以开发一个游戏外挂(不影响游戏平衡的外挂)。针对某个boss的外挂需求是这样的:我们可以一直释放“寒冰箭”,有“气定”+“奥强”cd就使用瞬发“火球术”,在释放“寒冰箭”期间夹杂一些“火球术”,可以加深伤害。我们的外挂实现就是这样的:
int boss_blood = 10000;//boss初始血量 System.out.println("战斗开始"); //一次循环大约31秒 while (true){ //气定 奥强 cd结束,就使用宏命令"气定 奥强 大火球" keyboard.pushKeyNum(5); //一次循环 15.5秒,两次31秒。气定和奥强cd时间都是30秒 for(int j=0;j<2;j++){ for (int i = 0;i<4;i++){//4次寒冰箭 10秒 keyboard.pushKeyNum(1); Thread.sleep(2000);//寒冰箭释法时长2秒 Thread.sleep(500);//按下一个键 人的反应时间,0.5秒 } keyboard.pushKeyNum(4);//火球术释法时长5秒 Thread.sleep(5000);//寒冰箭释法时长2秒 Thread.sleep(500);//按下一个键 人的反应时间,0.5秒 } boss_blood = boss_blood - 2000; if(boss_blood <0){ System.out.println("boss被消灭,开始分装备啦"); break; } } }
执行main方法,打印信息如下:
战斗开始 释放:气定神闲,接下来的一次读条技能变为瞬发 释放:奥术强化,接下来30秒内的攻击 暴击率提高30% 瞬发火球术完成 +++开始释放寒冰箭+++ 2秒读条ing +++完成释放寒冰箭+++ //此处省略约3分钟的战斗画面 ---开始释放火球术--- 5秒读条ing 气定神闲cd结束 奥术强化cd结束 ---完成火球术释放--- boss被消灭,开始分装备啦
整个过程由外挂执行,玩家可以上个厕所休息下,3分钟后回来“分装备”就可以啦。
小结
各大游戏里的“命令体系”设计,就是“命令模式”的典型应用场景之一。学会了魔兽世界的“命令体系”设计,相信你也可以设计“英雄联盟”的命令了。
结合命令模式中的undo(撤销)操作,此模式还可以广泛用于其他场景:日志记录和恢复、以及事务处理等。具体就是在执行execute方法时 记录操作顺序和日志,在出现问题后,执行undo操作进行恢复。这里就不再展开讲解,可以自行实现。
本次总结 内容涉及太多魔兽世界游戏元素,对于魔兽世界玩家是一个福利。但对于没有玩过魔兽世界的朋友,要说声抱歉了。
出处:
相关推荐
.NET FrameWork 4.8 已经对Github上的最新版本进行调整,可以无错运行导入Spell App.Config配置数据链接及新建数据库名称 WoW-Spell-Editor-master |____Documentation BandingList对应dbc文件二进制字段列表,语言...
魔兽世界单机版GM命令详解 以下是魔兽世界单机版GM命令的详细解释: 1. GM综合指令: ...这篇文章详细介绍了魔兽世界单机版GM命令的使用方法和作用,这将有助于玩家更好地在游戏中使用GM命令,提高游戏体验。
在深入探讨WoWFailureCMS之前,我们首先要理解的是,魔兽世界(World of Warcraft,简称WoW)是一款由暴雪娱乐开发并发行的大型多人在线角色扮演游戏,自2004年发布以来,吸引了全球无数玩家的喜爱。WoWFailureCMS则...
这是魔兽世界终极版POJ的-测试数据,找了好久才找到的。 本来想设置为0积分,但是它居然自动收费(o_ _)ノ。 看传送门:https://pan.baidu.com/s/1cCIwW8psGDASu2JdZawG3Q
在魔兽世界(WoW)的玩家社区中,Addon(插件)是提升游戏体验的重要工具。Addonmanager则是管理这些插件的利器,尤其对于那些热衷于自定义游戏界面和功能的玩家来说,它提供了方便的管理和更新功能。Python-wowa魔兽...
在魔兽世界这款大型多人在线角色扮演游戏(MMORPG)中,"大芒果"通常指的是私人服务器,这些服务器由玩家自行搭建,可以提供与官方服务器不同的游戏体验。在这个特定的场景下,"GM"是“Game Master”的缩写,即游戏...
E.M 2D游戏开发引擎,上手容易轻松打造属于自己的游戏世界
数据库和DBC的中文说明详解.包含所有的文件全部中文详解,魔兽世界单机技术学习技术,全是干货。
wow魔兽世界-C,C++利用自写代码分析进入副本的功能
2. 主题更换:在Z-Blog后台,选择“外观”-“主题管理”,点击“上传新主题”,将“Z-Blog WOW魔兽世界”模版文件(即zblog16)上传并启用。这样,你的网站就会呈现出魔兽世界的特色设计。 二、模版特色 1. 魔兽...
"魔兽世界lua插件开发教程" 魔兽世界lua插件开发教程是一本关于使用lua语言开发魔兽世界插件的教程。这本书籍提供了从基础知识到高级技术的详细指导,旨在帮助读者快速掌握lua语言和魔兽世界插件开发的技能。 本...
在魔兽世界中,lua被广泛用于创建自定义的游戏插件,以扩展游戏功能、自动化任务、优化玩家体验等。该解释器的核心在于解析和执行lua脚本,使玩家能够编写自己的脚本来实现个性化需求。 lua是一种轻量级的、解释型...
在《魔兽争霸DOTA》这款经典的多人在线战斗游戏中,不同版本的命令大全提供了丰富的游戏模式和命令,以满足玩家多样化的竞技需求。本文将详细介绍其中的主要游戏模式和部分二级游戏模式,以及它们的特定命令。 首先...
电子书下载 : http://blog.csdn.net/good3651/article/details/53420721 -------阅读完本书,您将学会如何对魔兽世界界面进行自定义修改。如果您初学编程,将从本书学习到Lua和XML的基础知识,以及如何开始编写自己...
WowLua 是一个在魔兽世界里边运行 Lua 脚本的编辑工具环境,他功能包括: 交互式 Lua 解释器 多页脚本编辑器。 语法着色 输出重定向到 WowLua 的输出窗口 WowLua 的输出窗口 /wowlua 或 /lua 打开 WowLua。 /...
这个模板能够帮助设计师和开发者快速构建出富有魔兽世界元素的网页,使得用户在浏览时能够沉浸在游戏的世界观之中。 在设计上,【魔兽世界HTML模板】通常会包含以下关键要素: 1. **主题色彩**:借鉴魔兽世界游戏...
登陆器源码。C#。NEt 2008.比较简单的通用吗登陆器源码。C#。NEt 2008.比较简单的通用吗登陆器源码。C#。NEt 2008.比较简单的通用吗登陆器源码。C#。NEt 2008.比较简单的通用吗登陆器源码。C#。...
一个非常小的魔兽世界插件,在角色信息中的库存插槽上覆盖单个项目级别。 安装 下载,解压缩并将其放入您的Interface/AddOns目录中。 用法 您无需执行任何操作 - 它会自动运行。 贡献 分叉吧 创建您的功能分支( git...
在IT领域,尤其是游戏开发与服务器构建方面,魔兽世界服务端模拟器是一项引人入胜的技术挑战。本篇文章将深入探讨使用C#语言开发的魔兽世界服务端模拟器,帮助对魔兽服务器感兴趣的朋友们了解这一领域的核心技术和...