using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace MessagingInCSharp
{
class Program
{
static void Main( string[] args )
{
// Create a scene manager
SceneManager sceneMgr = new SceneManager();
// Have scene manager create an entity for us, which
// automatically puts the object into the scene as well
Entity myEntity = sceneMgr.CreateEntity();
// Create a render component
RenderComponent renderComp = new RenderComponent();
// Attach render component to the entity we made
myEntity.AddComponent(renderComp);
// Set 'myEntity' position to (1, 2, 3)
MsgSetPosition msgSetPos = new MsgSetPosition(myEntity.uniqueID, 1.0f, 2.0f, 3.0f);
sceneMgr.SendMessage(msgSetPos);
Console.WriteLine("Position set to (1, 2, 3) on entity with ID: " + myEntity.uniqueID);
Console.WriteLine("Retreiving position from entity with ID: " + myEntity.uniqueID);
// Get 'myEntity' position to verify it was set properly
MsgGetPosition msgGetPos = new MsgGetPosition(myEntity.uniqueID);
sceneMgr.SendMessage(msgGetPos);
Console.WriteLine("X: " + msgGetPos.x);
Console.WriteLine("Y: " + msgGetPos.y);
Console.WriteLine("Z: " + msgGetPos.z);
}
}
public enum MessageType
{
SetPosition,
GetPosition
}
public class Vector3
{
public float x = 0.0f;
public float y = 0.0f;
public float z = 0.0f;
}
public class BaseMessage
{
public int destEntityID;
public MessageType messageType;
protected BaseMessage( int destinationEntityID, MessageType messageType )
{
this.destEntityID = destinationEntityID;
this.messageType = messageType;
}
}
public class PositionMessage : BaseMessage
{
public float x;
public float y;
public float z;
protected PositionMessage( int destinationEntityID, MessageType messageType,
float X = 0.0f, float Y = 0.0f, float Z = 0.0f) :
base(destinationEntityID, messageType)
{
this.x = X;
this.y = Y;
this.z = Z;
}
}
public class MsgSetPosition : PositionMessage
{
public MsgSetPosition( int destinationEntityID, float X, float Y, float Z ) :
base(destinationEntityID, MessageType.SetPosition, X, Y, Z)
{}
}
public class MsgGetPosition : PositionMessage
{
public MsgGetPosition( int destinationEntityID) :
base(destinationEntityID, MessageType.GetPosition, 0.0f, 0.0f, 0.0f)
{}
}
public abstract class BaseComponent
{
public virtual bool SendMessage( BaseMessage msg )
{
return false;
}
}
public class RenderComponent : BaseComponent
{
public override bool SendMessage( BaseMessage msg )
{
// Entity has a switch for any messages it cares about
switch (msg.messageType)
{
case MessageType.SetPosition:
{
// Update render mesh position/translation
Console.WriteLine("RenderComponent handling SetPosition");
}
break;
default:
return base.SendMessage(msg);
}
return true;
}
}
public class Entity
{
public int uniqueID;
public int UniqueID
{
get { return this.uniqueID; }
set { this.uniqueID = value; }
}
private Vector3 position = new Vector3();
private List<BaseComponent> components = new List<BaseComponent>();
public Entity( int uniqueID )
{
this.uniqueID = uniqueID;
}
public void AddComponent( BaseComponent component )
{
this.components.Add(component);
}
public bool SendMessage( BaseMessage msg )
{
bool messageHandled = false;
// Entity has a switch for any messages it cares about
switch (msg.messageType)
{
case MessageType.SetPosition:
{
MsgSetPosition msgSetPos = msg as MsgSetPosition;
position.x = msgSetPos.x;
position.y = msgSetPos.y;
position.z = msgSetPos.z;
messageHandled = true;
Console.WriteLine("Entity handled SetPosition");
}
break;
case MessageType.GetPosition:
{
MsgGetPosition msgGetPos = msg as MsgGetPosition;
msgGetPos.x = position.x;
msgGetPos.y = position.y;
msgGetPos.z = position.z;
messageHandled = true;
Console.WriteLine("Entity handled GetPosition");
}
break;
default:
return PassMessageToComponents(msg);
}
// If the entity didn't handle the message but the component
// did, we return true to signify it was handled by something.
messageHandled |= PassMessageToComponents(msg);
return messageHandled;
}
private bool PassMessageToComponents( BaseMessage msg )
{
bool messageHandled = false;
this.components.ForEach(c => messageHandled |= c.SendMessage(msg) );
return messageHandled;
}
}
public class SceneManager
{
private Dictionary<int, Entity> entities = new Dictionary<int,Entity>();
private static int nextEntityID = 0;
// Returns true if the entity or any components handled the message
public bool SendMessage( BaseMessage msg )
{
// We look for the entity in the scene by its ID
Entity entity;
if ( entities.TryGetValue(msg.destEntityID, out entity) )
{
// Entity was found, so send it the message
return entity.SendMessage(msg);
}
// Entity with the specified ID wasn't found
return false;
}
public Entity CreateEntity()
{
Entity newEntity = new Entity(SceneManager.nextEntityID++);
entities.Add(newEntity.UniqueID, newEntity);
return newEntity;
}
}
}
A blog by a professional game developer, about game programming and development. My posts will range in comments from beginners to game development to those at a more advanced level.
Showing posts with label messaging. Show all posts
Showing posts with label messaging. Show all posts
Saturday, February 11, 2012
Game Engine Architecture, C#
Here's the same architecture as my last two posts, but this time in C# (the last two were in Scala and C++).
Game Engine Architecture, now in Scala
In my previous post I discussed game engine architecture, object<->component hierarchy, etc. Here's the sample architecture as the last post, but instead of C++ this version is written in Scala. One thing worth noting, we get identical functionality in this Scala example, with 35% less code!
package MessagingInScala
object GameMessageType extends Enumeration {
type GameMessageType = Value
val SetPosition = Value
val GetPosition = Value
}
import GameMessageType._
class Vector3(var x: Float, var y: Float, var z: Float)
abstract class GameMessage (val destinationID: Int) {
def messageType: GameMessageType
}
abstract class PositionMessage (destinationID: Int,
var x: Float, var y: Float,
var z: Float) extends GameMessage(destinationID) {
}
class MsgSetPosition(destinationID: Int,
x: Float, y: Float,
z: Float) extends PositionMessage(destinationID, x, y, z) {
override val messageType = SetPosition
}
object MsgSetPosition {
def Apply(destinationID: Int,
x: Float, y: Float,
z: Float) = new MsgSetPosition(destinationID, x, y, z)
}
class MsgGetPosition(destinationID: Int) extends PositionMessage(destinationID, 0.0f, 0.0f, 0.0f) {
val messageType = GetPosition
}
object MsgGetPosition {
def Apply(destinationID: Int) = new MsgGetPosition(destinationID)
}
abstract class BaseComponent {
def SendMessage(message: GameMessage) = false
}
class RenderComponent extends BaseComponent {
override def SendMessage(message: GameMessage): Boolean = {
message.messageType match {
case GameMessageType.SetPosition => {
// Update render mesh position
println("RenderComponent received SetPosition")
true // Return value
}
case _ => super.SendMessage(message)
}
}
}
class Entity(ID: Int) {
private var Components: List[BaseComponent] = List()
var position: Vector3 = new Vector3(0.0f, 0.0f, 0.0f)
val uniqueID: Int = ID
def AddComponent(component: BaseComponent) {
Components = component :: Components
}
def SendMessage(message: GameMessage): Boolean = {
message.messageType match {
case GameMessageType.SetPosition => {
println("Entity received SetPosition")
var msgSetPos: MsgSetPosition = message.asInstanceOf[MsgSetPosition]
position.x = msgSetPos.x
position.y = msgSetPos.y
position.z = msgSetPos.z
PassMessageToComponents(message) // This is also the return value
}
case GameMessageType.GetPosition => {
println("Entity received GetPosition")
var msgGetPos: MsgGetPosition = message.asInstanceOf[MsgGetPosition]
msgGetPos.x = position.x
msgGetPos.y = position.y
msgGetPos.z = position.z
PassMessageToComponents(message) // This is also the return value
}
case _ => PassMessageToComponents(message) // This is also the return value
}
}
def PassMessageToComponents(message: GameMessage): Boolean = {
var messageHandled = false
Components.foreach(c => {
messageHandled |= c.SendMessage(message)
})
messageHandled
}
}
object Entity {
var nextUUID: Int = 0
def apply() = new Entity(nextUUID + 1)
}
class SceneManager {
// You don't need to type the entire HashMap path like this, I'm
// doing this so the reader understands this is not a Java HashMap
var entities: Map[Int, Entity] = Map.empty[Int, Entity]
def SendMessage(message: GameMessage): Boolean = {
if ( entities.contains(message.destinationID) ) {
entities(message.destinationID).SendMessage(message)
} else {
false
}
}
def CreateEntity(): Entity = {
val newEntity: Entity = Entity()
entities += newEntity.uniqueID -> newEntity
newEntity
}
}
object Main extends App {
val sceneMgr: SceneManager = new SceneManager
val testEntity = sceneMgr.CreateEntity()
val testRenderComp = new RenderComponent
testEntity.AddComponent(testRenderComp)
val msgSetPos: MsgSetPosition = new MsgSetPosition(testEntity.uniqueID, 1.0f, 2.0f, 3.0f)
sceneMgr.SendMessage(msgSetPos)
println("Position set to (1, 2, 3) on entity with ID " + testEntity.uniqueID)
println("Retreiving position from object with ID: " + testEntity.uniqueID)
val msgGetPos: MsgGetPosition = new MsgGetPosition(testEntity.uniqueID)
sceneMgr.SendMessage(msgGetPos)
println("X: " + msgGetPos.x)
println("Y: " + msgGetPos.y)
println("Z: " + msgGetPos.z)
}
Subscribe to:
Posts (Atom)