Friday, March 18, 2016

Inheritance versus ECS Pattern Concerns

"Should these data members become the base class that this class inherits from?"  If you've ever heard this phrase, or had any discussion involving multiple inheritance, read on!

If you've read anything about the Entity Component System design pattern (ECS), you might have dismissed it as being only relevant to game design.  But ECS short-circuits the need for inheritance - so it's worth trying to understand as a tool in your belt.

I started writing this with processing architectures in mind, because it helps to visualize how the ECS pattern seems to work.  So I will first enumerate computer processing architectures I have encountered.


From The Main Event Loop to Multi-Threaded OS

If you go back to before operating systems offered multi-tasking, code was written in a loop which waited for events, and every event was then processed.  There were several weaknesses - but we don't care for this article.

Later came multi-tasked operating systems.  They allowed events to be queued up in one (or several) tasks.  Other tasks could process event handling.  Then finally we have multi-threaded operating systems.  As more processors are available, tasks can be assigned to other processors.


But all we really need to understand is the main event loop, as it mimics the processing needed to make ECS work on a per-object basis.


The Entity Component System Pattern

Lets say you've got a bicycle class.  It has a gear data member.  And you later decide it needs to have a location too, so you create a location base class and have the bicycle inherit from location.  Seems reasonable doesn't it?  Unless you aren't always concerned with location of the bicycle.

ECS allows attaching concerns to an object dynamically.  It might help to first look at how ECS is implemented and processed in time.

In terms of time organization, the ECS pattern processes concerns in a loop, just like the old main event loop processed events.  An entity can have multiple class instances attached to it, where each instance represents a concern, and those instances can, but don't have to be, attached at run-time.

For this to work, the entity has to process through a list of all attached instances and run an update method (and maybe others).  Common methods can be called directly using polymorphism, but message sending to custom methods may require reflection, or a more sophisticated approach.

Because this architecture organizes by concerns that entity is responsible for, the overall code organization tends to avoid class inheritance.  That seems like a really big deal, and if you've never had exposure to using ECS, might expose assumptions about how code needs to be organized.

Thus a concern (the location of the bicycle) is not inherited by a bicycle class, even if bicycles have location.  Instead a bicycle will have a location concern possibly attached to it.

There are always trade-offs, and workflow for architectural design might be affected.  If you don't have to worry about inheritance as much, writing code can be more straightforward.  Also it seems easier to learn new code by visually seeing which classes are attached to entities.  But the penalty is in the ECS processing at run-time.


Wednesday, March 9, 2016

Detecting Collisions in 2D

Introduction
Let's say a game object is in 2 positions over frame updates.  The 2 positions form a line L1.  To determine if the game object collided with a line L2, we look for the presence of an intersection.

We can detect the presence of an intersection (we don't care where it is) by only looking at the slopes between L1's start point and L2's endpoints, and between L2's start point and L1's endpoints.  If L1's slope is between the 2 slopes of L1's start point and L2's endpoints, and also if L2's slope is between the 2 slopes of L2's start point and L1's endpoints, a collision occurred.


Caveats
I have not compared efficiency to other methods.  However this requires no dot product calculations thus no need for taking the cosine.  [If you know of other methods and would like to share - please post a comment!]


Process


Detect the presence of any intersection between line L1 from x1,y1 to x2,y2, and L2 from x3,y3 to x4,y4.


Figure 1, Two Lines L1 and L2



In Figure 1 above, the slopes of the lines are:

For L1, slope m1 = (y2-y1)/(x2-x1)

For L2, slope m2 = (y4-y3)/(x4-x3)

----------------------------------------------------------------------------------------------


Now we can calculate the slopes between x1,y1 and x3,y3, between x1,y1 and x4,y4, and between x3,y3 and x2, y2, as shown in Figure 2 below:



Figure 2, Additional Lines L14, L13, and L32


In Figure 2 above, the slopes of the lines are:

For L14, slope m14 = (y4-y1)/(x4-x1)

For L13, slope m13 = (y3-y1)/(x3-x1)

For L32, slope m32 = (y2-y3)/(x2-x3)

We also added L31, slope m31 = (y1-y3)/(x1-x3)


An intersection exists (and thus a collision occurred) if:

( m14 > m1 > m13 ) || (m14 < m1 < m13 )

&&

( m31 > m2 > m32 ) || (m31 < m2 < m32 )