0

I have come across a bit of a problem. I have a class called "GameScreen" which will know what level and stage has been selected. From that I can build a string to suggest something like "level1_1" or "level1_2". The problem is how do I load this class now?

I was going to use Class.forname(string) however each level is a different class so how do I pass the new operator to the class?

I am trying to achieve something like this... world = new World(worldListener); where "World" is the class such as "level1_1".

Hope that makes sense.

fireshadow52
  • 6,298
  • 2
  • 30
  • 46
Chris
  • 1,766
  • 1
  • 21
  • 36
  • doesn't make sense... are you asking about reflection? – Randy Jul 29 '11 at 23:58
  • Yeah, If I use Class c = Class.forName("java.lang.String"); how would I allow this to be created as "new" so it will not cause a null pointer? – Chris Jul 30 '11 at 00:01

4 Answers4

2

Aside from the fact that there are much better ways to implement this (see the other answers, for example), this should work (not tested, ignores exceptions, may cause abdominal distention, etc.):

public World createWorld(String levelClassName, WorldListener listener) throws Exception
{
    Class<?> clazz = Class.forName(name);
    Constructor<World> ctor = (Constructor<World>) clazz.getConstructor(WorldListener.class);
    World world = ctor.newInstance(listener);

    return world;
}
Matt Ball
  • 354,903
  • 100
  • 647
  • 710
  • 1
    Seriously, though, there are **much** better ways to design this. – Matt Ball Jul 30 '11 at 00:26
  • Thanks that works great, I can understand the abstracting way but I cant see a way around the whole "1_1" or "1_2" class parameters. – Chris Jul 30 '11 at 00:36
  • Would it just be better to create a "LevelManager" class that takes the stage and level and then calls the appropriate method within its own methods? – Chris Jul 30 '11 at 00:46
  • Consider [a more object-oriented representation for your game classes](http://stackoverflow.com/questions/2231527/). For Android, [consider making each level an activity](http://stackoverflow.com/questions/4548139/android-game-design) - no factory class to worry about at all, then, since Android manages it all for you once you configure the application. – Matt Ball Jul 30 '11 at 00:55
  • Thanks for the help, I only have one activity that is started and I have created a screen class which means I dont have to worry with the activity stack. – Chris Jul 30 '11 at 11:06
1

You must use reflection (java.lang.reflect)

First, even if the class for each level is different, all of them should extend/implement a common superclass/interface so basic operations are available (v.g. a constructor, a startLevel() method, and so on).

With reflection, you can chose the class related to your level, instantiate it, and pass it to your engine so it invokes your class.

As a side note, I find the architecture strange. Unless there is some other reason to do this, I would suggest using a unique class for levels and loading the configuration for each level from files. It may not be suited if gameplay changes between level, though.

SJuan76
  • 24,532
  • 6
  • 47
  • 87
1

See the Factory Pattern. For your case you could implement a CreateLevel(String level) method which does a simple case-statement to determine which class to create or use reflection.

Todd Smith
  • 17,084
  • 11
  • 59
  • 78
0

Um... there's 101 better ways of doing that.

Update For example:

public abstract class Level {
    // or whatever your interface is
    abstract public void createWorld(WorldListener worldListener);
    abstract public void nextWorld();
}

public class Level1 extends Level {
    public void createLevel(WorldListener worldListener) {
        /** do it **/
    }
    public Level nextLevel() { return new Level2(); }
}

Then somewhere else:

Level cur = new Level1();
do {
    cur.createLevel(worldListener);
    ...
    cur = cur.nextLevel();
} while (cur != null);

Original For example:

public abstract class Level {
    final public int number;
    public Level(int num) { this.number = num; levels[num-1] = this;/* set up level */ }

    // adjust 10 to number of levels
    static private Level[] = new Level[10];
    static public getLevel(int num) { return levels[num-1]; }

    // or whatever your interface is
    abstract public void createWorld(WorldListener worldListener);
}

public class Level1 extends Level {
    public Level1() { super(0); }
    public void createWorld(WorldListener worldListener) {
        /** do it **/
    }
}

Then somewhere else:

Level.getLevel(1).createWorld();
Charles Goodwin
  • 6,402
  • 3
  • 34
  • 63
  • I dont understand how that will work because of the abstract class. It is a better way of doing it but by calling Level.getLevel(1).createLevel() will that not throw an error because I have tried to declare an abstract class? – Chris Jul 30 '11 at 00:10
  • @Chris: no, because getLevel(1) returned a Level1 instant. – Charles Goodwin Jul 30 '11 at 00:12
  • The same problem remains though, you still have to say "= new Levelx" this app is setup to be deterministic so every level class will setup the stage different. Each Level will have a ".createlevel" field but its how to actually say "load level 1, stage 4" for instance this example would be "Level cur = new Level1_1(); – Chris Jul 30 '11 at 00:18