用Lua实现基于观察者模型的游戏成就系统
用Lua实现基于观察者模型的游戏成就系统
博主进入游戏开发行业一年多,希望在有空之余能多理解几种开发模型,并运用到实际项目中,为了督促自己,会时不时写下博客。这是开发模型系列的第一篇博客,也是博主本人的第一篇博客,有误之处还望指出。
简单说明
具体定义可以查看其他资料。简单的来说,观察者模型可以实现:事件的发生与相应功能的执行解耦。具体咱们通过下面的例子理解这句话到底是啥意思。
适用的地方
当初我同事是如此实现游戏的成就系统的:例如玩家在成功升级仙友时,我需要在相应的代码处调用他给我的接口,以此来告诉他仙友升级了。其实从逻辑上来讲是很通顺的,但是这样有个问题。同事还开发了每日任务系统,也就是说我必须也在仙友升级那里调用他给我的每日任务接口。这种方式是事件的发生主动去关联那些对这个事件感兴趣的操作。这样不大好,应该是对这个事件感兴趣的操作主动去关联这个事件。因为前者是一对多,后者是一对一。后者对开发人员更加友好。这就是开头说的事件的发生和功能的执行耦合度过高了。实现各个模块的解耦一直是我们开发追究的,所以在这里我们可以尝试用观察者模型来重构这成就系统。
开始愉快的撸代码啦
大致从观察者和被观察者(主题)两个方面讲
被观察者
首先我们需要定义先撸出我们的游戏的事件系统,我们让这个事件系统来管理被观察者。
--这个是我们的事件的枚举,我们就以三种事件为例
ENUM_GameEvent = {--仙友模块举例Xianyou_Lvl_Up = 1, --仙友升级事件Xianyou_Skill_Up = 2,--仙友技能升级事件Xianyou_Star_Up = 3,--仙友升星
}--这是上个table的反表
ENUM_GameEventInverse = {--仙友模块举例[1] = "Xianyou_Lvl_Up",[2] = "Xianyou_Skill_Up",[3] = "Xianyou_Star_Up",
}--初始化事件系统
function IGameEventSystem:Init( )CC.Print("init IGameEventSystem")self.gameEvents = {}
end--注册一个观察者
--enumGameEvent:事件名字, theKey:标记此观察者,为了更好的管理,theObserver:注册的观察者
function IGameEventSystem:RegisterObserver(enumGameEvent, theKey,theObserver) local subject = self:RegisterEvent(enumGameEvent)if subject thensubject:Attach({key = theKey,observer = theObserver})end
end--注册一个事件
function IGameEventSystem:RegisterEvent(enumGameEvent)if self.gameEvents[enumGameEvent] thenreturn self.gameEvents[enumGameEvent] --如果已经存在改事件就返回end local gameEventSubject = require "IGameEventSubject".IGameEventSubject:New()gameEventSubject:Init() --没有该事件,所以就为改事件生成一个主题if CC.ENUM.ENUM_GameEventInverse[enumGameEvent] thenself.gameEvents[enumGameEvent] = gameEventSubjectCC.Print("注册事件 " .. enumGameEvent)return gameEventSubjectelseCC.Print("还没有该事件的ENUM")end
end--事件发生,提醒注册改事件的observer更新
function IGameEventSystem:NotifySubject(enumGameEvent)if self.gameEvents[enumGameEvent] thenself.gameEvents[enumGameEvent]:Update()elseCC.Print("该事件没有注册")end
end
然后我们定义一个主题的类
--初始化事件主题
function IGameEventSubject:Init( )self.gameEventObservers = {}
end--在主题中加入一个观察者
function IGameEventSubject:Attach(tVal)if self.gameEventObservers[tVal.key] == nil thenself.gameEventObservers[tVal.key] = tVal.observerCC.Print("注册观察者 " .. tVal.key)end
end--移除一个观察者
function IGameEventSubject:Detach(key)self.gameEventObservers[key] = nil
end--通知主题下面的所有观察者更新
function IGameEventSubject:Update( )for k,v in CC.pairs(self.gameEventObservers) dov:Update()end
end
观察者
--初始化一个观察者
function IGameEventObserver:Init(tVal)self.key = tVal.key --改观察者的标记self.enumEvent = tVal.enumEvent --事件名称self.funcUpdate = tVal.funcUpdate --当被通知时所需要执行的函数igameEventSystem:RegisterObserver(tVal.enumEvent, tVal.key, self) -- 告诉事件系统,观察者的名字,对什么主题感兴趣
end--更新所需要执行的函数
function IGameEventObserver:Update( )if self.funcUpdate thenself.funcUpdate()end
end
成就系统(为了方便测试,把一些测试函数也写在了这里,并且和monoBehaviour绑定)
function AchievementSystem:Start( )CC.Print("observer begin")igameEventSystem:Init()self:C("Button"):Click("InitObserver")self:C("Button2"):Click("XianyouLvlup")self:C("Button3"):Click("SkillUp")
end--测试创建了三个个观察者,主分别是仙友升级和仙友技能升级
function AchievementSystem:InitObserver( )local xianyouLvlUpObserver = iGameEventObserver:New()xianyouLvlUpObserver:Init({enumEvent = CC.ENUM.ENUM_GameEvent.Xianyou_Lvl_Up,key = "achievementSystem_ob1",funcUpdate = function ( )--当这个func执行的时候,说明该主题已经更新(仙友已经升级),然后更新之后需要做的相关操作写在这里CC.Print("成就系统观察者捕捉到:仙友升级" )end})local xianyouSkillUpObserver1 = iGameEventObserver:New()xianyouSkillUpObserver1:Init({enumEvent = CC.ENUM.ENUM_GameEvent.Xianyou_Skill_Up,key = "achievementSystem_ob1",funcUpdate = function ( )--当这个func执行的时候,说明该主题已经更新(仙友技能已经升级),然后更新之后需要做的相关操作写在这里CC.Print("成就系统观察者1捕捉到:仙友技能升级" )end})local xianyouSkillUpObserver2 = iGameEventObserver:New()xianyouSkillUpObserver2:Init({enumEvent = CC.ENUM.ENUM_GameEvent.Xianyou_Skill_Up,key = "achievementSystem_ob2",funcUpdate = function ( )--当这个func执行的时候,说明该主题已经更新(仙友技能已经升级),然后更新之后需要做的相关操作写在这里CC.Print("成就系统观察者2捕捉到:仙友技能升级" )end})
end--模拟仙友升级了
function AchievementSystem:XianyouLvlup( )igameEventSystem:NotifySubject(CC.ENUM.ENUM_GameEvent.Xianyou_Lvl_Up)
end--模拟仙友技能升级了
function AchievementSystem:SkillUp( )igameEventSystem:NotifySubject(CC.ENUM.ENUM_GameEvent.Xianyou_Skill_Up)
end
现在让我们来测试
unity中创建3个按钮:注册观察者(一共有三个观察者), 仙友升级, 仙友技能升级
点击注册观察者:
点击仙友升级:
点击仙友技能升级:
总结一下
观察者模型在开发用到地方还是挺多的,具体是否用,用哪里,怎么用,我觉得需要程序猿自己把握了。在下认为开发模型固然重要,但是不能过分奉为圭臬。如果用了开发模型后,代码反而僵硬,这还不如不用。
用Lua实现基于观察者模型的游戏成就系统相关推荐
- 基于文法模型的中文纠错系统
基于文法模型的中文纠错系统 徐明 编译 论文地址:http://www.anthology.aclweb.org/W/W14/W14-6827.pdf 相关开源项目:https://github.co ...
- 毕设项目:基于BS模型的在线OJ系统
系列文章目录 文章目录 系列文章目录 前言 一.在线OJ系统描述 二.在线编译模块 1.搭建一个HTTP服务器完成在线编译 2.收到HTTP请求,进行数据格式转化(HTTP中body的内容转换为JSO ...
- Google Play游戏成就系统,7招搞定用户留存!
最近,谷歌Stadia平台的成就系统已经正式上线,用户使用电脑.电视和笔记本电脑进行Stadia游戏时可以得到实时成就获得通知,还可使用浏览器查看自己的成就解锁情况,完成度等信息. 对于这个新上线的& ...
- Google Play对游戏成就系统的要求和建议
Google Play对游戏提供成就系统的支持,开发者可以使用谷歌提供的成就系统,这样可以节省很多时间.在使用谷歌提供的成就系统中,具有一些要求和建议,想要使用谷歌成就系统的开发者可以详细了解下面的内 ...
- PHP怎么写游戏成就系统,游戏成就系统成就了什么
现年 25 岁的 Steven Rollins 是一家游戏网站的编辑.作为一名资深玩家,自打记事起,他就开启了自己的电子游戏生涯.小时候,他玩自己感兴趣的游戏,还和口味相投的小伙伴们彼此交换游戏,渐渐 ...
- 基于cocos2d-x引擎的游戏框架设计【转载】
http://www.cnblogs.com/lancidie/archive/2013/03/18/2965564.html 基于cocos2d-x引擎的游戏框架设计 移动互联网浪潮正在彻底改变人们 ...
- 学影视模型还是游戏模型更有前景?
选择影视模型还是游戏模型,同学们经常很纠结 到底学哪个课程更好呢?二者有没有互补? 回答这个问题之前,我们不妨先恶补些相关知识~ 游戏与影视模型有什么区别? 很多人都认为,模型无非就是模型,用不同的软 ...
- Pomelo:网易开源基于 Node.js 的游戏服务端框架
Pomelo 是基于 Node.js 的高性能.分布式游戏服务器框架.它包括基础的开发框架和相关的扩展组件(库和工具包),可以帮助你省去游戏开发枯燥中的重复劳动和底层逻辑的开发.Pomelo 不但适用 ...
- 基于java的俄罗斯方块游戏系统设计与实现(项目报告+答辩PPT+源代码+数据库+截图+部署视频)
基于Java的俄罗斯方块游戏的设计与实现 俄罗斯方块是一款风靡全球,从一开始到现在都一直经久不衰的电脑.手机.掌上游戏机产品,是一款游戏规则简单,但又不缺乏乐趣的简单经典小游戏,上手容易,适用范围广泛 ...
最新文章
- windows7 64位机上CUDA7.0配置及在VS2010中的简单使用举例
- 201406114331-黄智涛-OS 实验报告
- Wireshark如何选择多行
- 简单点儿、简单点儿、再简单点儿,其实世界可以不是我们想象的那么复杂
- 【webservice】Java JAX-WS和JAX-RS webservice
- Spring Boot 入门与实战笔记
- WPS for MacOS如何设置自动拼写检查
- C++自定义迭代器模板,实现ArrayList基本操作,自定义迭代器遍历
- 自定义的Spinner文字居中
- 微型计算机原理DL,微型计算机原理练习附解答.doc
- (转)移动互联加速金融科技的渗透 中国将成为全球最大智能投顾市场
- 湖南省对口升学c语言试题,湖南省对口升学计算机专业综合试卷试题.doc
- 车辆管理系统 c++
- Python基本数据类型字符串操作总结
- gogo protobuf
- STM IIC库函数
- 计算机算法的概念教案,高中信息技术 1.2 算法和算法的描述教案
- Python与人工神经网络(2)——使用神经网络识别手写图像
- 云计算介绍PPT2011-03版
- BSD是什么系统 BSD简介