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 )方式实现的.

管理类的源码如下:

 1 local entity_manager = class( "entity_manager", nil )
 2
 3 function entity_manager:ctor()
 4     self.entity_list_ = {}
 5     self.entity_nums_ = 0
 6 end
 7
 8 function entity_manager:register_entity( entity )
 9     if entity == nil then
10         return
11     end
12
13     local entity_rd
14     entity_rd = self.entity_nums_ + 1
15     entity:set_runtime_id( entity_rd )
16
17     table.insert( self.entity_list_, entity )
18     self.entity_nums_ = entity_rd
19 end
20
21 function entity_manager:remove_entity( entity )
22     if entity == nil then
23         return
24     end
25
26     local entity_rd
27     entity_rd = entity:get_runtime_rd()
28
29     if entity_rd > self.entity_nums_ then
30         return
31     end
32     entity:remove_from_node()
33     table.remove( self.entity_list_, entity_rd )
34     for index, v_t in ipairs( self.entity_list_ ) do
35         if index >= entity_rd then
36             v_t:set_runtime_id( index )
37         end
38     end
39     self.entity_nums_ = #self.entity_list_
40 end
41
42 function entity_manager:update( dt )
43     for _, v_t in ipairs( self.entity_list_ ) do
44         v_t:update( dt )
45     end
46 end
47
48 return entity_manager

提供一个概念就是runtime entity id, 我们不能保证一个类型只可以创建一个对象,这是不合理的,所以除了entity的uniqure_id之外,就提供了运行时候的id。由于这个运行时候的id是动态的,所以在remove的时候需要更新一下,也就是上面table.remove下面的操作。下面是entity的代码:

 1 local entity = class( "entity", nil )
 2
 3 entity.debug_mode_ = true
 4 entity.debug_color_ = cc.c4f( 0, 1, 0, 1 )
 5 entity.callback_list_ = {}
 6 entity.runtime_id_ = nil
 7
 8 function entity:set_debug_mode( mode )
 9     self.debug_mode_ = mode
10 end
11
12 function entity:get_debug_mode()
13     return self.debug_mode_
14 end
15
16 function entity:set_debug_color( color )
17     self.debug_color_ = color
18 end
19
20 function entity:get_debug_color()
21     return self.debug_color_
22 end
23
24 function entity:set_runtime_id( runtime_id )
25     self.runtime_id_ = runtime_id
26 end
27
28 function entity:get_runtime_id()
29     return self.runtime_id_
30 end
31
32 function entity:register_callback( callback, target )
33     if callback == nil then
34         return
35     end
36
37     for _, v_t in ipairs( self.callback_list_ ) do
38         if v_t[1] == callback and v_t[2] == target then
39             return
40         end
41     end
42
43     table.insert( self.callback_list_, { callback, target } )
44 end
45
46 function entity:remove_callback( callback, target )
47     if callback == nil then
48         return
49     end
50
51     for index, v_t in ipairs( self.callback_list_ ) do
52         if v_t[1] == callback and v_t[2] == target then
53             table.remove( self.callback_list_, index )
54         end
55     end
56 end
57
58 function entity:update( dt )
59     local callback
60     local target
61     for _, v_t in ipairs( self.callback_list_ ) do
62         callback = v_t[1]
63         target = v_t[2]
64         if target ~= nil then
65             callback( target, dt )
66         else
67             callback( dt )
68         end
69     end
70 end
71
72 return entity

这是一个基类的实现,不算复杂,也很好理解,就没什么好说的了.为什么要写一个entity base类呢? 因为现在的项目可能会用序列帧,也可能会用骨骼动画. 如果是骨骼动画的话,那么所有的action都比较好处理, bounding_box也很好获得.相应的接口就是

1 armature:getAnimation():play( action_const_name )
2
3 local bounding_box = armature:getBoundingBox() 

