Slick Forums

Discuss the Slick 2D Library
It is currently Wed Jun 19, 2013 3:05 am

All times are UTC




Post new topic This topic is locked, you cannot edit posts or make further replies.  [ 420 posts ]  Go to page Previous  1, 2, 3, 4, 5 ... 28  Next
Author Message
 Post subject:
PostPosted: Tue Mar 08, 2011 10:07 am 
Offline

Joined: Tue Mar 08, 2011 10:01 am
Posts: 7
Cool!

This is exactly what i've been looking for. Thanks for making the effort to port the T-Machine articles into a usable java entity system. (I was worried i'd have to do this on my own).

Definately going to take this for a whirl. Keep us updated on any changes you make to the library.

Many thanks


Top
 Profile  
 
 Post subject:
PostPosted: Tue Mar 08, 2011 10:43 am 
Offline
Game Developer
User avatar

Joined: Tue Nov 21, 2006 4:46 am
Posts: 620
Location: Iceland
A small note:
I'm now using a tag to identify "player", instead of a component. So the example of the PlayerShipControlSystem is outdated.

Here's an example of what I'm now doing:

Code:
public class PlayerUnitControlSystem extends EntitySystem implements KeyListener {
   private boolean forward;
   private boolean reverse;
   private Entity player;

   public PlayerTankMovementSystem(GameContainer container) {
      super(); // An empty system interested in no components.
      container.getInput().addKeyListener(this);
   }
   
   @Override
   public void initialize() {
      ensurePlayerEntity();
   }
   
   @Override
   protected void processEntities(ImmutableBag<Entity> entities) {
      ensurePlayerEntity();

      if (player != null) {
         updatePlayer(player);
      }
   }
   
   private void ensurePlayerEntity() {
      if (player == null)
         player = world.getTagManager().getEntity("PLAYER");
      else if(!player.isActive())
         player = null;
   }

   protected void updatePlayer(Entity e) {
      // Update the player entity
      ...
   }
      
   
   @Override
   public void keyPressed(int key, char c) {
      if (key == Input.KEY_W) {
         forward = true;
      } else if (key == Input.KEY_S) {
         reverse = true;
      }
   }

   @Override
   public void keyReleased(int key, char c) {
      if (key == Input.KEY_W) {
         forward = false;
      } else if (key == Input.KEY_S) {
         reverse = false;
      }
   }

   // Rest of KeyInput methods omitted.
}



Make sure you tag the player entity when you create it:
Code:
Entity playerUnit = EntityFactory.createControllablePlayerUnit(world);
world.getTagManager().register("PLAYER", playerUnit);


Top
 Profile  
 
 Post subject:
PostPosted: Tue Mar 08, 2011 8:44 pm 
Offline

Joined: Tue Mar 08, 2011 10:01 am
Posts: 7
Ok, that makes sense. So all the 'empty' place holder components can be removed and one can get a reference to the entity via the 'Tag'.

i.e. the Player and Enemy components that are just used to identify a entity to the system.

Nice. :)

Just tearing the example game apart in a test project now. This is some really nice stuff hey.

But a BIG paradigm shift: To think in terms of data and aspects.
I definitely think its the way to go though. I may post one or two questions later when i get more time, but for now, good job guys. I'm enjoying using the system right now.

I've got some ideas of my own on how to improve the API, but i'll play around further before i post again ;)

Any chance you have some more example code lying about preferably using some proper animated sprites and sound? I'd love to see the code for the entity systems behind that. Oh... and what about a example code showing game state (StateBasedGame) and how the systems would work with that.


Top
 Profile  
 
 Post subject:
PostPosted: Tue Mar 08, 2011 10:11 pm 
Offline
Game Developer
User avatar

Joined: Tue Nov 21, 2006 4:46 am
Posts: 620
Location: Iceland
This can all be encapsulated within a Slick GameState. Don't really need to do a lot, since setting things up and updating and rendering is done in the three methods, init, update, render, which all exists in a GameState.

Regarding the sounds, I'm doing that in another game I'm doing using Artemis. I simply have a "SoundSystem", which processes all SoundFile components, that contain the filename of the sound. The SoundSystem then creates a new Sound() for it and plays it.

Here's the code for it:
Code:
package com.tankz.systems;

import org.newdawn.slick.SlickException;
import org.newdawn.slick.Sound;

import com.artemis.ComponentMapper;
import com.artemis.Entity;
import com.artemis.EntityProcessingSystem;
import com.artemis.utils.Bag;
import com.tankz.components.SoundFile;

