7
\$\begingroup\$

I've been working on a basic Android game these days, but I'm a bit uncertain about my setup and need some advice. The basics of the game are simple: there are characters running on your screen and some of them perform specific actions at specific time intervals.

The code is pretty easy to follow if you know that it will create a thread that keeps calling the onDraw() method of the Game object, which in its turn calls the onDraw of its elements.

The simplified code I have is the following:

Game.java

public class Game extends SurfaceView {

    private Bitmap bmp;
    private GameLoopThread gameLoopThread;
    private List<Unit> units = new ArrayList<Unit>();


    public Game(Context context) {
          super(context);
          //starts gameLoopThread which calls the Game's onDraw() method 10x/sec      
    }

    private void createUnits(){  
        //creates characters for the field, specifies as string their behaviour, could be later extended to load level from XML file
        units.add(createUnit(R.drawable.richjohn,Arrays.asList("drop_gold")));
        units.add(createunit(R.drawable.ladymay,null)); 
    }



    private Unit createUnit(int resource, List<String> sActions) {
        //actual creation of Unit, where strings are checked and the corresponding behavior class is created and added to the unit.
        bmp = BitmapFactory.decodeResource(getResources(), resource);
        Unit unit = new Unit(this,bmp);
        List<Action> actions = new ArrayList<Action>();
        if (sActions != null){
            for (String s : sActions){
                if (s.equals("drop_gold")){
                    actions.add(new DropGold(this,unit));
                }
            }
        }
        unit.setActions(actions);
        return unit;
    }



    @Override
    protected void onDraw(Canvas canvas) {
        //first draw background+effects+coins (not in this sample) then call the onDraw method of each unit.
        for (Unit unit : units){
            unit.onDraw(canvas);
        }

        public void addTempSprite(float x,float y, Bitmap bmp){
              //adds a coin (this is added to a separate list of sprites that are drawn before drawing the units, so they are part of the background)
        }
    }

Unit.java

public class Unit {
    private int x;
    private int y;
    private Game gameView;
    private Bitmap bmp;//sprite
    private List<Action> actions;


    public Unit(Game gameView,  Bitmap bmp){
        this.gameView = gameView;
        this.bmp = bmp;
        //set random x,y,speeds
    }

    public void setActions(List<Action> actions){
        this.actions = actions;
    }

    private void update(){
        //first calculate new position based on directions of speed and current position
        //then call the execute method of all related actions.
        for(Action a : this.actions){
            a.execute();
        }
    }

    public void onDraw(Canvas canvas){
        //update the position, perform actions
        update();
        //draw image based on new coordinates
        canvas.drawBitmap(bmp, x, y, null);
    }
}

Action.Java

public interface Action {

    public void execute();
}

DropGold.Java

public class DropGold implements Action{

    private int tick;
    private int interval = 50;
    private Game game;
    private Unit unit;
    private int resource;

    public DropGold(Game game, Unit unit){
        this.game = game;
        this.unit = unit;
        this.tick = 0;
        this.resource = R.drawable.coin2;
    }

    public void execute(){
        tick++;
        if (tick == interval){
            tick = 0;
            game.addTempSprite(unit.getX(), unit.getY(), BitmapFactory.decodeResource(gameView.getResources(), resource));
        }
    }
}
  1. Is it a good idea to create Units dynamically like this? This way they can have multiple actions like dropping coins, teleporting, becoming invisible, all after a specific amount of ticks. These actions can be invoked by powerups etc.

    I thought this was the use of the Strategy pattern, but I could be wrong, since I'm new to patterns.

    I admit that the creation of the Units (by means of the String) is pretty ugly, but I thought it could be useful if I wanted to load levels from an XML file.

  2. I would like to have specific actions that occur when 2 units make a collision on the screen. discovering a collision part is easy, but since I do not use inheritance at this point, discovering the kind of unit can be difficult.

