3
\$\begingroup\$

I have a super class named Monster which implements Poolable. Then I got child classes which extends from the Monster class, but I can not figure out how I will use pool and maintain only one set of pool array.

Here is my current pool setup:

public class GameWorld {

    // Map
    private TmxMapLoader mapLoader;
    private TiledMap map;

    // Creatures
    private Player player;
    private final Array<Monster> activeMonsters = new Array<Monster>();
    private final Pool<Monster> monsterPool = new Pool<Monster>() {
        @Override
        protected Monster newObject() {
            return new Monster();
        }
    };

    public GameWorld(String path) {
        mapLoader = new TmxMapLoader();
        map = mapLoader.load(path);
        player = new Player();
        player.init("Player", this, new Vector2(5, 5));

        Monster firefox = Pools.obtain(Firefox.class);
        for (int i = 0; i <= 10; i++) {
            firefox.init("Firefox", this, new Vector2(8, 8));
            activeMonsters.add(firefox);
        }
    }

    public Player getPlayer() {
        return this.player;
    }

    public TiledMap getMap() {
        return map;
    }

    public Array<Monster> getMonsters() {
        Monster monster;
        int len = activeMonsters.size;
        for (int i = len; --i >= 0;) {
            monster = activeMonsters.get(i);
            if (monster.isVisible == false) {
                activeMonsters.removeIndex(i);
                monsterPool.free(monster);
            }
        }

        return this.activeMonsters;
    }
}
\$\endgroup\$
2
  • \$\begingroup\$ I'm not sure what you are asking. Are you asking how to know, in "newObject" (for example) what subclass of Monster to create, instead of just always creating a Monster? What is the specific problem you are having, what specifically can you "not figure out?" \$\endgroup\$
    – user1430
    Jul 18 '16 at 17:30
  • \$\begingroup\$ Example i have dragon class, rat class, bird class and so on. Which extends from the parent class. So i would like to create those "monsters" and store them into same pool array which define Monster class (parent class) \$\endgroup\$
    – Printer
    Jul 18 '16 at 18:06
2
\$\begingroup\$

The short answer is that you can't return different subclasses from a Pool. Even if you used a static variable to pass parameters to newObject(), newObject() is only called when all of the pooled objects are already being used; meaning that you would never know which subclass you are getting when you obtained a pooled object.

Before continuing down this path, you may want to ask yourself, are you creating and destroying Monsters frequently enough to require pooling?

The next logical option is to create a MonsterFactory which contains a Pool for each monster type. You can create an enum for each monster type and pass it to a "public Monster createMonster(MonsterType type)" function. That way, you still have a uniform interface to generate your monsters and only the MonsterFactoryhas to keep track of the pools. Here's an example.

public class MonsterFactory{
    public Enum MonsterType{
      BIRD,
      RAT
    };

    private final Pool<Bird> birdPool = new Pool<Bird>() {
        @Override
        protected Bird newObject() {
            return new Bird();
        }
    };
    private final Pool<Rat> ratPool = new Pool<Rat>() {
        @Override
        protected Rat newObject() {
            return new Rat();
        }
    };

    public Monster createMonster(MonsterType monsterType){
       switch(monsterType){
         case BIRD:
            return birdPool.obtain();
         case RAT:
            return ratPool.obtain();
       }
    }

    //You must call destroyMonster whenever you are done with the monster or the pool will leak.
    public void destroyMonster(Monster monster){
       if(monster instanceof Bird){
         birdPool.free((Bird)monster);
       }
       else if(monster instanceof Rat){
         ratPool.free((Rat)monster);
       }
    }
}

However, if you are totally opposed to creating a Pool for each subclass, use Composition Over Inheritance. Using this method, you wouldn't use sub-classes for monsters, but you would instead plug-in their behaviors.

For example, if you want your monsters to move in various ways, say ZigZag and Straight Lines, you could have an IMovement interface member inside of your monster class that defines how the monster moves. You would then create them this way