public class SoundSystem extends EntityProcessingSystem {
   private ComponentMapper<SoundFile> soundMapper;
   private Bag<Sound> sounds;

   public SoundSystem() {
      super(SoundFile.class);
   }

   @Override
   public void initialize() {
      sounds = new Bag<Sound>();
      soundMapper = new ComponentMapper<SoundFile>(SoundFile.class, world.getEntityManager());
   }

   @Override
   protected void process(Entity e) {
      Sound sound = sounds.get(e.getId());
      if(!sound.playing()) {
         world.deleteEntity(e); // you may not want to delete the entity, just the component.
      }
   }

   @Override
   protected void added(Entity e) {
      SoundFile soundFile = soundMapper.get(e);

      try {
         Sound sound = new Sound(soundFile.getSoundFile());
         sound.play(1, 0.3f);
         sounds.set(e.getId(), sound);
      } catch (SlickException e1) {
         e1.printStackTrace();
      }
   }

   @Override
   protected void removed(Entity e) {
      Sound sound = sounds.get(e.getId());
      sound.stop();
      sounds.set(e.getId(), null);
   }

}



Sound file component:
Code:
package com.tankz.components;

import com.artemis.Component;

public class SoundFile extends Component {
   private String soundFile;
   
   public SoundFile(String audioFile) {
      this.soundFile = audioFile;
   }

   public String getSoundFile() {
      return soundFile;
   }
}


Create the sound entity:
Code:
   public static Entity createSound(World world, String soundFileName) {
      Entity sound = world.createEntity();
      sound.addComponent(new SoundFile(soundFileName));
      sound.refresh();
      return sound;
   }



This arrangement not only separates logic from data, it also removes any dependency on a certain sound library. If you decide later not to use Slick, you can easily refactor your SoundSystem... and only that. That's the only place where the dependency on Slick's sound libraries lies.


Top
 Profile  
 
 Post subject:
PostPosted: Tue Mar 08, 2011 10:52 pm 
Offline
Game Developer
User avatar

Joined: Tue Nov 21, 2006 4:46 am
Posts: 620
Location: Iceland
I've updated the library, some minor glitches fixed.

http://gamadu.com/games/starwarrior/

(all Artemis assets are up to date)


Top
 Profile  
 
 Post subject:
PostPosted: Wed Mar 09, 2011 10:45 pm 
Offline

Joined: Wed Mar 09, 2011 10:40 pm
Posts: 49
I must have started work on my own version of the Adam Entity System around about when you did, Apple. I've spent more time on XML parsing, and less on optimization however. Would you mind if I looked at some of your solutions and borrowed from it? Right now I can render about 2500 entities with 6-10 components in a 2 threaded solution.

I'd like to share what I've got, but right now the code is kind of messy and mostly undocumented, but I hope to have a Asdroid clone ready in not too long.

Edit: Just browsing the code, and I see you have used an indexing solution to the getEntitiesPosessing problem, probably for the same reasons I did. Speed =)

Question: How much faster is Bag over Hashmap?

Edit: Image of progress
Image


Top
 Profile  
 
 Post subject:
PostPosted: Thu Mar 10, 2011 10:21 pm 
Offline
Game Developer
User avatar

Joined: Tue Nov 21, 2006 4:46 am
Posts: 620
Location: Iceland
I've set it up on SVN:
http://gamadu.com/svn/artemis/


@Uberrated

Screenie looks nice.

Bag is much faster than Hashmap. Iterating sequentially over a bag is as fast as iterating over an array[]. Hashmap is not good at that, and if you're using Hashmap then you're bound to make a system that is poor in performance. I use Bag for all my game code where I need speed. Java's collection is not good. LinkedList is dead slow, and ArrayList is really bad when it comes to removing. Bag is the perfect, but the downside is that it doesn't guarantee ordering, but you can get around that problem by not needing ordering.

I've not looked at how I could do multithreading, having systems processing in parallel in a lock-step gameloop. In theory, it could be done, but I need to think how to ensure thread-safeness of data in the components. But since the components are so concise and limited, it might be very easy.

I tested Artemis creating about 6000 rendering entities per second, and deleting them, on my machine (Q6600/8800GT). Creating/deleting entities that have nothing to render this performance can go up to millions per second.


Top
 Profile  
 
 Post subject:
PostPosted: Fri Mar 11, 2011 8:28 am 
Offline