然后就可以很简单的使用AABB或者是OBB进行碰撞检测以及设置AI等这些杂七杂八的东西了. 我们都知道序列帧使用的时候就没有那么方便了,在面对.png和Plist这样的组合的时候,动作的处理需要自己去解析,而Boundingbox也需要根据当前执行的动作做状态监测.好吧,废话说的有点多了,我简单实现了部分骨骼实体的封装,代码如下:

 1 local entity = require "src.firework.entity.entity"
 2
 3 local skeleton_entity = class( "skeleton_entity", entity )
 4
 5 function skeleton_entity:ctor( armature_const_name )
 6     self.skeleton_armature_ = nil
 7     self.draw_debug_node_ = nil
 8
 9     self.skeleton_armature_ = ccs.Armature:create( armature_const_name )
10     self.draw_debug_node_ = cc.DrawNode:create()
11     self.skeleton_armature_:addChild( self.draw_debug_node_ )
12     self:init_callbacks()
13 end
14
15 function skeleton_entity:play( const_action_name )
16     self.skeleton_armature_:getAnimation():play( const_action_name )
17 end
18
19 function skeleton_entity:init_callbacks()
20     self:register_callback( self.draw_debug_bounding_box, self )
21 end
22
23 function skeleton_entity:set_anchor_point( anchor_point )
24     self.skeleton_armature_:setAnchorPoint( anchor_point )
25 end
26
27 function skeleton_entity:get_anchor_point()
28     return self.skeleton_armature_:getAnchorPoint()
29 end
30
31 function skeleton_entity:set_position( position )
32     self.skeleton_armature_:setPosition( position )
33 end
34
35 function skeleton_entity:get_position()
36     return self.skeleton_armature_:getPosition()
37 end
38
39 function skeleton_entity:add_to_node( node )
40     node:addChild( self.skeleton_armature_ )
41 end
42
43 function skeleton_entity:remove_from_node()
44     self:remove_callback( self.draw_debug_bounding_box, self )
45     self.skeleton_armature_:getParent():removeChild( self.skeleton_armature_ )
46 end
47
48 function skeleton_entity:get_bounding_box()
49     return self.skeleton_armature_:getBoundingBox()
50 end
51
52 function skeleton_entity:draw_debug_bounding_box( dt )
53     local bounding_box = self:get_bounding_box()
54     local lb = self.skeleton_armature_:convertToNodeSpace( cc.p( bounding_box.x, bounding_box.y ) )
55     local lt = self.skeleton_armature_:convertToNodeSpace( cc.p( bounding_box.x, bounding_box.y + bounding_box.height ) )
56     local rt = self.skeleton_armature_:convertToNodeSpace( cc.p( bounding_box.x + bounding_box.width, bounding_box.y + bounding_box.height ) )
57     local rb = self.skeleton_armature_:convertToNodeSpace( cc.p( bounding_box.x + bounding_box.width, bounding_box.y ) )
58
59     self.draw_debug_node_:clear()
60     self.draw_debug_node_:drawLine( lb, lt, self:get_debug_color() )
61     self.draw_debug_node_:drawLine( lt, rt, self:get_debug_color() )
62     self.draw_debug_node_:drawLine( rt, rb, self:get_debug_color() )
63     self.draw_debug_node_:drawLine( rb, lb, self:get_debug_color() )
64 end
65
66 return skeleton_entity

我只是单纯的去获取创建Armatrue骨骼,没有加载资源,因为资源加载部分肯定是单独做的,这里只是顺便提一下.现在实现的部分代码只是单纯的画出了Boundingbox的区域,其他的还都没做.下面给出我的unittest部分的源码:

 1 local test_case = require "src.unittest.test_case"
 2 local skeleton_entity = require "src.firework.entity.skeleton_entity"
 3 local entity_manager = require "src.firework.entity.entity_manager"
 4 local visible_rect = require "src.firework.visible_rect"
 5 local test_entity_manager_case = class( "test_entity_manager_case", test_case )
 6
 7 local scene = cc.Scene:create()
 8 if cc.Director:getInstance():getRunningScene() then
 9     cc.Director:getInstance():replaceScene( scene )