IMovement zigZagMovement = new ZigZagMovement();
IMovement straightLineMovement = new StraightLineMovement();

public Monster createMonster(MonsterType monsterType){
    Monster newMonster = monsterPool.obtain();
    if(monsterType == MonsterType.Alligator){
       newMonster.movement = zigZagMovement ;
    }
    else if(monsterType == MonsterType.Zombie){
       newMonster.movement = straightLineMovement ;
    }
    return newMonster;
}

Then in your Monster class

public class Monster extends Actor
{
    public IMovement movement;

    public void act(float deltaTime){
       movement.move(deltaTime,this); //Updates the monster's movement
    }
}
\$\endgroup\$
9
  • \$\begingroup\$ This seems promosing, well about if i destroy monsters frequently. Not destroy them, but inactive them. Since if players is not near the monster it goes to idle. So i thougt pool would be great idea for a rpg game with alot of monsters. What would you recommend? Btw, thanks for the suggestion aswell. \$\endgroup\$
    – Printer
    Jul 18 '16 at 18:08
  • \$\begingroup\$ I would probably not pool monsters in this case. Pooling is used to reduce stress on allocations and garbage collections for objects that are created and destroyed frequently. If you used pooling, you would still have to reinitialize your inactive monsters when they came into view again. Instead, each monster should have a boolean variable of whether they are active. When set to false, they should not move or draw. Then make sure that when you switch rooms in your RPG, you clear your monsters list so that the garbage collector can have them. \$\endgroup\$ Jul 18 '16 at 18:17
  • \$\begingroup\$ Oh that sounds reasonable. But i wonder, if i had a huge map and alot of monsters on that map. The array become very big and the fps drop down. Any idéa what i should do, since i already dont draw the monsters when they cannot see the player. \$\endgroup\$
    – Printer
    Jul 18 '16 at 18:27
  • \$\begingroup\$ If you have so many monsters and the isActive variable is set correctly on the inactive ones, then you may want to chunk up your maps and dynamically load neighboring sections to keep your list smaller. Make sure it is the size of the list that is causing the low FPS though. Even iterating over 1,000 inactive monsters shouldn't be much of an FPS hit. You could also try keeping a separate list of inactive monsters so that you only have to iterate over the inactive monsters once per frame to see if they should become active. \$\endgroup\$ Jul 18 '16 at 19:00
  • \$\begingroup\$ Alright Thank you for the help. I will try your suggestions out :-) \$\endgroup\$
    – Printer
    Jul 18 '16 at 19:11
0
\$\begingroup\$

If I'm not mistaken, you want to create a pool of different monster without creating many pools? If yes, just create a MonsterPool that extends Monster

public class MonsterPool<T extends Monster>  extends Pool<T>{

}

public MonsterFactory<T extends Monster> {

     Array<T> activeMonster = new Array<T>();
     MonsterPool<T> monsterPool = new MonsterPool< T>();

     public T obtainMonster () {
          return monsterPool .obtain();
     }

}

and use it like this.

new MonsterFactory<Slime.class>().obtain();
new MonsterFactory<Dinosaur.class>().obtain();
\$\endgroup\$
3
  • \$\begingroup\$ What should i add into the MonsterPool class? Can you make it work with my current setup, i'm bit confused. \$\endgroup\$
    – Printer
    Jul 18 '16 at 20:18
  • 1
    \$\begingroup\$ This doesn't avoid creating multiple pools, each pool is just wrapped up in it's own generic factory -- A needless level of indirection. Also, MonsterPool needs to implement obtain() which could be pretty tricky since you have to get the class type of T to call newInstance() on it. Seems simpler just to have a factory with multiple pools. \$\endgroup\$ Jul 18 '16 at 20:26
  • \$\begingroup\$ Any idea's then? Since i've tested make Pool of just one class and my FPS increased 200%. So i would like to use pool for all monsters but still maintain one parent pool that is monster class \$\endgroup\$
    – Printer
    Jul 18 '16 at 20:36

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.