Joined: Tue Mar 08, 2011 10:01 am
Posts: 7
Thanks for the svn access.


Top
 Profile  
 
 Post subject:
PostPosted: Fri Mar 11, 2011 8:02 pm 
Offline

Joined: Wed Mar 09, 2011 10:40 pm
Posts: 49
I think I have to seriously consider moving all my stuff over to your system, I just have to look at the workload. Right now I have BIG stack of components & systems, but perhaps I'll get the biggest performance boost by switching to Bag.

Profiling has shown that Entity.getAs, which is a double hashmap lookup under the hood, is eating some performance, the rest is eaten by GL calls, which have to do what they gotta do. Switching to bag should improve this.

As for threading: I currently have a simple yet workable way where I have all my systems in one thread, and my rendering system in another, like so:
Code:
Main thread:
            synchronized (Scheduler.lock) {
                renderer.render(gc, game, gr, camera);
            }

Scheduler thread:
    public void tick(int delta) {
        synchronized (Scheduler.lock) {
            for (EntitySystem system : systems) {

                    system.execute(gc, game, delta);

            }
        }
    }



If you run on a computer with > 1 cpu this gives signifigant performance gain, even though there are suboptimal critical sections.


Top
 Profile  
 
 Post subject:
PostPosted: Fri Mar 11, 2011 11:48 pm 
Offline
Game Developer
User avatar

Joined: Tue Nov 21, 2006 4:46 am
Posts: 620
Location: Iceland
I've found that multithreading the game engine isn't worth it until you've reached AAA-level games. For games that are within the reach of most indies a singlethreaded game loop is more than enough.

I spent a lot of time studying parallel game engines, and found that they bring a lot of baggage.


Top
 Profile  
 
 Post subject:
PostPosted: Sat Mar 12, 2011 9:29 pm 
Offline

Joined: Wed Mar 09, 2011 10:40 pm
Posts: 49
I've started porting over to your system, but I was wondering why you have set so many class members to private instead of protected? Makes it hard to expand upon. Reusing entites does not work for my setup right now, so I have to work directly with the source. Now, I realize that this might be a warning sign about how my code is glued together, but one step at the time :D

Anyway, I think you got a nice framework here, one day of fiddling and my about 35 systems and 60ish components are ported over. Some bugs to weed out still, but coming along.

As for what I'm working on: A highly flexible xml system, where every parameter can be randomized and inherited in an entity chain. Entities can spawn other entites alongside them, when the entity crashes, expires or when the length of a chain has reached a certain point. Entity creation over time is also supported. Eve rything is backed up by a .dtd file which allows for autocomplete when writing the xml. Hopefully it can be showcased alongside Artmesis, as an example of the power of Entity Component Systems.

I have to close with a question again: Have you found an elegant way to debug the entity system? I find it to be the only flaw int this otherwise magnificent idea.


Edit: I might be mistaken, or be on the wrong version, but world.deleteEntity does not remove components.


Top
 Profile  
 
 Post subject:
PostPosted: Sun Mar 13, 2011 1:58 am 
Offline
Game Developer
User avatar

Joined: Tue Nov 21, 2006 4:46 am
Posts: 620
Location: Iceland
Uberrated wrote:
I've started porting over to your system, but I was wondering why you have set so many class members to private instead of protected? Makes it hard to expand upon.

Let me know how it goes. I can't foresee all design issues and will try to make changes when it's warranted.
I'm trying to separate the public API from the internals of the framework. If I don't hide the internals, then some guys might affect something they don't know what side effects it will have. E.g., creating a new Entity instance is not permitted, the constructor is protected, and the class is final, disallowing extending. I want the framework API to guide the programmer in it's usage, not offer lots of things to do he should not be allowed to do.

Uberrated wrote:
Anyway, I think you got a nice framework here, one day of fiddling and my about 35 systems and 60ish components are ported over. Some bugs to weed out still, but coming along.

As for what I'm working on: A highly flexible xml system, where every parameter can be randomized and inherited in an entity chain. Entities can spawn other entites alongside them, when the entity crashes, expires or when the length of a chain has reached a certain point. Entity creation over time is also supported. Eve rything is backed up by a .dtd file which allows for autocomplete when writing the xml. Hopefully it can be showcased alongside Artmesis, as an example of the power of Entity Component Systems.

