cocos2d-x开发: 场景实体(entity)管理
公司现在开新项目,主题的框架部分都是我自己在做,不用受到别人的牵制,所以还算是比较的自由,很好发挥. 游戏并不大,所以需要用到的地方并不多.今天花了一些时间写了场景entity管理的部分代码,还没有完全的完善.
我的思路是这样的, entity manager提供注册一个update( dt )的帧频回调事件, 在每一次回调的时候都会遍历管理的所有的entity,调用entity的update( dt )帧频回调.何为帧频回调?我解释一下,cocos2d-x在c++那边是可以重写onDraw()方法实现的.在lua这边的话,如果是从cocos2d::node派生的子类,也就是使用 node = class( "node", function() return cc.Node:create() end),然后也可以注册schedulexxxx系列的方法,具体的可以去参考源码.由于我的管理类和entity都不是node派生的,所以我在提供了管理类的update( dt )回调,通过cc.Director:getInstance():getScheduler(),然后调用scheduler:scheduleScripteFunc( function(dt) end,0,false )方式实现的.
管理类的源码如下:
local entity_manager = class( "entity_manager", nil ) function entity_manager:ctor()
self.entity_list_ = {}
self.entity_nums_ =
end function entity_manager:register_entity( entity )
if entity == nil then
return
end local entity_rd
entity_rd = self.entity_nums_ +
entity:set_runtime_id( entity_rd ) table.insert( self.entity_list_, entity )
self.entity_nums_ = entity_rd
end function entity_manager:remove_entity( entity )
if entity == nil then
return
end local entity_rd
entity_rd = entity:get_runtime_rd() if entity_rd > self.entity_nums_ then
return
end
entity:remove_from_node()
table.remove( self.entity_list_, entity_rd )
for index, v_t in ipairs( self.entity_list_ ) do
if index >= entity_rd then
v_t:set_runtime_id( index )
end
end
self.entity_nums_ = #self.entity_list_
end function entity_manager:update( dt )
for _, v_t in ipairs( self.entity_list_ ) do
v_t:update( dt )
end
end return entity_manager
提供一个概念就是runtime entity id, 我们不能保证一个类型只可以创建一个对象,这是不合理的,所以除了entity的uniqure_id之外,就提供了运行时候的id。由于这个运行时候的id是动态的,所以在remove的时候需要更新一下,也就是上面table.remove下面的操作。下面是entity的代码:
local entity = class( "entity", nil ) entity.debug_mode_ = true
entity.debug_color_ = cc.c4f( , , , )
entity.callback_list_ = {}
entity.runtime_id_ = nil function entity:set_debug_mode( mode )
self.debug_mode_ = mode
end function entity:get_debug_mode()
return self.debug_mode_
end function entity:set_debug_color( color )
self.debug_color_ = color
end function entity:get_debug_color()
return self.debug_color_
end function entity:set_runtime_id( runtime_id )
self.runtime_id_ = runtime_id
end function entity:get_runtime_id()
return self.runtime_id_
end function entity:register_callback( callback, target )
if callback == nil then
return
end for _, v_t in ipairs( self.callback_list_ ) do
if v_t[] == callback and v_t[] == target then
return
end
end table.insert( self.callback_list_, { callback, target } )
end function entity:remove_callback( callback, target )
if callback == nil then
return
end for index, v_t in ipairs( self.callback_list_ ) do
if v_t[] == callback and v_t[] == target then
table.remove( self.callback_list_, index )
end
end
end function entity:update( dt )
local callback
local target
for _, v_t in ipairs( self.callback_list_ ) do
callback = v_t[]
target = v_t[]
if target ~= nil then
callback( target, dt )
else
callback( dt )
end
end
end return entity
这是一个基类的实现,不算复杂,也很好理解,就没什么好说的了.为什么要写一个entity base类呢? 因为现在的项目可能会用序列帧,也可能会用骨骼动画. 如果是骨骼动画的话,那么所有的action都比较好处理, bounding_box也很好获得.相应的接口就是
armature:getAnimation():play( action_const_name ) local bounding_box = armature:getBoundingBox()
然后就可以很简单的使用AABB或者是OBB进行碰撞检测以及设置AI等这些杂七杂八的东西了. 我们都知道序列帧使用的时候就没有那么方便了,在面对.png和Plist这样的组合的时候,动作的处理需要自己去解析,而Boundingbox也需要根据当前执行的动作做状态监测.好吧,废话说的有点多了,我简单实现了部分骨骼实体的封装,代码如下:
local entity = require "src.firework.entity.entity" local skeleton_entity = class( "skeleton_entity", entity ) function skeleton_entity:ctor( armature_const_name )
self.skeleton_armature_ = nil
self.draw_debug_node_ = nil self.skeleton_armature_ = ccs.Armature:create( armature_const_name )
self.draw_debug_node_ = cc.DrawNode:create()
self.skeleton_armature_:addChild( self.draw_debug_node_ )
self:init_callbacks()
end function skeleton_entity:play( const_action_name )
self.skeleton_armature_:getAnimation():play( const_action_name )
end function skeleton_entity:init_callbacks()
self:register_callback( self.draw_debug_bounding_box, self )
end function skeleton_entity:set_anchor_point( anchor_point )
self.skeleton_armature_:setAnchorPoint( anchor_point )
end function skeleton_entity:get_anchor_point()
return self.skeleton_armature_:getAnchorPoint()
end function skeleton_entity:set_position( position )
self.skeleton_armature_:setPosition( position )
end function skeleton_entity:get_position()
return self.skeleton_armature_:getPosition()
end function skeleton_entity:add_to_node( node )
node:addChild( self.skeleton_armature_ )
end function skeleton_entity:remove_from_node()
self:remove_callback( self.draw_debug_bounding_box, self )
self.skeleton_armature_:getParent():removeChild( self.skeleton_armature_ )
end function skeleton_entity:get_bounding_box()
return self.skeleton_armature_:getBoundingBox()
end function skeleton_entity:draw_debug_bounding_box( dt )
local bounding_box = self:get_bounding_box()
local lb = self.skeleton_armature_:convertToNodeSpace( cc.p( bounding_box.x, bounding_box.y ) )
local lt = self.skeleton_armature_:convertToNodeSpace( cc.p( bounding_box.x, bounding_box.y + bounding_box.height ) )
local rt = self.skeleton_armature_:convertToNodeSpace( cc.p( bounding_box.x + bounding_box.width, bounding_box.y + bounding_box.height ) )
local rb = self.skeleton_armature_:convertToNodeSpace( cc.p( bounding_box.x + bounding_box.width, bounding_box.y ) ) self.draw_debug_node_:clear()
self.draw_debug_node_:drawLine( lb, lt, self:get_debug_color() )
self.draw_debug_node_:drawLine( lt, rt, self:get_debug_color() )
self.draw_debug_node_:drawLine( rt, rb, self:get_debug_color() )
self.draw_debug_node_:drawLine( rb, lb, self:get_debug_color() )
end return skeleton_entity
我只是单纯的去获取创建Armatrue骨骼,没有加载资源,因为资源加载部分肯定是单独做的,这里只是顺便提一下.现在实现的部分代码只是单纯的画出了Boundingbox的区域,其他的还都没做.下面给出我的unittest部分的源码:
local test_case = require "src.unittest.test_case"
local skeleton_entity = require "src.firework.entity.skeleton_entity"
local entity_manager = require "src.firework.entity.entity_manager"
local visible_rect = require "src.firework.visible_rect"
local test_entity_manager_case = class( "test_entity_manager_case", test_case ) local scene = cc.Scene:create()
if cc.Director:getInstance():getRunningScene() then
cc.Director:getInstance():replaceScene( scene )
else
cc.Director:getInstance():runWithScene( scene )
end function test_entity_manager_case:run_impl()
ccs.ArmatureDataManager:getInstance():addArmatureFileInfo( "Hero/Hero0.png", "Hero/Hero0.plist", "Hero/Hero.ExportJson" )
local entity_manager_ins = entity_manager.new()
local skeleton_entity_ins = skeleton_entity.new( "Hero" )
skeleton_entity_ins:play( "loading" )
skeleton_entity_ins:set_anchor_point( cc.p( 0.5, 0.5 ) )
skeleton_entity_ins:set_position( visible_rect:center() )
skeleton_entity_ins:add_to_node( scene ) ccs.ArmatureDataManager:getInstance():addArmatureFileInfo( "tauren/tauren0.png", "tauren/tauren0.plist", "tauren/tauren.ExportJson" )
local skeleton_entity_ins1 = skeleton_entity.new( "tauren" )
skeleton_entity_ins1:play( "loading" )
skeleton_entity_ins1:set_anchor_point( cc.p( 0.5, 0.5 ) )
skeleton_entity_ins1:set_position( visible_rect:right_center() )
skeleton_entity_ins1:add_to_node( scene ) entity_manager_ins:register_entity( skeleton_entity_ins )
entity_manager_ins:register_entity( skeleton_entity_ins1 ) local scheduler = cc.Director:getInstance():getScheduler()
scheduler:scheduleScriptFunc( function ( dt )
entity_manager_ins:update( dt )
end, , false )
end return test_entity_manager_case
把这些代码加到test_controller中就好了.代码如下:
local fmt_logger = require "src.firework.fmt_logger" local test_controller = class( "test_controller", nil ) function test_controller:ctor()
fmt_logger.trace("---------------------------------------------------------")
fmt_logger.info(" running mode: [" .. self.__cname .. "] ")
end function test_controller:run() require "src.unittest.test_case"
get_test_case_sample().new():run() local test_fmt_logger_case = require "src.unittest.firework.test_fmt_logger_case"
test_fmt_logger_case.new():run() local test_default_dispatcher_case = require "src.unittest.firework.test_default_dispatcher_case"
test_default_dispatcher_case.new():run() local test_g_firework_case = require "src.unittest.firework.test_g_firework_case"
test_g_firework_case.new():run() local test_event_dispatcher_case = require "src.unittest.firework.test_event_dispatcher_case"
test_event_dispatcher_case.new():run() local test_measure_manager_case = require "src.unittest.firework.test_measure_manager_case"
test_measure_manager_case.new():run() local test_layer_update_case = require "src.unittest.firework.test_layer_update_case"
--test_layer_update_case.new():run() local test_entity_manager_case = require "src.unittest.firework.test_entity_manager_case"
test_entity_manager_case.new():run() end return test_controller
unittest这一套是我自己写的,只是为了自己用着方便, 如果需要知道如何实现的,请去参考前面文章.我在写代码分离模块的时候写过这部分的代码.
cocos版本是cocos2d-x 3.3 final. 如果是用 <3.3版本或者是2.x版本,相信修改少量的代码就可以了.就到这里了。
2015-1-30 修正: 将entity.lua 属性初始化放到一个entity:_init()函数中.我不知道看过这篇文章的人有没有看出问题. 这里的问题是update调用的callback_list_将包含所有entity派生子类的callback函数。 导致在一次update过程中执行的速度非常的慢.我原本以为是gl渲染速度的问题.
虽然我开启debug模式打印boundingbox,但是跑到100就会很卡. 果断是发现entity:update()中执行有问题. 所以做了一次调整之后轻松跑到两百个骨骼同时在一个场景中渲染.而且我还开启了debug gl绘制模式.
cocos2d-x开发: 场景实体(entity)管理的更多相关文章
- SharePoint Server 2013开发之旅(一):新的开发平台和典型开发场景介绍
我终于开始写这个系列文章,实际上确实有一段时间没有动笔了.最近重新安装了一套SharePoint Server 2013的环境,计划利用工作之余的时间为大家写一点新的东西. SharePoint Se ...
- JavaScript应用于asp开发场景
JavaScript应用于asp开发场景 演示代码示例: <%Path="../"%> <!--#include file="../../Inc/Con ...
- EBS OAF开发中实体对象和视图对象的属性设置器
EBS OAF开发中实体对象和视图对象的属性设置器 (版权声明.本人原创或者翻译的文章如需转载,如转载用于个人学习,请注明出处:否则请与本人联系,违者必究) 源文: Home > Oracle ...
- winform快速开发平台 -> 通用权限管理之动态菜单
这几个月一直忙APP的项目,没来得及更新项目,想想该抽出时间整理一下开发思路,跟大家分享,同时也希望得到宝贵的建议. 先说一下我们的权限管理的的设计思路,首先一个企业信息化管理系统一定会用到权限管理, ...
- CozyRSS开发记录14-RSS源管理初步完工
CozyRSS开发记录14-RSS源管理初步完工 1.添加源的响应 DialogHost.Show有几个版本的重载,加一个DialogClosingEventHandler参数.我们让添加源对话框的添 ...
- CozyRSS开发记录10-RSS源管理
CozyRSS开发记录10-RSS源管理 1.RSS源树结构 做解析体力活很多,把RSS解析的优化先放放,先玩一玩RSS源的管理. 虽然在初步的设计中,RSS源是以一个列表的方式来展示,但是,我觉得如 ...
- RDIFramework.NET V2.8版本 ━ 开发实例之产品管理(WinForm)
RDIFramework.NET V2.8版本 ━ 开发实例之产品管理(WinForm) 现在,我们使用.NET快速开发整合框架(RDIFramework.NET)来开发一个应用,此应用皆在说明如何使 ...
- SNF开发平台WinForm之四-开发-主细表管理页面-SNF快速开发平台3.3-Spring.Net.Framework
4.1运行效果: 4.2开发实现: 4.2.1 有了第一个程序的开发,代码生成器的配置应该是没有问题了,我们只要在对应的数据库中创建我们需要的表结构就可以了,如下: 主表结构如下: ...
- SNF开发平台WinForm之二-开发-单表表单管理页面-SNF快速开发平台3.3-Spring.Net.Framework
2.1运行效果: 2.2开发实现: 2.2.1 这个开发与第一个开发操作步骤是一致的,不同之处就是在生成完代码之后,留下如下圈红程序,其它删除. 第一个开发地址:开发-单表表格编辑管理页面 http: ...
随机推荐
- atitit.404错误的排查流程总结vOa6
atitit.404错误的排查流程总结vOa6 1. 场景 1 1.1. 子应用猛个腊擦不能使用 404 兰.. 1 2. 服务器配置问题 2 2.1. 登录服务器管理子应用,查看应用是否启动okk ...
- 好消息!Html5游戏和动画的福音
今年基本都淡出了cocos2d-js的开发,更多集中在普通H5应用上,还有自己的Fanvas组件(http://code.tencent.com/),做canvas动画. 不过,最近回头一看WebGL ...
- 首先定义一个描述银行账户的Account类,包括成员变 量“账号”和“存款余额”,成员方法有“存款”、“取款”和“余额查询”。其次, 编写一个主类,在主类中测试Account类的功能。(已完善)
package java1; public class Account { String zhanghao; double yue=0; double add; double get; Account ...
- [ZT]Language codes – MFC
Below is table with all MFC language codes. I think it can be sometimes very useful. First column c ...
- 493萬Gmail用戶的賬號密碼遭洩露,Google否認自己存在安全漏洞
最近,大公司在互聯網信息安全問題上狀況頻出.上週,蘋果因iCloud被黑客攻擊而導致大量明星私照外洩,著實是熱鬧了一陣.而Google也來湊熱鬧了.據俄羅斯媒體CNews消息,近493萬Gmail用戶 ...
- libuv在cocos2d-x中的使用
libuv经过Node.js的实践和应用,已经证明非常之成熟,本来之前项目用的是这个:clsocket https://github.com/DFHack/clsocket 当初选它的主要原因是它支 ...
- 为EasyUI 的Tab 标签添加右键菜单
在网上看了很多demo 自己实现了一个效果如下 ps jquery1.7.2 jQuery EasyUI 1.3.6easyui QQ群:15129679 <!doctype html> ...
- Ques核心思想——CSS Namespace
Facebook’s challenges are applicable to any very complex websites with many developers. Or any situa ...
- 资源监控工具Spotlight-使用说明
几年前使用过此工具,发现用于监控远程服务器,非常方面而且快捷.当前再次用于配合压力测试进行资源监控,突然想起来了,以免生疏,在此记录! 1.被监控服务器为Ubuntu server,先在服务器上创建一 ...
- Javascript的一个生产PDF的库: unicode和中文问题的解决
Javascript的一个生产PDF的库: unicode和中文问题的解决基于canvas和jspdf库, 实现用javascript的支持中文pdf生成实用工具.参考:http://javascri ...