C#服务端的微信小游戏——多人在线角色扮演(七)
C#服务端的微信小游戏——多人在线角色扮演(七)
物以类聚,人以群分。游戏世界更是如此,合理的规划类的关系,对开发质量有很大的帮助。
——茂叔
小猫也来了,但是……
上一篇,我们实现了用
ObjectFactory来生成地图的内容——一只小狗。
那如果我们要生成一只小猫呢?是不是代码应该是这样的:
…… case ObjectClassID.DOG: { ret = new GameObject(LOGFUN) { Name = "小狗旺财", Description = "一只小狗,就是你", CanPass = false, ClassID = ClassID, Category = ObjectCategory.ANIMAL, ImgFileID = 0, ImgID = 0, Status = ObjectStatus.IDEL, StatusStep = 0, OwnerEID = null, Inventory = new GameObject[8]//可以带8个物品 }; } break; case ObjectClassID.CAT: { ret = new GameObject(LOGFUN) { Name = "小猫咪咪", Description = "一只小猫,好可爱", CanPass = false, ClassID = ClassID, Category = ObjectCategory.ANIMAL, ImgFileID = 0, ImgID = 2, Status = ObjectStatus.IDEL, StatusStep = 0, OwnerEID = null, Inventory = new GameObject[8]//可以带8个物品 }; } break; ……
拷贝粘贴,稍作修改,半分钟不到,一只小猫就实现了。然后再到地图内容清单那里加入一下就可以了。
继续添加草地、岩石也很容易实现。
小猫小狗心跳
HeartBeat应该也区别不大,跑跑跳跳见人就靠而已,但是小猫小狗和草地岩石,它们的心跳
HeartBeat会是差不多的么?
我们是不是也要在
GameObject的
HeartBeat里面去搞个又粗又长的
switch语句来分别实现他们的心跳呢?
这显然一点也不硬核。
地图内容分类
所以,我们需要从
GameObject派生出不同的类,来分别处理不同类型
Category的心跳。
我们先梳理一下游戏的需求,大致需要以下几类:
- 地形(Terrain),基本地图特征的元素,不可破坏和移动,这样可以使地图保持一个相对固定的环境,不至于三天不上线就找不到方向了。
- 角色(Character),可以移动、交互的元素,例如小猫小狗,包括玩家、NPC、动物等。
- 资源(Resource),可以进行采集的元素,比如树木、岩石,通过采集可以获得资源。
- 材料(Material),可以拾取使用的元素,如木材、石材等。
- 武器(Weapon),呵呵
- 防具(Armor),嘿嘿
- 药品(Herb),嘻嘻
- 货币(Currency),第五套人民币,除了不能提现,其他功能都一样
好吧,先这么多,其他以后想到再陆续添加。
我们注意到,材料、武器、防具、药品、货币这些,又可以归类于可携带(Carriable)元素,也就是可以被拾取、交易、使用或属于装备(Equip)类型的元素。
所以,我们计划建立以下类架构:
GameObject地形角色可携带资源NPC玩家动物材料装备武器防具药品货币树木岩石依据上图,我们修改
ObjectCategory的定义为:
public enum ObjectCategory : ushort { NONE = 0, TERRAIN = 1, CHARACTER = 2, PLAYER = 3, NPC = 4, ANIMAL = 5, CARRIABLE = 6, MATERIAL = 7, EQUIP = 8, WEAPON = 9, ARMOR = 10, HERB = 11, CURRENCY = 12, RESOURCE = 13, PLANT = 14, ROCK = 15 }
然后,分别新建类,其继承关系严格按照图片所示,具体类的成员可以暂时不管,等今后再来添加。只是在构造函数里面把
Catagory设置为相应的值。
为了防止命名冲突,我们统一使用Game作为类名的前缀。
class GameObject : Existence { public string Description; public ExistenceID MapEID; public sbyte X; public sbyte Y; public ObjectCategory Category; public ObjectClassID ClassID; public ObjectStatus Status; public byte StatusStep; public byte ImgFileID; public byte ImgID; public bool CanPass; public GameObject[] Inventory; public ExistenceID OwnerEID; public GameObject(Action<string> LOGFUN = null) : base(LOGFUN) { LOG("GameObject(" + EID + ")创建成功"); } public override void HeartBeat() { LOG("GameObject[" + Name + "](" + EID + ")正在心跳 " + G.GlobeTime); } } class GameTerrain : GameObject { public GameTerrain(Action<string> LOGFUN = null) : base(LOGFUN) { Category = ObjectCategory.TERRAIN; } } class GameCharacter : GameObject { public GameCharacter(Action<string> LOGFUN = null) : base(LOGFUN) { Category = ObjectCategory.CHARACTER; } } class GamePlayer : GameCharacter { public GamePlayer(Action<string> LOGFUN = null) : base(LOGFUN) { Category = ObjectCategory.PLAYER; } } class GameNPC : GameCharacter { public GameNPC(Action<string> LOGFUN = null) : base(LOGFUN) { Category = ObjectCategory.NPC; } } class GameAnimal : GameCharacter { public GameAnimal(Action<string> LOGFUN = null) : base(LOGFUN) { Category = ObjectCategory.ANIMAL; } } class GameCarriable : GameObject { public GameCarriable(Action<string> LOGFUN = null) : base(LOGFUN) { Category = ObjectCategory.CARRIABLE; } } class GameMaterial : GameCarriable { public GameMaterial(Action<string> LOGFUN = null) : base(LOGFUN) { Category = ObjectCategory.MATERIAL; } } class GameEquip : GameCarriable { public GameEquip(Action<string> LOGFUN = null) : base(LOGFUN) { Category = ObjectCategory.EQUIP; } } class GameWeapon : GameEquip { public GameWeapon(Action<string> LOGFUN = null) : base(LOGFUN) { Category = ObjectCategory.WEAPON; } } class GameArmor : GameEquip { public GameArmor(Action<string> LOGFUN = null) : base(LOGFUN) { Category = ObjectCategory.ARMOR; } } class GameHerb : GameCarriable { public GameHerb(Action<string> LOGFUN = null) : base(LOGFUN) { Category = ObjectCategory.HERB; } } class GameCurrency : GameCarriable { public GameCurrency(Action<string> LOGFUN = null) : base(LOGFUN) { Category = ObjectCategory.CURRENCY; } } class GameResource : GameObject { public GameResource(Action<string> LOGFUN = null) : base(LOGFUN) { Category = ObjectCategory.RESOURCE; } } class GamePlant : GameResource { public GamePlant(Action<string> LOGFUN = null) : base(LOGFUN) { Category = ObjectCategory.PLANT; } } class GameRock : GameResource { public GameRock(Action<string> LOGFUN = null) : base(LOGFUN) { Category = ObjectCategory.ROCK; } }
好,建好以后,都在一个文件
GameObject.cs里面,这样一目了然。将来需要细化的时候,再来移动到单独的文件里面。
走两步试试?
现在,我们先把
GameCharacter拿出来,选中类名,按alt+enter调出菜单,选择移动到新文件。然后把它的子类
GamePlayer
GameNPC
GameAnimal也移到同一个文件里。
然后给
GameCharacter加上一个方法
Move(Direction dir)。
其中
Direction定义如下:
public enum Direction : byte { NONE = 0, EAST = 1, WEST = 2, NORTH = 3, SOUTH = 4 }
记住要写在
Type.cs里面哦。
Move(Direction dir)的代码也很简单:
public void Move(Direction dir) { switch (dir) { case Direction.NONE: break; case Direction.EAST: X++; break; case Direction.WEST: X--; break; case Direction.NORTH: Y--; break; case Direction.SOUTH: Y++; break; default: break; } }
接下来,我们把
GameAnimal类也移到单独的文件里,并且覆盖(
Override)
GameAnimal类的
HeartBeat让它随机移动:
public override void HeartBeat() { base.HeartBeat(); Direction dir = (Direction)G.RND((int)Direction.EAST, (int)Direction.SOUTH); Move(dir); LOG(Name + " 向 " + dir.ToString() + " 走去。当前坐标(" + X + ":" + Y + ")"); }
把
ObjectFactory创建小狗的相关代码修改一下,直接创建一个
GameAnimal类:
…… case ObjectClassID.DOG: { ret = new GameAnimal(LOGFUN)//这里原来是GameObject { Name = "小狗旺财", ……
调试一下,看,我们的小狗可以移动了。
不过仔细一看,一秒钟跑了10次……太快了吧~!
如果我们注释掉其他无关的心跳日志,你会看到它一秒钟起码跑40几次,如果跑不到40次以上,你的电脑该换一台了……
更要命的是,不可能所有的角色都是一个速度,乌龟不可能比兔子慢啊!
速度,必须可控~!
控制速度的算法
给
GameCharacter加上一些内容:
…… public byte Speed = 128; private byte SpeedBuff = 0; public bool IsHeartReady { get { if (Speed + SpeedBuff == 255) return true; else return false; } } public override void HeartBeat() { if (Speed + SpeedBuff == 255) { SpeedBuff = 0; base.HeartBeat(); } SpeedBuff++; } ……
这是通过
SpeedBuff不断增加,直到与
Speed加起来等于255,这样的算法,使得
Speed可以取值0-255以控制速度,数值越大越快(达到255)。
再修改
GameAnimal的
HeartBeat:
public override void HeartBeat() { base.HeartBeat(); if (IsHeartReady) { Direction dir = (Direction)G.RND((int)Direction.EAST, (int)Direction.SOUTH); Move(dir); LOG(Name + " 向 " + dir.ToString() + " 走去。当前坐标(" + X + ":" + Y + ")"); } }
注意,凡是
GameCharacter的派生类,都需要判断’IsHeartReady’才能进行心跳。
这样,通过调整
GameCharacter的
Speed,就可以控制每个角色的
HeartBeat速度了。
好了,把小猫也加到地图清单里面去,这个应该人人都能自己搞定吧……修改
GameWorld的构造函数:
public GameWorld(Action<string> LOGFUN = null) : base(LOGFUN) { gMaps = new List<GameMap>(); LOG("GameWorld(" + EID + ")创建成功"); GameMap Map = new GameMap(LOG); Map.MapItems.Add(new MapItem() { ClassID = ObjectClassID.DOG, X = 1, Y = 1 } ); Map.MapItems.Add(new MapItem() { ClassID = ObjectClassID.CAT, X = 1, Y = 2 } ); Map.Refresh(); gMaps.Add(Map); }
把
ObjectFactory关于小猫小狗的部分修改成下面这样,注意小猫速度不同。
case ObjectClassID.DOG: { ret = new GameAnimal(LOGFUN) { Name = "小狗旺财", Description = "一只小狗,就是你", CanPass = false, ClassID = ClassID, ImgFileID = 0, ImgID = 0, Status = ObjectStatus.IDEL, StatusStep = 0, OwnerEID = null, Inventory = new GameObject[8]//可以带8个物品 }; } break; case ObjectClassID.CAT: { ret = new GameAnimal(LOGFUN) { Name = "小猫咪咪", Speed = 60, Description = "一只小猫,好可爱", CanPass = false, ClassID = ClassID, ImgFileID = 0, ImgID = 2, Status = ObjectStatus.IDEL, StatusStep = 0, OwnerEID = null, Inventory = new GameObject[8]//可以带8个物品 }; } break;
(很简单吧,下次添加类似代码大家自己搞吧,贴代码太占篇幅了)
然后调试一个看看:
效果好极了,这一篇我们把地图内容的实现梳理了一个框架出来,在这个框架内添加和实现更多的功能就比较容易了,下一篇,我们要讨论一下移动与地图的关系,让走位更加风骚~!
上一篇:C#服务端的微信小游戏——多人在线角色扮演(六)
下一篇:C#服务端的微信小游戏——多人在线角色扮演(八)
请用微信扫描查看游戏效果演示
- C#服务端的微信小游戏——多人在线角色扮演(一)
- C#服务端的微信小游戏——多人在线角色扮演(十二)
- C#微信小程序服务端获取用户解密信息
- 用c#开发微信(5)自定义菜单设置工具 (在线创建)
- [原创]用C#实现微信“跳一跳”小游戏的自动跳跃助手
- C#实现微信跳一跳小游戏的自动跳跃助手开发实战
- 微信移动支付V3开发详细教程服务端采用.net mvc webapi(C#)
- C#微信小程序服务端获取用户解密信息实例代码
- 微信移动支付V3开发详细教程服务端采用.net mvc webapi(C#)
- C#微信小程序服务端获取用户解密信息
- 用c#开发微信(5)自定义菜单设置工具 (在线创建)
- C#微信小程序服务端获取用户解密信息
- 基于控制台的多人在线角色扮演游戏(类似MUD)项目
- c# WINFORM SOCKET编程-简单聊天程序(服务端)(转载)
- 微信小游戏学习笔记2(脚本)
- 微软BI 之SSAS 系列 - 实现Cube 以及角色扮演维度,度量值格式化和计算成员的创建
- 理解C# 3.0新特性之Extension方法浅议开发者在线 Builder.com.cn 更新时间:2008-07-19作者: 来源:
- [扮演不同的角色 知道不同的成就]2008.06.20 黄桃西米露
- [置顶] 【java web spring mvc】服务端 微信支付+微信异步通知【精】
- 【C#】纯托管实现一个Git服务端