10 else
11     cc.Director:getInstance():runWithScene( scene )
12 end
13
14 function test_entity_manager_case:run_impl()
15     ccs.ArmatureDataManager:getInstance():addArmatureFileInfo( "Hero/Hero0.png", "Hero/Hero0.plist", "Hero/Hero.ExportJson" )
16     local entity_manager_ins = entity_manager.new()
17     local skeleton_entity_ins = skeleton_entity.new( "Hero" )
18     skeleton_entity_ins:play( "loading" )
19     skeleton_entity_ins:set_anchor_point( cc.p( 0.5, 0.5 ) )
20     skeleton_entity_ins:set_position( visible_rect:center() )
21     skeleton_entity_ins:add_to_node( scene )
22
23     ccs.ArmatureDataManager:getInstance():addArmatureFileInfo( "tauren/tauren0.png", "tauren/tauren0.plist", "tauren/tauren.ExportJson" )
24     local skeleton_entity_ins1 = skeleton_entity.new( "tauren" )
25     skeleton_entity_ins1:play( "loading" )
26     skeleton_entity_ins1:set_anchor_point( cc.p( 0.5, 0.5 ) )
27     skeleton_entity_ins1:set_position( visible_rect:right_center() )
28     skeleton_entity_ins1:add_to_node( scene )
29
30     entity_manager_ins:register_entity( skeleton_entity_ins )
31     entity_manager_ins:register_entity( skeleton_entity_ins1 )
32
33     local scheduler = cc.Director:getInstance():getScheduler()
34     scheduler:scheduleScriptFunc( function ( dt )
35         entity_manager_ins:update( dt )
36     end, 0, false )
37 end
38
39 return test_entity_manager_case

把这些代码加到test_controller中就好了.代码如下:

 1 local fmt_logger = require "src.firework.fmt_logger"
 2
 3 local test_controller = class( "test_controller", nil )
 4
 5 function test_controller:ctor()
 6     fmt_logger.trace("---------------------------------------------------------")
 7     fmt_logger.info("        running mode: [" .. self.__cname .. "]               ")
 8 end
 9
10 function test_controller:run()
11
12     require "src.unittest.test_case"
13     get_test_case_sample().new():run()
14
15     local test_fmt_logger_case = require "src.unittest.firework.test_fmt_logger_case"
16     test_fmt_logger_case.new():run()
17
18     local test_default_dispatcher_case = require "src.unittest.firework.test_default_dispatcher_case"
19     test_default_dispatcher_case.new():run()
20
21     local test_g_firework_case = require "src.unittest.firework.test_g_firework_case"
22     test_g_firework_case.new():run()
23
24     local test_event_dispatcher_case = require "src.unittest.firework.test_event_dispatcher_case"
25     test_event_dispatcher_case.new():run()
26
27     local test_measure_manager_case = require "src.unittest.firework.test_measure_manager_case"
28     test_measure_manager_case.new():run()
29
30     local test_layer_update_case = require "src.unittest.firework.test_layer_update_case"
31     --test_layer_update_case.new():run()
32
33     local test_entity_manager_case = require "src.unittest.firework.test_entity_manager_case"
34     test_entity_manager_case.new():run()
35
36 end
37
38 return test_controller

unittest这一套是我自己写的,只是为了自己用着方便, 如果需要知道如何实现的,请去参考前面文章.我在写代码分离模块的时候写过这部分的代码.

cocos版本是cocos2d-x 3.3 final. 如果是用 <3.3版本或者是2.x版本,相信修改少量的代码就可以了.就到这里了。

时间: 2024-12-29 01:59:45

cocos2d-x开发: 场景实体(entity)管理的相关文章

专注智慧城市项目开发,智慧城市管理建设

