Habréã«ã¯ãã²ãŒã ããŒãããäœæããããšã«é¢ããè峿·±ãèšäºããã§ã«å€æ°ãããŸããããæ°ã«å
¥ãã®ã¯ã©ããããã©ã³ã±ã³ã·ã¥ã¿ã€ã³ã«ãªãããå¥å
šãªç¶æ
ã«å°éããããã«äœããã¹ããã説æããèšäºã¯ã»ãšãã©ãããŸããã å
ã®èšäºã®èè
ã¯ãã²ãŒã ãšã³ãžã³ã®ã³ãŒãããã¡ã€ã³ã«ãŒãã®ãžã£ã³ã¯ããŒããããEntity Component Systemã䜿çšããç¶¿å¯ã«èããããæ¡åŒµå¯èœãªã¢ãŒããã¯ãã£ã«é²åããæ§åãèªã£ãŠããŸãã èšäºã«ã¯å€ãã®ã³ãŒãããããŸãããã»ãšãã©ã®å Žåç¹°ãè¿ãããŸãããèè
ãäœã倿Žãããããæ§é å
šäœã«ã©ã®ããã«åœ±é¿ããããããæç¢ºã«ãªãã®ã§ãç§ã¯ãããæšãŠãŸããã§ããã ãã®èšäºã¯ãç§ã®ãããªåå¿è
ã察象ãšããŠããŸãããæ¢ã«åå¿è
ã¯ãéªæªãªããããã¿ã€ããããã€ãäœæããŠããŸãããä»ã§ã¯ã³ãŒããçè§£ããæ¹æ³ãããããŸããã
翻蚳è
ã®ã¡ã¢ïŒç§ã¯ç¿»èš³è
ã§ã¯ãããŸããã ç§ã¯åœŒã®ã²ãŒã ããªãã¡ã¯ã¿ãªã³ã°ããæ¹æ³ãæ¢ããŠããæ®éã®èã§çžãããããã°ã©ããŒã§ããããã®ãã¿ãŒã³ã«ã€ãŸãããŠãããã«ã»ãšãã©èšåãããŠããªãããšã«é©ãã 倧ããªããã¹ãã翻蚳ããããšã¯äžåºŠããããŸãããç°¡åã§çè§£ããããè±èªã®ããã¹ããéåžžã®ãã·ã¢èªã«ç¿»èš³ããã®ã¯ãšãŠãé£ããããšã ãšç¥ã£ãã®ã¯å瀺ã§ããã èŠããã«ããã®èšäºãäžåšçšã§æ²ãã£ãŠæžãããŠããããã«èŠããå Žåãç§ã¯è¬çœªããŸãã æ£çŽèšã£ãŠ:)
å
é±ãç§ã¯
Ash -Entity Systemãã¬ãŒã ã¯ãŒã¯ããªãªãŒã¹ããŠActionScriptã²ãŒã ãéçºããŸããããå€ãã®äººãããEntity System Frameworkãšã¯äœã§ããïŒããšãã質åããããŸããã ããã«ç§ã®é·ãçãããããŸãã
ãšã³ãã£ãã£ã·ã¹ãã ã¯ãUnityãEmber2ãXemberãããã³èªåã®Ashãªã©ã®ããŸãç¥ãããŠããªãActionScriptãã¬ãŒã ã¯ãŒã¯ã®ãããªèº«è¿ãªãã®ã®ãããã§äººæ°ãåããŠããŸãã ããã«ã¯ååãªçç±ããããŸããã³ãŒãå
ã®è²¬ä»»ã®åé¢ãä¿é²ããã²ãŒã ã®åçŽåãããã¢ãŒããã¯ãã£ã¯äœ¿ããããã§ãã
ãã®æçš¿ã§ã¯ããšã³ãã£ãã£ããŒã¹ã®ã¢ãŒããã¯ãã£ãæãªããã®ã²ãŒã ã«ãŒãããã©ã®ããã«åºçŸããããäžè²«ããŠç€ºããŸãã å°ãæéãããããŸãã äžèšã®äŸã¯Actionscriptäžã«ãããŸããããã¯çŸæç¹ã§ãŸãã«äœ¿çšããŠãããã®ã§ãããã¢ãŒããã¯ãã£èªäœã¯ããããããã°ã©ãã³ã°èšèªã«é©ããŠããŸãã
äŸ
ãã®èšäºã§ã¯ãäŸãšããŠåçŽãªã²ãŒã
Asteroidsã䜿çšããŸãã ã¬ã³ããªã³ã°ã·ã¹ãã ãç©çåŠãAIããªããžã§ã¯ãã®ãã¬ã€ã€ãŒã³ã³ãããŒã«ãéå¶åŸ¡ãªããžã§ã¯ããªã©ãããã°ã²ãŒã ã«å¿
èŠãªãã®ã®å€ããå«ãŸããŠãããããäŸãšããŠå°ææã䜿çšããŠããŸãã
ã²ãŒã ãµã€ã¯ã«
ãšã³ãã£ãã£ã·ã¹ãã ã䜿çšããçç±ãæ¬åœã«çè§£ããã«ã¯ãå€ãè¯ã
ã²ãŒã ãµã€ã¯ã«ãã©ã®ããã«æ©èœããããæç¢ºã«çè§£ããå¿
èŠããããŸãã å°ææã®å Žåãæ¬¡ã®ããã«ãªããŸãã
function update( time:Number ):void { game.update( time ); spaceship.updateInputs( time ); for each( var flyingSaucer:FlyingSaucer in flyingSaucers ) { flyingSaucer.updateAI( time ); } spaceship.update( time ); for each( var flyingSaucer:FlyingSaucer in flyingSaucers ) { flyingSaucer.update( time ); } for each( var asteroid:Asteroid in asteroids ) { asteroid.update( time ); } for each( var bullet:Bullet in bullets ) { bullet.update( time ); } collisionManager.update( time ); spaceship.render(); for each( var flyingSaucer:FlyingSaucer in flyingSaucers ) { flyingSaucer.render(); } for each( var asteroid:Asteroid in asteroids ) { asteroid.render(); } for each( var bullet:Bullet in bullets ) { bullet.render(); } }
ãã®ã²ãŒã ã«ãŒãã¯ãã²ãŒã ãæŽæ°ããããã«ãéåžžæ¯ç§60ãŸãã¯30åã宿çã«åŒã³åºãããŸãã ã«ãŒãå
ã®æäœã®é åºã¯éèŠã§ãããªããªããããŸããŸãªã²ãŒã ãªããžã§ã¯ããæŽæ°ãããããã®éã®è¡çªããã§ãã¯ããŠããããããããã¹ãŠæç»ããããã§ãã ãã¹ãŠã®ãã¬ãŒã ã
ããã¯ã次ã®çç±ã§éåžžã«åçŽãªã²ãŒã ã«ãŒãã§ãã
1.ã²ãŒã èªäœã¯ã·ã³ãã«ã§ãã
2.ã²ãŒã ã«ã¯1ã€ã®ç¶æ
ãããããŸããã
éå»ã«ãç§ã¯ã³ã³ãœãŒã«ã²ãŒã ã«åãçµãã§ãããå¯äžã®æ©èœã§ããã²ãŒã ã«ãŒãã¯3,000è¡ãè¶
ããã³ãŒãã§æ§æãããŠããŸããã ããã¯çŸãããªããæãã§ããã ãããããããã²ãŒã ã®äœææ¹æ³ã§ãããç§ãã¡ã¯ãããšå
±ã«çããªããã°ãªããŸããã§ããã
ãšã³ãã£ãã£ã·ã¹ãã ã¢ãŒããã¯ãã£ã¯ãã²ãŒã ã«ãŒãã®åé¡ã解決ããããšããããšããçãŸããŸããã ããã«ãããã²ãŒã ã«ãŒããã²ãŒã ã®äžå¿ãšãªããã²ãŒã ã«ãŒãã®åçåãçŸä»£ã®ã²ãŒã ã®ã¢ãŒããã¯ãã£ã«ãããŠä»ã®äœãããéèŠã§ããããšã瀺åãããŸãã ããã¯ãããšãã°ããã¥ãŒãã³ã³ãããŒã©ãŒããåé¢ãããããéèŠã§ãã
ããã»ã¹
ãã®é²åã®æåã®ã¹ãããã¯ãããã»ã¹ãšåŒã°ãããªããžã§ã¯ãã§ãã ãããã¯ãåæåãæŽæ°ãããã³ç Žæ£ã§ãããªããžã§ã¯ãã§ãã ããã»ã¹ã€ã³ã¿ãŒãã§ã€ã¹ã¯æ¬¡ã®ããã«ãªããŸãã
interface IProcess { function start():Boolean; function update( time:Number ):void; function end():void; }
ããšãã°ãã¬ã³ããªã³ã°ããªããžã§ã¯ãã®ç§»åãè¡çªã®åŠçãªã©ãæ
åœããè€æ°ã®ããã»ã¹ã«åå²ãããšãã²ãŒã ãµã€ã¯ã«ãåçŽåã§ããŸãã ãããã®ããã»ã¹ã管çããããã«ãããã»ã¹ãããŒãžã£ãŒãäœæããŸãã
class ProcessManager { private var processes:PrioritisedList; public function addProcess( process:IProcess, priority:int ):Boolean { if( process.start() ) { processes.add( process, priority ); return true; } return false; } public function update( time:Number ):void { for each( var process:IProcess in processes ) { process.update( time ); } } public function removeProcess( process:IProcess ):void { process.end(); processes.remove( process ); } }
ããã¯ãããã»ã¹ãããŒãžã£ãŒã®ç°¡æããŒãžã§ã³ã§ãã ç¹ã«ãããã»ã¹ãæ£ããé åºïŒaddã¡ãœããã®priorityãã©ã¡ãŒã¿ãŒã«ãã£ãŠæ±ºå®ãããïŒã§æŽæ°ããã²ãŒã ãµã€ã¯ã«äžã«ããã»ã¹ãåé€ãããç¶æ³ãåŠçããå¿
èŠããããŸãã ãããããã®åçŽåãããããŒãžã§ã³ã¯ã¢ã€ãã¢ãã®ãã®ãäŒããŠããŸãã ã²ãŒã ãµã€ã¯ã«ãè€æ°ã®ããã»ã¹ã«åå²ãããŠããå Žåãããã»ã¹ãããŒãžã£ãŒã®æŽæ°æ¹æ³ã¯æ°ããã²ãŒã ãµã€ã¯ã«ã§ãããããã»ã¹ã¯æ¢ã«ã²ãŒã ã®ã³ã¢ã«ãªã£ãŠããŸãã
ã¬ã³ããªã³ã°ããã»ã¹
ããšãã°ãã¬ã³ããªã³ã°ããã»ã¹ãèŠãŠã¿ãŸãããã ã²ãŒã ã«ãŒãããã¬ã³ããŒã³ãŒããåŒãåºããŠããã»ã¹ã«é
眮ããã ãã§ã次ã®ããã«ãªããŸãã
class RenderProcess implements IProcess { public function start() : Boolean {
ã€ã³ã¿ãŒãã§ãŒã¹ã䜿çšããŸã
ããããããŸã广çã§ã¯ãããŸããã å¯èœãªãã¹ãŠã®çš®é¡ã®ã²ãŒã ãªããžã§ã¯ããæåã§æç»ããå¿
èŠããããŸãã ãã¹ãŠã®å¯èŠãªããžã§ã¯ãã®å
±éã€ã³ã¿ãŒãã§ãŒã¹ãããå Žåãå€ãã®ããšãåçŽåã§ããŸã
interface IRenderable { function render(); } class RenderProcess implements IProcess { private var targets:Vector.<IRenderable>; public function start() : Boolean {
次ã«ãå®å®è¹ã®ã¯ã©ã¹ã«åæ§ã®ã³ãŒããå«ãŸããŸãã
class Spaceship implements IRenderable { public var view:DisplayObject; public var position:Point; public var rotation:Number; public function render():void { view.x = position.x; view.y = position.y; view.rotation = rotation; } }
ãã®ã³ãŒãã¯ãFlashãã£ã¹ãã¬ã€ãªã¹ãã«åºã¥ããŠããŸãã ãããã¡ãŸãã¯stage3dã䜿çšããå Žåãããã¯ç°ãªããŸãããååã¯åãã§ãã ã¬ã³ããªã³ã°ããç»åãã¬ã³ããªã³ã°ããäœçœ®ãšå転ãå¿
èŠã§ãã ãããŠãç»é¢ãžã®åºåãå®è¡ããã¬ã³ããªã³ã°é¢æ°ã
åºæ¬ã¯ã©ã¹ãšç¶æ¿ã䜿çšããŸã
å®éãè¹ã®ã³ãŒãã«ã¯ãŠããŒã¯ãªãã®ã¯äœããããŸããã ãã®ã³ãŒãã¯ãã¹ãŠããã¹ãŠã®å¯èŠãªããžã§ã¯ãã§äœ¿çšã§ããŸãã ããããåºå¥ããå¯äžã®ãã®ã¯ãviewããããã£ã«ãã£ãŠã¢ã¿ããããã衚瀺ãªããžã§ã¯ããšãå転ã®äœçœ®ãšè§åºŠã§ãã ãããåºæ¬ã¯ã©ã¹ã§ã©ããããŠãç¶æ¿ã䜿çšããŸãããã
class Renderable implements IRenderable { public var view:DisplayObject; public var position:Point; public var rotation:Number; public function render():void { view.x = position.x; view.y = position.y; view.rotation = rotation; } } class Spaceship extends Renderable { }
ãã¡ãããæç»ããããã¹ãŠã®ãªããžã§ã¯ãã¯åºæ¬ã¯ã©ã¹ãå±éããæ¬¡ã®ãããªéå±€ãååŸããŸãã

ç§»åããã»ã¹
次ã®ã¹ããããçè§£ããã«ã¯ãæåã«å¥ã®ããã»ã¹ãšãããæ©èœããã¯ã©ã¹ã調ã¹ãå¿
èŠããããŸãã ãªããžã§ã¯ãã®äœçœ®ã«é¢ããæ
å ±ãæŽæ°ããåãã®ããã»ã¹ãæ³åããŠã¿ãŸããã
interface IMoveable { function move( time:Number ); } class MoveProcess implements IProcess { private var targets:Vector.<IMoveable>; public function start():Boolean { return true; } public function update( time:Number ):void { for each( var target:IMoveable in targets ) { target.move( time ); } } public function end():void { } } class Moveable implements IMoveable { public var position:Point; public var rotation:Number; public var velocity:Point; public var angularVelocity:Number; public function move( time:Number ):void { position.x += velocity.x * time; position.y += velocity.y * time; rotation += angularVelocity * time; } } class Spaceship extends Moveable { }
å€éç¶æ¿
ããã¯ãã¹ãŠè¯ãããã«èŠããŸãããæ®å¿µãªãããè¹ãåãããŠã¬ã³ããªã³ã°ãããã®ã§ãããå€ãã®ããã°ã©ãã³ã°èšèªã¯å€éç¶æ¿ãèš±å¯ããŠããŸããã ãããŠãããããµããŒãããèšèªã§ãããMovableã¯ã©ã¹ã®äœçœ®ãšå転ãRenderableã¯ã©ã¹ãšåãã§ãªããã°ãªããªããšãã«åé¡ãçºçããŸãã
解決çã¯ãMovableãRenderableãæ¡åŒµãããšãã«ç¶æ¿ãã§ãŒã³ãäœæããããšã§ãã
class Moveable extends Renderable implements IMoveable { public var velocity:Point; public var angularVelocity:Number; public function move( time:Number ):void { position.x += velocity.x * time; position.y += velocity.y * time; rotation += angularVelocity * time; } } class Spaceship extends Moveable { }
çŸåšãç§ãã¡ã®å®å®è¹ã¯ç§»åãšã¬ã³ããªã³ã°ã®äž¡æ¹ãå¯èœã§ãã åãååãä»ã®ã²ãŒã ãªããžã§ã¯ãã«é©çšããŠããã®ã¯ã©ã¹éå±€ãååŸã§ããŸãã

RenderableãåçŽã«æ¡åŒµããéçãªããžã§ã¯ããååŸã§ããŸãã

ç§»åå¯èœã ãã¬ã³ããªã³ã°äžå¯
ããããæç»ãã¹ãã§ã¯ãªãç§»åãªããžã§ã¯ããäœæãããå Žåã¯ã©ãã§ããããïŒ ããšãã°ãé衚瀺ã®ã²ãŒã ãªããžã§ã¯ãã§ããïŒ ããã§ãã¯ã©ã¹éå±€ãå£ããŠãããRenderableããç¶æ¿ãããªãMovableã€ã³ã¿ãŒãã§ã€ã¹ã®ä»£æ¿å®è£
ãå¿
èŠã§ãã
class InvisibleMoveable implements IMoveable { public var position:Point; public var rotation:Number; public var velocity:Point; public var angularVelocity:Number; public function move( time:Number ):void { position.x += velocity.x * time; position.y += velocity.y * time; rotation += angularVelocity * time; } }

åçŽãªã²ãŒã ã§ã¯ãããã¯æ±ãã§ããã管çãããããè€éãªã²ãŒã ã§ã¯ãç¶æ¿ã䜿çšããŠããã»ã¹ããªããžã§ã¯ãã«ãã€ã³ããããšãã³ãŒããããã«ç®¡çäžèœã«ãªããããã«ãäžèšã®ãããªåçŽãªç¶æ¿ããªãŒã«åã蟌ãŸããŠããªããã®ãã²ãŒã ã§èŠã€ãããŸãã
ç¶æ¿ãããæ§æãåªå
ããŸãã
å€ãOOPã®ååããããŸãïŒ
ç¶æ¿ãããåæãåªå
ããŸãã ãã®ååãé©çšãããšãç¶æ¿ã«é¢ããæœåšçãªæ··ä¹±ããããªããæãããšãã§ããŸãã
Renderableã¯ã©ã¹ãšMovableã¯ã©ã¹ã¯åŒãç¶ãå¿
èŠã§ãããããããç¶æ¿ããŠå®å®è¹ã¯ã©ã¹ãäœæãã代ããã«ããããã®åã¯ã©ã¹ã®ã€ã³ã¹ã¿ã³ã¹ãå«ãshipã¯ã©ã¹ãäœæããŸãã
class Renderable implements IRenderable { public var view:DisplayObject; public var position:Point; public var rotation:Number; public function render():void { view.x = position.x; view.y = position.y; view.rotation = rotation; } } class Moveable implements IMoveable { public var position:Point; public var rotation:Number; public var velocity:Point; public var angularVelocity:Number; public function move( time:Number ):void { position.x += velocity.x * time; position.y += velocity.y * time; rotation += angularVelocity * time; } } class Spaceship { public var renderData:IRenderable; public var moveData:IMoveable; }
ãã®ããã«ããŠãç¶æ¿ã®åé¡ãçºçãããããšãªããããŸããŸãªåäœãä»»æã®æ¹æ³ã§çµã¿åãããããšãã§ããŸãã

ãã®æ§æã䜿çšããŠäœæããããããã®ãªããžã§ã¯ãïŒéçãªããžã§ã¯ããå®å®è¹ã空é£ã¶åç€ãå°ææãããã³åå Ž-ç·ç§°ããŠãšã³ãã£ãã£ãšåŒã°ããŸãã
ç§ãã¡ã®ããã»ã¹ã¯å€ãããŸããã
interface IRenderable { function render(); } class RenderProcess implements IProcess { private var targets:Vector.<IRenderable>; public function update(time:Number):void { for each(var target:IRenderable in targets) { target.render(); } } } interface IMoveable { function move(); } class MoveProcess implements IProcess { private var targets:Vector.<IMoveable>; public function update(time:Number):void { for each(var target:IMoveable in targets) { target.move( time ); } } }
ãã ããåããã»ã¹ã«shipãªããžã§ã¯ãã远å ããã®ã§ã¯ãªãããã®ã³ã³ããŒãã³ãã远å ããŸãã ãããŠã次ã®ãããªãã®ãåŸãããŸãã
public function createSpaceship():Spaceship { var spaceship:Spaceship = new Spaceship(); ... renderProcess.addItem( spaceship.renderData ); moveProcess.addItem( spaceship.moveData ); ... return spaceship; }
ãã®ã¢ãããŒãã¯è¯ãããã§ãã ããŸããŸãªç¶æ¿ãèªå·±å埩ãã§ãŒã³ãªãã§ãããŸããŸãªã²ãŒã ãªããžã§ã¯ãã§ããã»ã¹ãµããŒããèªç±ã«çµã¿åããããçµã¿åããããããããšãã§ããŸãã ãããã1ã€ã®åé¡ããããŸãã
äžè¬çãªæ
å ±ãã©ãããŸããïŒ
Moveããã»ã¹ã¯å€ã倿Žããå¿
èŠããããRenderããã»ã¹ã¯ããããæç»ããå¿
èŠããããããRenderableã¯ã©ã¹ã®ãªããžã§ã¯ãã®äœçœ®ãšå転ã®ããããã£ã¯ãMovableãªããžã§ã¯ãã®å転ãããäœçœ®ãšåãå€ãæã€å¿
èŠããããŸãã
class Renderable implements IRenderable { public var view:DisplayObject; public var position:Point; public var rotation:Number; public function render():void { view.x = position.x; view.y = position.y; view.rotation = rotation; } } class Moveable implements IMoveable { public var position:Point; public var rotation:Number; public var velocity:Point; public var angularVelocity:Number; public function move( time:Number ):void { position.x += velocity.x * time; position.y += velocity.y * time; rotation += angularVelocity * time; } } class Spaceship { public var renderData:IRenderable; public var moveData:IMoveable; }
ãã®åé¡ã解決ããã«ã¯ãäž¡æ¹ã®ãªããžã§ã¯ãããããã®ããããã£ã®åãã€ã³ã¹ã¿ã³ã¹ãåç
§ããŠããããšã確èªããå¿
èŠããããŸãã ActionScriptã§ã¯ãããã¯ããããã®ããããã£ããªããžã§ã¯ãã§ãªããã°ãªããªãããšãæå³ããŸãããªããžã§ã¯ãã¯åç
§ã§æž¡ãããšãã§ããããªããã£ãåã¯å€ã§æž¡ãããã§ãã
ãã®ãããã³ã³ããŒãã³ããšåŒã¶å¥ã®ã¯ã©ã¹ã®ã»ãããæç€ºããŸãã ãããã®ã³ã³ããŒãã³ãã¯ããããã£å€ã®ã©ãããŒã§ãããããããã»ã¹éã§å
±æã§ããŸãã
class PositionComponent { public var x:Number; public var y:Number; public var rotation:Number; } class VelocityComponent { public var velocityX:Number; public var velocityY:Number; public var angularVelocity:Number; } class DisplayComponent { public var view:DisplayObject; } class Renderable implements IRenderable { public var display:DisplayComponent; public var position:PositionComponent; public function render():void { display.view.x = position.x; display.view.y = position.y; display.view.rotation = position.rotation; } } class Moveable implements IMoveable { public var position:PositionComponent; public var velocity:VelocityComponent; public function move( time:Number ):void { position.x += velocity.velocityX * time; position.y += velocity.velocityY * time; position.rotation += velocity.angularVelocity * time; } }
å®å®è¹ã¯ã©ã¹ãäœæãããšããMovableãªããžã§ã¯ããšRenderableãªããžã§ã¯ããPositionComponentã®åãã€ã³ã¹ã¿ã³ã¹ãåç
§ããããšã確èªããå¿
èŠããããŸãã
class Spaceship { public function Spaceship() { moveData = new Moveable(); renderData = new Renderable(); moveData.position = new PositionComponent(); moveData.velocity = new VelocityComponent(); renderData.position = moveData.position; renderData.display = new DisplayComponent(); } }
ãã®å€æŽã¯ããã»ã¹ã«ã¯åœ±é¿ããŸããã
ãããŠãããã¯äŒæ¯ããã®ã«è¯ãå Žæã§ãã
ããã§ãã¿ã¹ã¯ãæç¢ºã«åå²ãããŸããã ã²ãŒã ã«ãŒãã¯ããã»ã¹ãããããããããããã®æŽæ°ã¡ãœãããåŒã³åºããŸãã åããã»ã¹ã¯ããªããžã§ã¯ããšã®å¯Ÿè©±ãå¯èœã«ããã€ã³ã¿ãŒãã§ã€ã¹ãå®è£
ãããªããžã§ã¯ãã®ã³ã¬ã¯ã·ã§ã³ã§æ§æãããïŒããã»ã¹ïŒã¯ãããã®ãªããžã§ã¯ãã«å¿
èŠãªã¡ãœãããåŒã³åºããŸãã ãã®ãããªãªããžã§ã¯ãã¯ãæ
å ±ã䜿çšããŠåäžã®ã¿ã¹ã¯ãå®è¡ããŸãã ã³ã³ããŒãã³ãã䜿çšããŠããããã®ãªããžã§ã¯ãã¯å
±éã®æ
å ±ãæã¡ãããŸããŸãªããã»ã¹ã®çµã¿åããã«ãããåããã»ã¹ãæ¯èŒçã·ã³ãã«ã«ä¿ã¡ãªãããã²ãŒã ãªããžã§ã¯ãéã®è€éãªçžäºäœçšãäœæã§ããŸãã
ãã®ã¢ãŒããã¯ãã£ã¯ãã²ãŒã éçºã«ãããå€ãã®ãšã³ãã£ãã£ã·ã¹ãã ã«äŒŒãŠããŸãã OOPã®ååãããŸãå®è£
ããæ©èœããŸãã ããããããªãã倢äžã«ãããäœãä»ã®ãã®ããããŸãã
é©åãªãªããžã§ã¯ãæåã®å®è·µãé¿ãã
çŸåšã®ã¢ãŒããã¯ãã£ã¯ã
ã«ãã»ã«åã
責任ã®åé¢ãªã©ã®ãªããžã§ã¯ãæåããã°ã©ãã³ã°ã®ååã䜿çšããŠããŸãã
責任ããšã«IRenderableããã³IMovableã®è¿ãå€ãšããžãã¯ã䜿çšãããã¬ãŒã ããšã«ã²ãŒã ãªããžã§ã¯ããæŽæ°ããŸãã
æ§æ -å®å®è¹ãªããžã§ã¯ãã¯ãIRenderableããã³IMovableã€ã³ã¿ãŒãã§ãŒã¹ã®å®è£
ãçµã¿åãããŠäœæãããŸãã ã³ã³ããŒãã³ãã·ã¹ãã ã䜿çšãããšãå¿
èŠã«å¿ããŠãããŒã¿ã¯ã©ã¹ã®ããŸããŸãªãªããžã§ã¯ãã®å€ã«çããã¢ã¯ã»ã¹ã§ããŸãã
ãªããžã§ã¯ãã®ã·ã¹ãã ã®é²åã«ãããæ¬¡ã®ã¹ãããã¯ãçŽæçã«çè§£ã§ããããªããžã§ã¯ãæåããã°ã©ãã³ã°ã®æ¬è³ªã«ããããã¬ã³ããç Žå£ããããã«èŠãããããããŸããã Renderableããã³Movableã®å®è£
ã«ãããæ
å ±ãšããžãã¯ã®ã«ãã»ã«åãè§£é€ããŸãã ç¹ã«ããããã®ã¯ã©ã¹ããããã»ã¹ã«ããžãã¯ãç§»åããŸãã
ããã¯ïŒ
interface IRenderable { function render(); } class Renderable implements IRenderable { public var display:DisplayComponent; public var position:PositionComponent; public function render():void { display.view.x = position.x; display.view.y = position.y; display.view.rotation = position.rotation; } } class RenderProcess implements IProcess { private var targets:Vector.<IRenderable>; public function update( time:Number ):void { for each( var target:IRenderable in targets ) { target.render(); } } }
ããã«ãªããŸãïŒ
class RenderData { public var display:DisplayComponent; public var position:PositionComponent; } class RenderProcess implements IProcess { private var targets:Vector.<RenderData>; public function update( time:Number ):void { for each( var target:RenderData in targets ) { target.display.view.x = target.position.x; target.display.view.y = target.position.y; target.display.view.rotation = target.position.rotation; } } }
ãããŠããïŒ
interface IMoveable { function move( time:Number ); } class Moveable implements IMoveable { public var position:PositionComponent; public var velocity:VelocityComponent; public function move( time:Number ):void { position.x += velocity.velocityX * time; position.y += velocity.velocityY * time; position.rotation += velocity.angularVelocity * time; } } class MoveProcess implements IProcess { private var targets:Vector.<IMoveable>; public function move( time:Number ):void { for each( var target:Moveable in targets ) { target.move( time ); } } }
ããã«ãªããŸãïŒ
class MoveData { public var position:PositionComponent; public var velocity:VelocityComponent; } class MoveProcess implements IProcess { private var targets:Vector.<MoveData>; public function move( time:Number ):void { for each( var target:MoveData in targets ) { target.position.x += target.velocity.velocityX * time; target.position.y += target.velocity.velocityY * time; target.position.rotation += target.velocity.angularVelocity * time; } } }
ãªããããããã®ãã¯ããã«ã¯ããããªããããããŸããããç§ãä¿¡é ŒããŠãã ããã ã€ã³ã¿ãŒãã§ã€ã¹ã®å¿
èŠæ§ããªãããããã»ã¹ã¯ããéèŠãªããšãããŠããŸããIRenderableãŸãã¯IMovableã®å®è£
ã§äœæ¥ãå§ä»»ãã代ããã«ã圌ã¯èªåã§äœæ¥ãè¡ããŸãã
æåã®æçœãªçµè«ã¯ãã¬ã³ããŒã³ãŒããRenderProcessã«ããããããã¹ãŠã®ãšã³ãã£ãã£ãåãã¬ã³ããªã³ã°ã¡ãœãããæã£ãŠããå¿
èŠããããšããããšã§ãã ããããããã ãã§ã¯ãããŸããã ããšãã°ãRenderMovieClipãšRenderBitmapã®2ã€ã®ããã»ã¹ãäœæã§ããŸãããããã®ããã»ã¹ã¯ãããŸããŸãªãšã³ãã£ãã£ã»ããã§æäœã§ããŸãã ãããã£ãŠãã³ãŒãã®æè»æ§ã倱ãããããšã¯ãããŸããã
ãšã³ãã£ãã£ã倧å¹
ã«ãªãã¡ã¯ã¿ãªã³ã°ããŠãããçè§£ããããåé¢ãšã·ã³ãã«ãªæ§æã®ã¢ãŒããã¯ãã£ãå®çŸããããšãã§ããŸãã ãªãã¡ã¯ã¿ãªã³ã°ã¯è³ªåããå§ãŸããŸãã
å€ã¯ã©ã¹ãå¿
èŠã§ããïŒ
çŸæç¹ã§ã¯ãç§ãã¡ã®æ¬è³ª
class Spaceship { public var moveData:MoveData; public var renderData:RenderData; }
2ã€ã®ã¯ã©ã¹ãå«ãŸããŠããŸã
class MoveData { public var position:PositionComponent; public var velocity:VelocityComponent; } class RenderData { public var display:DisplayComponent; public var position:PositionComponent; }
ãããã®ããŒã¿ã¯ã©ã¹ã«ã¯ã3ã€ã®ã³ã³ããŒãã³ããå«ãŸããŸãã
class PositionComponent { public var x:Number; public var y:Number; public var rotation:Number; } class VelocityComponent { public var velocityX:Number; public var velocityY:Number; public var angularVelocity:Number; } class DisplayComponent { public var view:DisplayObject; }
ãããŠããããã®å€ã¯ã©ã¹ã¯2ã€ã®ããã»ã¹ã§äœ¿çšãããŸãã
class MoveProcess implements IProcess { private var targets:Vector.<MoveData>; public function move( time:Number ):void { for each( var target:MoveData in targets ) { target.position.x += target.velocity.velocityX * time; target.position.y += target.velocity.velocityY * time; target.position.rotation += target.velocity.angularVelocity * time; } } } class RenderProcess implements IProcess { private var targets:Vector.<RenderData>; public function update( time:Number ):void { for each( var target:RenderData in targets ) { target.display.view.x = target.position.x; target.display.view.y = target.position.y; target.display.view.rotation = target.position.rotation; } } }
ãããããšã³ãã£ãã£ã¯ããŒã¿ã¯ã©ã¹ãæ°ã«ããã¹ãã§ã¯ãããŸããã ãã¹ãŠã®ã³ã³ããŒãã³ãã«ã¯ããšã³ãã£ãã£èªäœã®ç¶æ
ãå«ãŸããŸãã ããŒã¿ã¯ã©ã¹ã¯ãããã»ã¹ã®å©äŸ¿æ§ã®ããã«ååšããŸãã Spaceshipã¯ã©ã¹ã«ããŒã¿ã¯ã©ã¹ã§ã¯ãªãã³ã³ããŒãã³ãèªäœãå«ãŸããããã«ãã³ãŒãããªãã¡ã¯ã¿ãªã³ã°ããŸãã
class Spaceship { public var position:PositionComponent; public var velocity:VelocityComponent; public var display:DisplayComponent; } class PositionComponent { public var x:Number; public var y:Number; public var rotation:Number; } class VelocityComponent { public var velocityX:Number; public var velocityY:Number; public var angularVelocity:Number; } class DisplayComponent { public var view:DisplayObject; }
æ
å ±ã¯ã©ã¹ãåãé€ãã代ããã«å®å®è¹ãå®çŸ©ããããã«è€åã³ã³ããŒãã³ãã䜿çšããŠãã©ã®ããã»ã¹ãããã«åœ±é¿ãäžããå¯èœæ§ãããããç¥ããšã³ãã£ãã£ã®å¿
èŠæ§ããã¹ãŠåãé€ããŸããã è¹ã«ã¯ããã®ç¶æ
ãæ±ºå®ããã³ã³ããŒãã³ããå«ãŸããŠããŸãã ãããã®ã³ã³ããŒãã³ããä»ã®å€ã¯ã©ã¹ã«çµåããå¿
èŠã¯ãçŸåšä»ã®ã¯ã©ã¹ã®è²¬ä»»ã§ãã
ã·ã¹ãã ãšããŒãã
Entity Systemãã¬ãŒã ã¯ãŒã¯ã®ã³ã¢ã®ç¹å®ã®éšåïŒåŸã§èª¬æããŸãïŒã¯ãããã»ã¹ã®å¿
èŠã«å¿ããŠãããã®ãªããžã§ã¯ããåçã«äœæããŸãã ãã®åçŽåãããã³ã³ããã¹ãã§ã¯ãå€ã¯ã©ã¹ã¯ãããã»ã¹ã䜿çšããã³ã¬ã¯ã·ã§ã³ïŒé
åããªã³ã¯ãªã¹ãããŸãã¯ãã®ä»ïŒã®ããŒããŸãã¯ãªãŒãã«ãããŸããã ãã®ãããæç¢ºã«ããããã«ãããŒãã«ååã倿ŽããŸãã
class MoveNode { public var position:PositionComponent; public var velocity:VelocityComponent; } class RenderNode { public var display:DisplayComponent; public var position:PositionComponent; }
ããã»ã¹èªäœã¯å€æŽãããŸããããããäžè¬çãªåœåèŠåãä¿æããŠããããã®ååãã·ã¹ãã ã«å€æŽããŸãã
class MoveSystem implements ISystem { private var targets:Vector.<MoveNode>; public function update( time:Number ):void { for each( var target:MoveNode in targets ) { target.position.x += target.velocity.velocityX * time; target.position.y += target.velocity.velocityY * time; target.position.rotation += target.velocity.angularVelocity * time; } } } class RenderSystem implements ISystem { private var targets:Vector.<RenderNode>; public function update( time:Number ):void { for each( var target:RenderNode in targets ) { target.display.view.x = target.position.x; target.display.view.y = target.position.y; target.display.view.rotation = target.position.rotation; } } } interface ISystem { function update( time:Number ):void; }
ãããŠãã®æ¬è³ªã¯äœã§ããïŒ
æåŸã®å€æŽ-å®å®è¹ã¯ã©ã¹ã«ã€ããŠç¹å¥ãªããšã¯ãããŸããã ã³ã³ããŒãã³ãã®åãªãã³ã³ããã§ãã ãããã£ãŠãåã«EntityãšåŒã³ãã³ã³ããŒãã³ãã®é
åãæå®ããŸãã ãããã®ã³ã³ããŒãã³ãã«ã¯ãã¯ã©ã¹ã¿ã€ããä»ããŠã¢ã¯ã»ã¹ã§ããŸãïŒãããŠãããããã©ã¹-çŽTranslatorã§è¡šç€ºããŸãïŒã
class Entity { private var components : Dictionary; public function add( component:Object ):void { var componentClass : Class = component.constructor; components[ componentClass ] = component' } public function remove( componentClass:Class ):void { delete components[ componentClass ]; } public function get( componentClass:Class ):Object { return components[ componentClass ]; } }
ãããŠãå®å®è¹ãäœæããŸãã
public function createSpaceship():void { var spaceship:Entity = new Entity(); var position:PositionComponent = new PositionComponent(); position.x = Stage.stageWidth / 2; position.y = Stage.stageHeight / 2; position.rotation = 0; spaceship.add( position ); var display:DisplayComponent = new DisplayComponent(); display.view = new SpaceshipImage(); spaceship.add( display ); engine.add( spaceship ); }
ãšã³ãžã³ã³ã¢ã¯ã©ã¹
以åã¯ããã»ã¹ãããŒãžã£ãŒãšããŠç¥ãããŠããã·ã¹ãã ãããŒãžã£ãŒãå¿ããŠã¯ãªããŸããã
class SystemManager { private var systems:PrioritisedList; public function addSystem( system:ISystem, priority:int ):void { systems.add( system, priority ); system.start(); } public function update( time:Number ):void { for each( var system:ISystem in systemes ) { system.update( time ); } } public function removeSystem( system:ISystem ):void { system.end(); systems.remove( system ); } }
ãã®ã¯ã©ã¹ã¯æ¡åŒµããããã¬ãŒã ã¯ãŒã¯ã®äžå¿ã«ãªããŸãã ã·ã¹ãã ã®ããŒããåçã«äœæããåè¿°ã®æ©èœããã®æ©èœã«è¿œå ããŸãã
ãšã³ãã£ãã£ã¯ã³ã³ããŒãã³ãã®ã¿ãæ±ããã·ã¹ãã ã¯ããŒãã®ã¿ãæ±ããŸãã
ãããŠããšã³ãã£ãã£ãšã·ã¹ãã ã®ãã¬ãŒã ã¯ãŒã¯ã宿ãããããã«ïŒç§ãæãŠãŸãããããè¯ãç¿»èš³æ¹æ³ã¯ããããŸãã-翻蚳è
ã®ã¡ã¢ïŒããšã³ãã£ãã£ã®ç£èŠããšã³ã³ãŒãããã·ã¹ãã ã倿Žããããšãã«äœ¿çšããããŒãã®ã³ã¬ã¯ã·ã§ã³ã«ã³ã³ããŒãã³ãã远å ãŸãã¯åé€ããå¿
èŠããããŸãããã®ã³ãŒãã¯ãšã³ãã£ãã£ãšã·ã¹ãã ã®äž¡æ¹ãç¥ã£ãŠãããããã²ãŒã ã®äžå¿ã«é
眮ããŸããããããšã³ãžã³ã¯ã©ã¹ãšåŒã³ãŸããããã¯ã·ã¹ãã ãããŒãžã£ãŒã®æ¡åŒµããŒãžã§ã³ã§ããåãšã³ãã£ãã£ããã³åã·ã¹ãã ã¯ã䜿çšãéå§ããã³çµäºãããšãã«ãšã³ãžã³ã¯ã©ã¹ã«è¿œå ããã³åé€ãããŸãããšã³ãžã³ã¯ã³ã³ããŒãã³ããšãšã³ãã£ãã£ã远跡ããå¿
èŠã«å¿ããŠããŒããäœæããã³åé€ãããããã®ããŒããé
åã«è¿œå ããŸãããšã³ãžã³ã¯ãå¿
èŠãªããŒãã®ã³ã¬ã¯ã·ã§ã³ãžã®ã·ã¹ãã ã¢ã¯ã»ã¹ãæäŸããŸãã public class Engine { private var entities:EntityList; private var systems:SystemList; private var nodeLists:Dictionary; public function addEntity( entity:Entity ):void { entities.add( entity );
å®éã«ã©ã®ããã«èŠãããã確èªããã«ã¯ãAsh Entity System FrameworkãããŠã³ããŒãããŠãã²ãŒã Asteroidsã®å®è£
ã確èªããŠãã ããããããã«
èŠããã«ããšã³ãã£ãã£ã·ã¹ãã ã¯ãã²ãŒã ãµã€ã¯ã«ãåçŽåããããšããæãããçãŸããŸãããããã«ãããã²ãŒã ã®ç¶æ
ã衚ããšã³ãã£ãã£ã¢ãŒããã¯ãã£ãšãã²ãŒã å
ã®ç¶æ
ã§åäœããã·ã¹ãã ãå®çŸããŸãããã·ã¹ãã ã¯ãã¬ãŒã ããšã«æŽæ°ãããŸã-ããã¯ã²ãŒã ãµã€ã¯ã«ã§ãããšã³ãã£ãã£ã¯ã³ã³ããŒãã³ãã§æ§æãããã·ã¹ãã ã¯ããããã«å¿
èŠãªã³ã³ããŒãã³ãïŒã·ã¹ãã ïŒãæã€ãšã³ãã£ãã£ã§ã®ã¿åäœããŸãããšã³ãžã³ã¯ã·ã¹ãã ãšãšã³ãã£ãã£ãç£èŠããåã·ã¹ãã ã«å¿
èŠãªã³ã³ããŒãã³ããæã€ãšã³ãã£ãã£ã®ã³ã¬ã¯ã·ã§ã³ãžã®ã¢ã¯ã»ã¹ãæäŸããŸãããã ããã·ã¹ãã ã¯å®éã«ã¯ãšã³ãã£ãã£å
šäœãåŠçããã®ã§ã¯ãªãããšã³ãã£ãã£ãæ§æããã³ã³ããŒãã³ãã®ã¿ãåŠçããŸããã¢ãŒããã¯ãã£ãæé©åããããæç¢ºã«ããããã«ãã·ã¹ãã ã¯å¿
èŠãªã³ã³ããŒãã³ããå«ãããŒãã§åäœããŸãããããã®ã³ã³ããŒãã³ãã¯ãã¹ãŠåããšã³ãã£ãã£ã«å±ããŸããEntity System Frameworkã¯ããšã³ãã£ãã£ã¯ã©ã¹ãã·ã¹ãã ãæäŸããã«ããã®ãããªã¢ãŒããã¯ãã£ã®æãåçŽãªãã¬ãŒã ã¯ãŒã¯ãæäŸããŸããå¿
èŠãªãšã³ãã£ãã£ãšã·ã¹ãã ãäœæããŠãã²ãŒã ãæ§ç¯ããŸãã翻蚳è
ã®ã¡ã¢ïŒ- - Entity Component System C++? , . , - Artemis Entity System Framework, , .
:
, :)
ãªãªãžãã«