    What is the best approach for this? Like, if I have a hero character, if a bad character hits him he should die?

\$\endgroup\$
  • \$\begingroup\$ Could you add the code for the GameLoopThread ? You might not do things correctly with that one. \$\endgroup\$ – Simon Forsberg Dec 15 '14 at 10:54
6
\$\begingroup\$
//starts gameLoopThread which calls the Game's onDraw() method 10x/sec

I don't think that's a good approach. onDraw() should be called by the Android framework, not by your code. It is automatically called by Android after a call to invalidate().


private Bitmap bmp;

This should definitely be a private variable inside the createUnit method.


if (sActions != null){
    for (String s : sActions){
        if (s.equals("drop_gold")){
            actions.add(new DropGold(this,unit));
        }
    }
}

Checking if a list is not null is a bit dirty. Avoid using null when you're dealing with lists, use an empty list instead.

I don't like that you are passing on a list of Strings to this method. You aren't loading from XML currently, you are doing things programmatically. So I would pass a List<Action> to the method. Then, later when you are loading from XML you can check the strings in the XML and map those to actions this way.

Is it a good idea to create Units dynamically like this? This way they can have multiple actions like dropping coins, teleporting, becoming invisible, all after a specific amount of ticks. These actions can be invoked by powerups etc.

Yes it is a good idea, and yes I would also call that Strategy Pattern.


I have a feeling that using some interval for your actions will be very common, so you can abstract that functionality into a IntervalAction with the constructor IntervalAction(int interval, Action action).

In the execute() method, you would then only check for the interval stuff and call the other action method:

public void execute() {
    tick++;
    if (tick == interval) {
        tick = 0;
        action.execute();
    }
}

About collisions, there are a few options:

  • Store String type (or use an enum instead of a String) inside a Unit, check what type the unit is, and then do something depending on the type.
  • Use a CollisionAction strategy pattern, similar to your current Action.

I think you should avoid using inheritance here.


If you want to code games and want to support more than just Android, I can highly recommend using Libgdx

Additionally, you might want to use an Entity-Component-System approach to your game. It is often used for games and is a way of really separating the parts of a game into their smallest possible parts, which you can then use with composition to create the game you want. I'd recommend reading an article about ECS on Gamedev.net

\$\endgroup\$
  • \$\begingroup\$ Thank you for the interesting information! I'm currently trying to learn Android, and I thought creating a game would be a good start. Perhaps I'll delve into Libgdx later. I do have a question though, namely: Do you know of a pattern or approach in order to check for collisions, since if I have 400 entities on my screen, checking them at each draw() invocation would cost me O(n²). A friend of mine suggested to keep track of a matrix of booleans for each pixel being taken, but that seems overkill to me. Thanks in advance! \$\endgroup\$ – DJanssens Dec 23 '14 at 22:03
  • 1
    \$\begingroup\$ @DJanssens Matrix of booleans does sound like a bad approach. I would recommend either using an Android game library, or perhaps dividing the map into sections, and checking entities inside a section against that section and the neighboring sections. Or you could go ahead and do the O(n^2) solution, it might be faster than you think (but don't do it inside draw(), separate the game logic from draw logic!) \$\endgroup\$ – Simon Forsberg Dec 23 '14 at 22:17
  • \$\begingroup\$ Well I'll give it a shot and I will check the performance. My code is based on a tutorial that I followed (edu4java.com/en/androidgame/androidgame3.html), they suggested to start a thread which keeped on calling the onDraw method. Would you say she's wrong? Also, libgdx is a framework, right? Not a library. Does it still involve android coding or is it just basic java combined with libgdx functions? What about phonegap? \$\endgroup\$ – DJanssens Dec 23 '14 at 22:26
  • \$\begingroup\$ @DJanssens yeah I think that's the wrong way to do it. It is better to repeatedly call invalidate(); from the onDraw itself to make it continuously repaint. Libgdx is indeed a framework, but a very good one IMO. It doesn't involve much android-specific coding but instead uses some very nice abstractions to make it multi-platform (even supports iOS!). Phonegap does not have good performance and can be very buggy in my personal experience. \$\endgroup\$ – Simon Forsberg Dec 23 '14 at 22:45
  • 1
    \$\begingroup\$ @DJanssens There is no need to use a loop at all inside the onDraw. Simply calling invalidate tells Android to repaint it on the next draw iteration (which happens continuously). To update the positions, I would either use a thread, or use Android's postRunnable. If you go with LibGDX however, that will handle this "loop" stuff for you. If you want to chat more about this, I suggest we chat in the 2nd monitor rather than continue writing comments. \$\endgroup\$ – Simon Forsberg Dec 23 '14 at 23:37

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.