2
\$\begingroup\$

I'm building a small game for a college project. It's quite a simple game. There are a number of dots on the screen and the player has to select them in a specific order. It's kind of a "join the dots" thing, it's for my 4 year old son to play with.

So we've been pointed towards a few game tutorials by the college, I've been studying one of them, and I'm currently at this point:

http://www.javacodegeeks.com/2011/07/android-game-development-game-loop.html

However, I'm a little stuck here as this is where my app deviates from the tutorial. There is nothing moving on my screen, just pictures of dots that change colour when they are touched. At the moment I'm updating the status of each dot based on the position of the users finger relative to the dots using a switch statement in the onTouchEVent() method in my SurfaceView Class.

it looks like this:

NOTE: the method .checkCurrentStatus() updates the image on the point based on whether the point has been touched or not.

public boolean onTouchEvent(MotionEvent event){

Log.i(TAG, "Event: " + event.getActionMasked());

switch(event.getAction()){

case MotionEvent.ACTION_DOWN:
    sounds.play(soundDrip, 1.0f, 1.0f, 0, 0, 1.5f);
    image.handleActionDown((int) event.getX(), (int) event.getY());

    for(LetterPoint p : capitalA){

        p.handleActionDown((int) event.getX(), (int) event.getY());
        Log.i(TAG, "Set state of point " + p + " 'isTouched()' to " + p.isTouched());
    }

    if(event.getY() > getHeight() - 50){
        gameThread.setRunning(false);
        Activity activity = (Activity) getContext();
        activity.finish();

    }else{
        Log.i(TAG, "Co-ordinates: x= " + event.getX() + " y= " + event.getY());

    }
    break;

case MotionEvent.ACTION_MOVE:

    for(int i = 0; i < capitalA.length; i++){
        capitalA[i].handleActionDown((int) event.getX(), (int) event.getY());
        Log.i(TAG, "Set state of point " + i + " 'isTouched()' to " + capitalA[i].isTouched());
        capitalA[i].checkCurrentStatus();

        if(i != 0){

            if(capitalA[i-1].getCurrentState() == LetterPoint.status.green){

                capitalA[i].setCurrentState(LetterPoint.status.orange);
                capitalA[i].checkCurrentStatus();
                Log.i(TAG, "Set state of point " + i + " to " + capitalA[i].getCurrentState().toString());
            }
        }

        if(capitalA[i].getCurrentState() == LetterPoint.status.orange && capitalA[i].isTouched()){
            capitalA[i].setCurrentState(LetterPoint.status.green);
            capitalA[i].checkCurrentStatus();
            if(!capitalA[i].isCorrectPlayed()){
                sounds.play(soundCorrect, 1.0f, 1.0f, 0, 0, 1.5f);
                capitalA[i].setCorrectPlayed(true);

            }
            Log.i(TAG, "Set state of point " + i + " to " + capitalA[i].getCurrentState().toString());
        }
    }
    break;

case MotionEvent.ACTION_UP:

    int count = 0;
    for(LetterPoint p : capitalA){
        if(p.getCurrentState() == LetterPoint.status.green) count++ ;
        Log.i(TAG, "Green count is: " + count);
    }

    if(count == capitalA.length){
        sounds.play(soundWin, 1.0f, 1.0f, 0, 0, 1.5f);

    }else{
        sounds.play(soundLoose, 1.0f, 1.0f, 0, 0, 1.5f);
        for(int i = 0; i < capitalA.length; i++){

            if(i < 1){
                capitalA[i].setCurrentState(LetterPoint.status.orange);
            }else{
                capitalA[i].setCurrentState(LetterPoint.status.red);
            }
            capitalA[i].setTouched(false);
            capitalA[i].checkCurrentStatus();
        }

    }


    break;
}

So given that all my updating is handled in the onTouchEvent() method how can I best control the frame rate of the thread? Should I just store the variables for each touch point in the SurfaceView class on every touch event then update the SurfaceView periodically from a separate update method called by the Thread? EDIT: Also, where should I call the sound effects from? the Switch statement above? the update method? the thread when I'm drawing?

\$\endgroup\$

2 Answers 2

0
\$\begingroup\$

If you don't have any animations that run on their own and the game is controled by finger touch alone then you don't need a thread but just update the Canvas of the SurfaceView on every touch event by calling a method:

  //draw screen without a thread
  public void drawScreen(){
    if (holderUI == null) return;
        try{
            cm = holderUI.lockCanvas();
            synchronized (holderUI) {   
                onDraw(cm);
            } 
        } finally {
            if (cm != null) {
                holderUI.unlockCanvasAndPost(cm);
            }
        }
}
\$\endgroup\$
5
  • \$\begingroup\$ Thanks for this. I have accepted this as the correct answer, but we've since decided to animate the points heavily on selection by the user, so we're probably going to stick with the threads. \$\endgroup\$
    – mal
    Mar 26, 2013 at 15:32
  • \$\begingroup\$ When it comes to the refresh rate, for the purpose of quality and smoothness of animation the best is to keep it at 60fps. Remember that your UI thread should not do any operations on objects in the Game thread, but only inform it what to do via variables, so these two threads will never get in conflict. \$\endgroup\$
    – Lumis
    Mar 26, 2013 at 17:06
  • \$\begingroup\$ OK, not sure if I'm clear on this. I was updating the game state and drawing to the screen in the onTouchEvent() method above. I've since removed this code and separated it into update() and draw() methods respectively. so the onTouchEvent() method now updates variables that are then checked by the update() method and game objects are updated, then the draw() method draws them. Currently the same thread calls update() and draw(), should they be seperate threads? \$\endgroup\$
    – mal
    Mar 29, 2013 at 13:06
  • \$\begingroup\$ Also, I was getting null pointer errors when the thread was trying to access an array before it was properly populated. I handled it by putting if(array[i] != null) clauses into the update() and draw() methods. This works, but is it OK to handle this problem this way? Many thanks for your help! \$\endgroup\$
    – mal
    Mar 29, 2013 at 13:08
  • \$\begingroup\$ It is correct that your game thread calls two blocks one for claculation and logic like update() and the other one drawing, that is how the games are done. I use ArrayLists, they are easier to control, add and remove objects etc. In a loop one just checks their size, but they cannot be null. You can also use a boolean flag or an integer constant like final int GAME_MODE_START = 1; so if (gameMode == GAME_MODE_START) then do some things and not do something else... \$\endgroup\$
    – Lumis
    Mar 29, 2013 at 16:43
-1
\$\begingroup\$

it might help if somewhere you use Thread.Sleep(no of milliseconds). This will cause the code to stop for n amount of time. You can still run other classes while sleep is... sleeping.

\$\endgroup\$
1
  • 2
    \$\begingroup\$ -1; Sleep is never a reliable method of controlling framerate as it only specifies a minimum time to sleep for, and has poor precision. For Java see docs.oracle.com/javase/tutorial/essential/concurrency/… - "sleep times are not guaranteed to be precise, because they are limited by the facilities provided by the underlying OS. Also, the sleep period can be terminated by interrupts, as we'll see in a later section. In any case, you cannot assume that invoking sleep will suspend the thread for precisely the time period specified". \$\endgroup\$ Mar 26, 2013 at 15:13

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .