Keeping the Display logic clean

87 views
Skip to first unread message

JohnJohn

unread,
May 23, 2013, 11:34:48 AM5/23/13
to ash-fr...@googlegroups.com
Hi folks.

I am working on a game with Ash (this is actually my 3rd project using it).  I have run into this issue before but kinda just skipped it.  The problem is this:  I can't seem to find a CLEAN implementation of how to pass drawing data to my Display components & subsequent displayObjects.  My Display & example iGFX components looks like this:

package ds2d.entity.components
{
import flash.display.Sprite;
import ds2d.gfx.iGFX;

public class Display
{
public var isInvalidated:Boolean = true;
public var sprite:Sprite;
public function draw():void
{
if ( isInvalidated )
{
if ( sprite )
{
if ( sprite is iGFX )
iGFX( sprite ).draw();
}
isInvalidated = false;
}
}
}
}

package ds2d.gfx
{
import flash.display.Shape;
import flash.display.Sprite;
public class mGFX extends Sprite implements iGFX
{
protected var cnvs:Shape;
public function mGFX()
{
super();
cnvs = new Shape();
addChild( cnvs );
}
public function draw():void
{
var thickness:Number = ....related to another comp's prop
var color:Number = ....related to another comp's prop
var size:Number = ....related to another comp's prop

cnvs.graphics.clear();
cnvs.graphics.lineStyle( THICKNESS???, COLOR???);
cnvs.graphics.beginFill( COLOR???);
cnvs.graphics.drawCircle(0, 0, SIZE???);
cnvs.graphics.endFill();
}
}
}

Given an unrelated component's props, say size, type or life, etc... (props that are unrelated to the drawing API but may affect HOW they are drawn) how do I pass those into the iGFX implementation in a clean way?  I initially had the iGFX draw function signature like the following but didn't really like how it felt:

function draw( ... params ):void


Michael Cann

unread,
May 23, 2013, 11:56:47 AM5/23/13
to ash-fr...@googlegroups.com
Hi John,

I would say you are going about things in a non-ash way. Instead of putting the logic for drawing inside the component you should create a system or systems that contain the logic using the data contained in the components.

If you take a look at Richard's Asteroids example you can see how he accomplishes this:

Rather than having a draw function in the Display component he just takes out the display object from the Display component and adds it to the display list. Then each iteration of the game loop he updates the display object's properties with whatever is stored in the components (position, rotation etc). 

Theres nothing stopping you adding more components the "RenderNode" then using the data from there. Or if they are optional components you could do dynamic lookups for components. 

Hope this helps,
Mike




--
You received this message because you are subscribed to the Google Groups "Ash Framework" group.
To unsubscribe from this group and stop receiving emails from it, send an email to ash-framewor...@googlegroups.com.
Visit this group at http://groups.google.com/group/ash-framework?hl=en.
For more options, visit https://groups.google.com/groups/opt_out.
 
 



--
Mike Cann
http://www.mikecann.co.uk/

JohnJohn0421

unread,
May 23, 2013, 12:11:05 PM5/23/13
to ash-fr...@googlegroups.com
Thanks for reply Mike.

Yeah I see what you're saying about it being the non-ash way.  I do do that to some degree but didn't think about making the draw calls within the RenderSystem itself (whereby I pull out the graphics instance and do the drawing on it as I THINK you're suggesting).  Here is my RenderSystem:

package ds2d.entity.systems
{
import flash.display.DisplayObject;
import flash.display.Sprite;
import flash.geom.Point;
import ash.tools.ListIteratingSystem;
import ds2d.entity.components.Spatial;
import ds2d.entity.nodes.RenderNode;
import ds2d.gfx.iGFX;
import ds2d.ui.ViewStack;
public class RenderSystem extends ListIteratingSystem
{
[Inject]
public var vs:ds2d.ui.ViewStack;
public function RenderSystem()
{
super( RenderNode, updateNode, addNode, delNode );
}
private function addNode( node:RenderNode ):void
{
var s:Sprite = node.display.sprite;
if ( s )
{
s.doubleClickEnabled = true;
vs.gameLayer.addChild( s );
}
}
private function delNode( node:RenderNode ):void
{
var s:Sprite = node.display.sprite;
if ( s )
vs.gameLayer.removeChild( s );
}
private var _iGFX:iGFX;
private var _pt:Point = new Point();
private function updateNode( node:RenderNode, time:Number ):void
{
var gfx:DisplayObject = node.display.sprite;
var spatial:Spatial = node.spatial;
// var isCelestrial:Boolean = node.entity.has( Planet );
if ( node.display.isInvalidated )
{
// if ( isCelestrial )
// {
// var p:Planet = node.entity.get( Planet );
// node.display.draw({ size:p.size });
// }
//
// else
node.display.draw();
node.display.isInvalidated = false;
}
_pt.x = spatial.x //+ node.display.offset.x;
_pt.y = spatial.y //+ node.display.offset.y;
gfx.x = _pt.x;
gfx.y = _pt.y;
gfx.rotation = spatial.r;

Michael Cann

unread,
May 23, 2013, 1:15:17 PM5/23/13
to ash-fr...@googlegroups.com
Yes thats more of an ash way. Perhaps what you could also do if you wanted to make the Render system more generic is take out any specific logic and put it in its own system. 

So for example if you have special drawing routines for planets you could have "CelestialDrawingSystem" which only draws (or updates the display object) for celestial objects.


JohnJohn0421

unread,
May 23, 2013, 1:25:51 PM5/23/13
to ash-fr...@googlegroups.com
So performance-wise, say I have N specific types of renderable Entities PLUS say a generic one.... would it be more performant to:
  • Have a singular Render system that uses N+ specific drawing APIs based on a type-like entity component lookup?
  • Have N+ Render systems that contain their own singular drawing API
I tend to lean towards the 1st but not having delved too much into the performance side of Ash I am not sure.

This leads me to wonder if maybe having a new type of System that Ash could use might be of use.... say something like so:

var e:Entity = createEntityWithComponents();
e.inavlidate( CompClassA, CompClassB, ... );

Then somehow those nodes would get pushed into the list of nodes to be processed by their respective systems.

Michael Cann

unread,
May 23, 2013, 5:11:11 PM5/23/13
to ash-fr...@googlegroups.com
Well it really depends on what you mean by 'Render'. In Richards Asteroids example the RenderSystem doesnt actually render. It meerly adds and removes display objects to the display list and then updates a few properties on that display list each frame. 

In your example you may not have a "CelestialRenderingSystem" but instead a "CelestialObjectManager" which is a system that takes care of whatever logic is specific to Celestial objects. The beauty of ash is that you can start off with a load of specific systems if you like then later write a component that encapsulates that data and split it off into its own system so that it get handled generically such as rendering, physics or enemy vs player AI.



--
You received this message because you are subscribed to the Google Groups "Ash Framework" group.
To unsubscribe from this group and stop receiving emails from it, send an email to ash-framewor...@googlegroups.com.
Visit this group at http://groups.google.com/group/ash-framework?hl=en.
For more options, visit https://groups.google.com/groups/opt_out.
 
 
Reply all
Reply to author
Forward
0 new messages