专注智慧城市项目开发,智慧城市管理建设(作者:ruiec_wangxuyan) 智慧城市是按照科学的城市发展理念,利用新一代信息技术,在信息全面感知和互联的基础上,实现人.物.城市功能系统之间无缝连接与协同联动,达到城市管理智能自感知.自适应.自优化,形成具备可持续内生动力的安全.便捷.高效.绿色的城市形态,以推进实体基础设施和信息设施相融合.构建城市智能基础设施为基础,以物联网.云计算.移动互联网等新一代信息通信技术在城市各领域的充分运用为主线,通过高科技的应用解决方案,提升城市运行管理水平.

Asp.Net MVC4开发二: Entity Framework在Asp.Net MVC4中的应用

ORM作为一种数据库访问机制已广泛地应用于各种项目当中,在.Net开发中,应用比较广泛的ORM框架大致有下面几个: 官方支持的有:Linq to SQL,Entity Framework.三方的有:NHibernate.前面介绍过Linq to SQL的应用,这篇介绍一下Entity Framework在Asp.Net MVC4中的应用. 首先用Visual Studio(2012或2013,其它版本需要安装Asp.Net MVC4)创建一个Asp.Net MVC4的项目,项目创建完成后会发现E

企业场景用户密码管理

企业场景用户密码管理 1.密码要复杂,8位以上字母数字以及特殊字符的组合. 2.大的企业用户和密码统一管理(相当于活动目录,openLDAP). 3.动态密码:动态口令,第三方提供或者自己开发.

crm2011创建自定义实体Entity

using System; using Microsoft.Xrm.Sdk; using Microsoft.Xrm.Sdk.Messages; using Microsoft.Xrm.Sdk.Metadata; using Microsoft.Crm.Sdk.Messages; /// <summary> /// crm创建自定义实体 /// </summary> public class CreateEntityHelper { public void Create(IOrga

EBS OAF开发中实体对象和视图对象的属性设置器

(版权声明,本人原创或者翻译的文章如需转载,如转载用于个人学习,请注明出处:否则请与本人联系,违者必究) 源文: Home > Oracle Application Framework Documentation Set, Release 12.2 > Oracle Application Framework Developer's Guide > Chapter 5: Implementing Server-Side Features > Entity Object and Vi

【用django2.0来开发】 后台会员管理

[用django2.0来开发] 后台会员管理 项目地址:https://gitee.com/ccnv07/django_example这一篇主要是要完成django 后台的会员管理功能, 会涉及到model, ModelAdmin, admin, Form等多个方面, 所以会讲的比较细 创建会员模块 cd cms python manage.py startapp account python manage.py startapp 是创建一个模块 至于模块的定义, 每个人都有不同的看法, 有些是

cocos2d 游戏开发实战

文章转自:http://uliweb.clkg.org/tutorial/read/40 6   cocos2d 游戏开发实战 6.1   创建cocos2d项目 6.2   cocos2d v3 "hello world" 6.2.1   显示一个飞船 6.3   精灵 6.4   開始 space viking 之旅 6.4.1   添加 sneakyinput 6.5   精灵的移动效果,旋转效果 6.6   定时器效果 6.7   启动 cocos2d,默认竖屏 6.8   检

[ios5 cocos2d游戏开发实战] 笔记3-FileUtils, notificationCenter

FileUtils //文件管理工具 FileUtils::getInstance() std::string getStringFromFile(const std::string& filename);//读取文件中的字符串 Data getDataFromFile(const std::string& filename);//获取文件数据 void setSearchPaths(const std::vector<std::string>& searchPaths

团队项目:开发模式及代码管理

本次团队项目我们有意无意地使用了主治医师模式,即由一到两个主程序员进行游戏风格,整体框架的设计,实现较为核心的内容,其他人的工作都围绕主程序员展开.说是有意无意是因为该项目利用Unity游戏引擎进行开发,而当时组里只有两人对Unity引擎较为熟悉,其他人在一边学习的同时先进行外围的工作,之后逐渐加入核心的实现. 比较遗憾的是目前我们的项目缺乏代码管理.由于采用Unity引擎开发,无法上传github进行托管,我们寻找了其他的管理工具但由于付费等原因效果不太理想.我们的代码都保存在每个人的电脑中,