The base of an entity system

Hey, I’ve been trying to think of ways to make an entity system. I have never made one so I’m not quite sure whats efficient or not. Honestly, I don’t know how the class would look. So if someone could help me out with the base of one, thanks.

It depends. There are no silver bullets in computer science. So it depends on what your skills are like, what you want to do, etc. etc.

Try to find things in common between your entities. :slight_smile:
Their x and y coordinates?
A draw and update method?
A move method?
How about getX, getY methods?
Or you could also handle their sprites here. Animation…
If all your entities have health, why not put it here? (I wouldn’t do that, I have lots of entities that are neither drawn nor have health, so I leave that for extended classes)

If you don’t have any idea what an entity system should look like, why are you looking to write one? Most libraries factor out common patterns that the creator is already familiar with. If you just want to use an entity system, grab an existing implementation like Entreri

[quote]It depends. There are no silver bullets in computer science. So it depends on what your skills are like, what you want to do, etc. etc.
[/quote]
Yeah, I understand that. I mean how should an efficient base look like.

Ok, really I kind of figured that. I should have been more clear, I was in a hurry last night typing that.
So how should I go about IDing them? I noticed some people used a HashMap array I guess, never used one before. But is that how I would id them?

Like,


public int getEntityX(int ID) {
return ID.x;
{

I’m trying to write one so I can learn about them now. I don’t want to use any external libraries.

What matters is the interface. You should have a method that takes an Entity ID and returns an Entity. An Entity should be able to query and alter its list of Components. These are interfaces, and you should write them as interfaces first, classes after. How you implement it, whether it’s with a Map or an array or a database is then up to whatever concrete class implements the interface.

Some general tips:

[*] Int or a Long makes a decent entity ID. I’d go with Long, since it’ll give you enough IDs that you’ll never need to recycle an ID, and that has some benefits later.

[*] Start simple. Using a Map<Long,Entity> to store your entities is fine to start with. Just don’t expose it, make sure you can only get at it with methods defined on an interface.

[*] Entity shouldn’t do anything super interesting – it’s just a relation of components, that’s all. Components do all the real work.

Just to be anal, the test: (Entity system == component based) can return true or false.

Could someone give me an example of one?

This:

http://slick.cokeandcode.com/wiki/doku.php?id=entity_tutorial

It’s an example for slick, but should be easy to put in any library.

I’m just a little confused on how to use the HashMapArray.

Will someone teach me how to use the HashMap array please?

What hashmap array are you talking about?

HashMap<Int, ArrayList> entityListMap = new HashMap<Int, ArrayList>();

As you’ve noticed I’ve been trying to make my first entity system. I just still have a few questions.

Int would be the Entity id
And Entity would be every Entity alives data?

I haven’t seen quite that configuration, typically I have seen :

HashMap<Long,ArrayList<Component>> dataByEntity;

Where the long is the entity id and the ArrayList is the list of components that belong to that entity. This makes it easy to get all of the components for a given entity. Another possibility is:

HashMap<Int,ArrayList<Entity>> dataByComponent;

In this case, the Int is a Component Id. This allows you to easily get all of the entities that have a given component.

There are other (and most likely better) ways to do this as well. Like sproingie said, think about the interface. Imagine your entity system is already written and you are writing a game using it. What are the methods that your game is calling?

This is what I’ve got so far.

GameWorld.java


package com.akrillix.client;

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;

public class GameWorld extends JPanel implements ActionListener {

	Player Player;
	Monster Monster;
	MapLoader Map;
	Timer time;

	public GameWorld() throws Exception {
		Player = new Player(100,100);
		Monster = new Monster(250,250);
		Map = new MapLoader("testMap");
		addKeyListener(new AL());
		setFocusable(true);
		time = new Timer(5, this);
		time.start();
	}

	public void actionPerformed(ActionEvent e) {
		Player.move();
		Monster.randomWalkRight();
		repaint();
	}

	public void paint(Graphics g) {
		super.paint(g);
		Graphics2D g2d = (Graphics2D) g;
		Map.paint(g);
		g2d.drawImage(Player.getImage(), Player.getX(), Player.getY(), null);
		g2d.setColor(Color.GREEN);
		g2d.drawString(Player.playerName, Player.getX(), Player.getY());
		g2d.drawImage(Monster.getImage(), Monster.getX(), Monster.getY(), null);
		g2d.setColor(Color.YELLOW);
		g2d.drawString(Monster.monsterName, Monster.getX() - 17, Monster.getY());
	}

	private class AL extends KeyAdapter {
		public void keyReleased(KeyEvent e) {
			Player.keyReleased(e);
		}

		public void keyPressed(KeyEvent e) {
			Player.keyPressed(e);
		}
	}
}

Monster.java



package com.akrillix.client;

import java.awt.Image;

import javax.swing.ImageIcon;

public class Monster {
	Image jelly;
	int x, y;
	String monsterName = "Purple Jelly";
	
	public Monster(int x, int y) {
		ImageIcon i = new ImageIcon("src/jelly.png");
		jelly = i.getImage();
		this.x = x;
		this.y = y;
	}
	public int getX(){
		return x;
	}
	public int getY(){
		return y;
	}
	public Image getImage(){
		return jelly;
	}
	public String getMonsterName() {
		return monsterName;
	}
	public void randomWalkRight() {
		if(this.x < 700) {
			this.x += 2;
		}
	}
}

Player.java



package com.akrillix.client;

import java.awt.Image;
import com.akrillix.*;
import java.awt.event.KeyEvent;

import javax.swing.ImageIcon;

public class Player {
	int x, y, dx, dy, speed;
	boolean alive;
	MapLoader Map;
	GameWorld GameWorld;
	String playerName = "Admin";
	Image player;
	
	public Player(int x, int y) {
		ImageIcon i = new ImageIcon("src/player.png");
		player = i.getImage();
		this.x = x;
		this.y = y;
		speed = 3;
	}
	public void move (){
		x = x + dx;
		y = y + dy;
		if (x > 800 - 32) {
			try {
				Map = new MapLoader("testMap2");
			} catch (Exception e) {
				e.printStackTrace();
			}
			x = 5;
		}
		if(x < 1) {
			try {
				Map = new MapLoader("testMap");
			} catch (Exception e) {
				e.printStackTrace();
			}
			x = 800 - 33;
		}
	}
	public int getX(){
		return x;
	}
	public int getY(){
		return y;
	}
	public Image getImage(){
		return player;
	}
	public String getPlayerName() {
		return playerName;
	}
	public void keyPressed(KeyEvent e){
		int key = e.getKeyCode();
		if (key == KeyEvent.VK_LEFT) {
			dx = -speed;
			dy = 0;
		}
		if (key == KeyEvent.VK_RIGHT) {
			dx = speed;
			dy = 0;
		}
		if (key == KeyEvent.VK_UP) {
			dy = -speed;
			dx = 0;
		}
		if (key == KeyEvent.VK_DOWN) {
			dy = speed;
			dx = 0;
		}	
		if (key == KeyEvent.VK_SHIFT) {
			speed = 4;
		}
		if (key == KeyEvent.VK_F1 ) {
			
		}
		if (key == KeyEvent.VK_F2 ) {
			//Map.drawGrid = false;
		}
	}
	public void keyReleased(KeyEvent e){
		int key = e.getKeyCode();
		if (key == KeyEvent.VK_LEFT) {
			dx = 0;
		}
		if (key == KeyEvent.VK_RIGHT) {
			dx = 0;
		}
		if (key == KeyEvent.VK_UP) {
			dy = 0;
		}
		if (key == KeyEvent.VK_DOWN) {
			dy = 0;
		}
		if (key == KeyEvent.VK_SHIFT) {
			speed = 3;
		}
	}
}

Entity.java - Does nothing, still don’t know what to do.



package com.akrillix.client;

import java.awt.Graphics;
import java.awt.Rectangle;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;

public class Entity {
	int x;
	int y;
	int dx;
	int dy;
	HashMap<Long,ArrayList<Entity>> dataByComponent;
	SpriteSheetLoader sprite;
	Rectangle me = new Rectangle();
	Rectangle him = new Rectangle();
	
	public Entity(String sheetName, int x, int y, int rows, int columns) {
		try {
			this.sprite = new SpriteSheetLoader(sheetName, 32, 32, rows, columns);
			this.x = x;
			this.y = y;
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	public void move() {
		x += dx;
		y += dy;
	}
	
	public void setHorizontalMovement(int dx) {
		this.dx = dx;
	}
	
	public void setVerticalMovement(int dy) {
		this.dy = dy;
	}
	
	public int getHorizontalMovement() {
		return dx;
	}
	
	public int getVerticalMovement() {
		return dy;
	}
}

Other two classes are SpriteSheetLoader and MapLoader.

A couple of comments.

Typically the Monster and Player classes will inherit Entity. (In some EC systems, there are no hardcoded classes like Monster or Player just Entities but I wouldn’t start that way as I do not think it is useful).

Most Entity Systems will have a centralized EntitySystem or EntityManager type class that holds the entities and components assigned to them. So you your Entity would not have a dataByComponent method. It would instead have a getComponent method which in turn gets the data from the EntitySystem. So think about creating an EntitySystem class which has the responsibility of storing Entities and components and allows you to:

  • Get all Components for a given Entity
  • Get all Entities that have a given Component
  • Get a specific Entity’s Component.
  • Returns true if an Entity has as given Component
  • Allows you to create, delete Entities
  • Allows you to associate and disassociate components with entities.

It looks like you have two potential Components, Movement and Image (or Sprite). If you want to go the EC route and are using these as an example start with creating a Movement Component that can be applied to both Monster and Player.

I am surprised you have input handling code directly in the Player class. If I were doing this, I would have the input handling code in a separate class and have it update Player’s state as necessary.

Could you write me a simple example? I’m having a hard time understanding.

“Entity system” can mean different things depending on who you ask.

In my opinion a complex entity system that relies on total separation of logic/rendering/etc, hash maps storing components, and all that jazz (like Artemis) is complete overkill for most simple 2D games. Instead, a good “entity system” might have a base class as simple as this:

interface Entity {
    void update(int delta); //update AI, input, etc.
    void render(); //render entity
    void onCollision(Entity other); //notified that a collision is happening
    int getX();
    int getY();
}

“Oh my god – rendering, input, AI logic, and collision handling is all done in the same class! What an atrocity!”

Whatever. My entire game will be finished before you even start debugging your “super-flexible and totally logic-separated” entity system… :wink:

Having all those operations on one base class is one thing, might serve all the practical needs of your game so who really cares if they don’t contain a bunch of components, right? Putting them on a single interface however is just nonsense – they’re quite clearly different interfaces! The whole point of interfaces is that you’d split that into Updateable, Renderable, and Spatial interfaces, and then if you decide what the heck, everything has those so let’s implement them on an abstract base, then great. But naming it “Entity” doesn’t automatically mean you have an entity system.

[quote=“sproingie,post:19,topic:38702”]
That’s my point. Most “entity systems” for simple 2D games end up being a single class/interface; everything else is overkill.

Note: Of course, my code was just an example. Some 2D games might separate Entity/CollidableEntity… others might separate Entity/MovableEntity… or whatever. Point is: you generally don’t need a huge/complex “entity system” for a simple 2D game.