Jump to content




Photo

Vaerydian: Adventures in ECS-Land

Posted by Net Gnome, 30 January 2012 · 510 views

Been working in constructing a 2D, top-down Action-RPG named Vaerydian in my modified Artemis Framework for c# called simply enough: ECSFramework. So Far its coming along well.

I've enabled the following features in the last week working on it:
  • Sprite Rendering System
  • Smart 2D camera System
  • Player Input System
  • Mouse Reticle System
  • CaveMap System (will be genericized into TileMap later on)
  • CaveMap Collision System (will be genericized into TileMapCollision later on)
  • Behavior Tree System
These systems make use (to varying degrees) of the following components:
  • AiBehavior
  • CameraFocus
  • CaveMap
  • Controllable
  • Heading
  • MapCollidable
  • MousePosition
  • Position
  • Sprite
  • Velocity
  • ViewPort
Currently it is integrated with my BehaviorLibrary (simple follow AI atm), and my WorldGeneration library (cave-map generation atm).

Entities are created in an Entity Factory, here are a couple examples:

Camera being created:

		public void createCamera()
		{
			Entity e = e_EcsInstance.create();
			e_EcsInstance.EntityManager.addComponent(e, new Velocity(5f));
			e_EcsInstance.EntityManager.addComponent(e, new ViewPort(new Vector2(540f, 337.5f), new Vector2(1080, 675)));
			e_EcsInstance.TagManager.tagEntity("CAMERA", e);
			e_EcsInstance.refresh(e);
		  
		}

Player being created:

		public void createPlayer()
		{
			Entity e = e_EcsInstance.create();
			e_EcsInstance.EntityManager.addComponent(e, new Position(new Vector2(540f, 337.5f)));
			e_EcsInstance.EntityManager.addComponent(e, new Velocity(5f));
			e_EcsInstance.EntityManager.addComponent(e, new Controllable());
			e_EcsInstance.EntityManager.addComponent(e, new Sprite("characters\\player"));
			e_EcsInstance.EntityManager.addComponent(e, new CameraFocus(150));
			e_EcsInstance.EntityManager.addComponent(e, new MapCollidable());
			e_EcsInstance.EntityManager.addComponent(e, new Heading());
			e_EcsInstance.TagManager.tagEntity("PLAYER", e);
			e_EcsInstance.refresh(e);
		}

Systems crunch over entity data:

Here is how the very simple "smart" camera system works:

class CameraFocusSystem : EntityProcessingSystem
	{
		private ComponentMapper c_PositionMapper;
		private ComponentMapper c_CameraFocusMapper;
		private ComponentMapper c_ViewportMapper;
		private Entity c_Camera;
		public CameraFocusSystem() : base() { }
		public override void initialize()
		{
			c_PositionMapper = new ComponentMapper(new Position(), e_ECSInstance);
			c_CameraFocusMapper = new ComponentMapper(new CameraFocus(), e_ECSInstance);
			c_ViewportMapper = new ComponentMapper(new ViewPort(), e_ECSInstance);
		}
		protected override void preLoadContent(Bag<Entity> entities)
		{
			c_Camera = e_ECSInstance.TagManager.getEntityByTag("CAMERA");
		}
		protected override void process(Entity entity)
		{
			Position focusPosition = (Position) c_PositionMapper.get(entity);
			CameraFocus focus = (CameraFocus) c_CameraFocusMapper.get(entity);
			ViewPort cameraView = (ViewPort)c_ViewportMapper.get(c_Camera);
			Vector2 cPos = cameraView.getOrigin();
			Vector2 fPos = focusPosition.getPosition();
			float dist,radius;
			dist = Vector2.Distance(fPos,cPos);
			radius = focus.getFocusRadius();
			if (dist > radius)
			{
				Vector2 vec = Vector2.Subtract(fPos, cPos);
				vec.Normalize();
				cPos += Vector2.Multiply(vec, dist - radius);
				cameraView.setOrigin(cPos);
			}
		}
	}

All this combined, looks as such:

Posted Image

Nothing fancy, but its running fine at a frame-locked 15ms (66fps). Unlocked it renders in under 1ms atm (reports as 0ms). The green tile is just a debug feature to help debug which tile the game currently thinks the player position is in contact with.

E right now is a following AI and P is the player (both using placeholder textures). Collision detection is very basic right now, just reversing a heading vector. It causes some interesting behavior in "hanging-up" on collision if you move anywhere close to towards the blocking tile (the two upper left E's are actually stuck until P moves further west or south). I've tried some funky vector math tricks to attempt to resolve it (bisectors w/ heading reflection, etc), but right now they are disabled due to allowing you to slide between blocking tiles. I'll likely just have to do a vector-dot product to figure angles of approach then apply a unit vector in one of the appropriate cardinal directions to allow you to slide along an edge (if anyone has a better tip, please let me know).

Next I'll likely start working on a straightforward A* pathing routine and integrate that into the behavior tree for the following AI. Likely refactoring will result as i attempt to make it iterate over several cycles... i may need to add a few new BehaviorComponent Decarator types to allow it as well.

Anyway, thats all for now.




PARTNERS