Sounds nice. I've worked on a data driven game like that, using XML for entity definition. I was using Spring :) Was quite powerful, but too slow for my taste. I had to have a thread instancing entities in the background because it wasn't fast enough to do realtime. You'll be surprised how many entities you need to create in a space battle of 20-30 ships. Bullets, explosions, lasers, etc. Artemis will handle that stuff nicely.


Uberrated wrote:
I have to close with a question again: Have you found an elegant way to debug the entity system? I find it to be the only flaw int this otherwise magnificent idea.

Good question. There's no easy way to just look at one entity and it's components. It's easy to debug a system, but when it comes to the state of the entity you need to dig into the EntityManager, and look at the componentsByType bag. If you know the id of the entity you can look up the right index in each of the bags to see the component for it. It's very tedious, I know. I could offer some way of retrieving all the components for a entity, e.g.:
ImmutableBag<Component> components = world.getComponents(entity);
Would that help?

Uberrated wrote:
Edit: I might be mistaken, or be on the wrong version, but world.deleteEntity does not remove components.

Thanks for catching that, clearly a serious bug. Easy to fix however, will make the changes in svn and deploy.


Top
 Profile  
 
 Post subject:
PostPosted: Sun Mar 13, 2011 8:57 am 
Offline

Joined: Wed Mar 09, 2011 10:40 pm
Posts: 49
appel wrote:
Let me know how it goes. I can't foresee all design issues and will try to make changes when it's warranted.
I'm trying to separate the public API from the internals of the framework. If I don't hide the internals, then some guys might affect something they don't know what side effects it will have. E.g., creating a new Entity instance is not permitted, the constructor is protected, and the class is final, disallowing extending. I want the framework API to guide the programmer in it's usage, not offer lots of things to do he should not be allowed to do.

Groupmanager should have an isInGroup(String, Entity) function.
Reuse of entities is great, but I need everincreasing ids to identify them uniquely in time, any reason id cant be long, and just go ++?

Edit: Poking around abit I see that not reusing ids has the unfortunate effect of increasing the bagsizes quite unnecessarily. Perhaps some sort of entity sequence number in addition to id, coupled with an Entity.equals which uses said sequence number?

appel wrote:
Sounds nice. I've worked on a data driven game like that, using XML for entity definition. I was using Spring :) Was quite powerful, but too slow for my taste. I had to have a thread instancing entities in the background because it wasn't fast enough to do realtime. You'll be surprised how many entities you need to create in a space battle of 20-30 ships. Bullets, explosions, lasers, etc. Artemis will handle that stuff nicely.

I preload everything into a DataElement class, which basically is a giant EntityFactory: I can handle 4-6k entities with about 10 components each on my 3 year old powerbook. The bottleneck right now is collision detection, which is an art and a hassle in its own right.

appel wrote:
ImmutableBag<Component> components = world.getComponents(entity);
Would that help?

That would help. I guess my design is especially hard to deal with however, as I have entities linked to entities, quickly making EntityManager browsing a pain.

appel wrote:
Thanks for catching that, clearly a serious bug. Easy to fix however, will make the changes in svn and deploy.

Fixing it locally opened up somewhat of a can of nullpointer exceptions. Hopefully you have a better overview and implementation.
Btw, IntervalEntitiyProcessingManager does not actually call begin and end in intervalProcess.

On that note, porting is basically complete. I'm now running Artemis :D Really digging grouping and tagging, finally getting rid of empty component. JProfiler shows good hotspot improvments!


Edit: I'm in love with the speeeeeed (entity counter is wrong off but still, all those ships are fireing 10 beams a second):
Image[/img]


Top
 Profile  
 
 Post subject:
PostPosted: Sun Mar 13, 2011 1:09 pm 
Offline
Game Developer
User avatar

Joined: Tue Nov 21, 2006 4:46 am
Posts: 620
Location: Iceland
I have ideas to solve the id thing.

Don't have time right now to update this, but I'll see if I can tonight.


Top
 Profile  
 
 Post subject:
PostPosted: Sun Mar 13, 2011 6:36 pm 
Offline

Joined: Wed Mar 09, 2011 10:40 pm
Posts: 49
Great! If its not too much trouble, some way to reset the system/remove all entities should be supported. There are several scenarios where this is necessary, like new level, player death, state change ect..


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic This topic is locked, you cannot edit posts or make further replies.  [ 420 posts ]  Go to page Previous  1, 2, 3, 4, 5 ... 28  Next

All times are UTC


Who is online

Users browsing this forum: No registered users and 1 guest


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB® Forum Software © phpBB Group