Android Open Source - RockFall-Android Game Canvas






From Project

Back to project page RockFall-Android.

License

The source code is released under:

GNU Lesser General Public License

If you think the Android project RockFall-Android listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

package eu.raffprta.rockfall.app;
//from   w  w w.  j a  va  2  s .  c o m
import android.view.*;
import android.content.*;
import android.app.*;
import android.graphics.*;
import android.util.Log;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

import eu.raffprta.rockfall.core.entity.*;
import eu.raffprta.rockfall.core.entity.Entity;
import eu.raffprta.rockfall.core.sprite.SpriteFactory;

/**
 * This class represents the main game canvas, where resources like levels, menus
 * and such are controlled.
 */

public class GameCanvas extends SurfaceView implements SurfaceHolder.Callback{

    private Activity parent;
    private Canvas canvas;
    private SurfaceHolder surface;
    private Context context;
    private SpriteFactory s;
    private EntityFactory e;
    private GameScreen screen;
    private TouchHandler touchMonitor = new TouchHandler();
    private boolean gameActive = true;

    private int moveFactor = 4;
    private Entity miner;

    private String pointsStr;


    public GameCanvas(Context context, Activity parent, GameScreen screen){
        super(context);
        // pass the resources to our sprite factory.
        s = new SpriteFactory(getResources());
        // pass the sprite factory to our entity factory
        e = new EntityFactory(s);
        // Set up a surface holder, and callback
        this.context = context;
        surface = this.getHolder();
        surface.addCallback(this);
        this.parent = parent;
        this.screen = screen;
        // This enables the capture of ACTION_DOWN (i.e. release)
        this.setLongClickable(true);
        // Add touch listener
        this.setOnTouchListener(touchMonitor);
        // Get strings
        this.pointsStr = this.context.getString(R.string.points);
    }

    public void surfaceCreated(SurfaceHolder holder){
        final int OFF = 135;
        miner = e.getMiner(getWidth() / 2, getHeight() - OFF, 2, 0);
        // Start timer and spawn initial rocks
        stopWatch.start();
        spawnRocks();
        // Start rendering thread.
        (new Thread(new GameThread())).start();
    }

    public void surfaceDestroyed(SurfaceHolder holder){

    }

    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height){

    }

    private List<Fallable> fallables = new ArrayList<Fallable>();
    private StopWatch stopWatch = new StopWatch();
    private int points = 0;
    /**
     * This handles temporal logic in the game.
     */
    private void checkTimerAndReset(StopWatch timer, long timeToElapseNano){
        if(timer.getElapsedTime() > timeToElapseNano){
            spawnRocks();
            timer.reset();
            timer.start();
        }
    }
    /**
     * This method initiates the start of the game, when the surface is drawn.
     */
    private void spawnRocks(){
        Random r = new Random();
        int initialRocks = r.nextInt(this.getWidth() >> 6);
        for(int i = 0 ; i < initialRocks; i++){
            fallables.add(getRandomRock(r.nextInt(getWidth()), -1 * r.nextInt(getHeight())));
        }
    }

    private Fallable getRandomRock(int x, int y){
        final int FALLABLES_AVAILABLE = 7;
        int theRandomNumber = (new Random()).nextInt(FALLABLES_AVAILABLE);

        switch(theRandomNumber){
            case 0:
                return (Fallable)e.getNoobKitty(x, y, 0, 2);
            case 1:
                return (Fallable)e.getIcePointedRock(x, y, 0, 4);
            case 2:
                return (Fallable)e.getIceRock(x, y, 0, 3);
            case 3:
                return (Fallable)e.getNormalRock(x, y, 0, 3);
            case 4:
                return (Fallable)e.getNormalPointedRock(x,y,0,4);
            case 5:
                return (Fallable)e.getNormalFatRock(x,y,0,2);
            case 6:
                return getRandomPowerup(x,y);
        }

        throw new RuntimeException("Unresolved error with random generation");

    }

    private Fallable getRandomPowerup(int x, int y){
        final int FALLABLES_AVAILABLE = 5;
        int theRandomNumber = (new Random()).nextInt(FALLABLES_AVAILABLE);

        switch(theRandomNumber){
            case 0:
                return (Fallable)e.getHeartUp(x, y, 0, 2);
            case 1:
                return (Fallable)e.getSpeedUp(x, y, 0, 2);
            case 2:
                return (Fallable)e.getSpeedDown(x,y,0,3);
            case 3:
                return (Fallable)e.getPointsUp(x,y,0,2);
            case 4:
                return (Fallable)e.getPointsDown(x,y,0,3);
        }

        throw new RuntimeException("Unresolved error with random generation");

    }

    private void drawAll(Canvas c){
        screen.render(0, 0, canvas, s.getBackground());
        screen.render(miner.getX(), miner.getY(), c, miner);
        drawFallables(fallables, c);
        drawHearts(c);
        screen.renderText(0, 0, c,  pointsStr + Integer.toString(points), 36);
    }


    private void drawHearts(Canvas c){
        double lives = ((Protagonist)miner).getLives();
        for(double i = 0 ; i < lives; i++){
            SpriteContainer toRender;
            if(lives - 0.5 == Math.floor(lives) && i == 0){
                toRender = s.getHeartHalf();
            }else{
                toRender = s.getHeartFull();
            }
            screen.render(getWidth() - ((int)(Math.round(i+1)) * s.getHeartFull().getSprite().getWidth() + 2), 0, c, toRender);
        }
    }

    private void drawFallables(List<Fallable> fallables, Canvas c){
        for(Fallable f : fallables)
            screen.render(f.getX(), f.getY(),c,f);
    }


    private void updateFallables(List<Fallable> fallables){
        for(int i = 0; i < fallables.size(); i++){
            if(fallables.get(i).getY() > this.getHeight() + fallables.get(i).getSprite().getHeight()) {
                fallables.remove(i);
                // The basis of the game is that every fallable dodged = 1 point.
                points++;
            }
            else
                fallables.get(i).update(fallables.get(i).getX(), fallables.get(i).getY(), 0, fallables.get(i).getVelY());
        }
    }

    final int BASE_MOVE = moveFactor;

    private void applyPowerup(Protagonist m, Powerup p){
        if(p.getId() == FallableType.HEART_UP){
            m.setLives(m.getLives() + 1);
        }
        if(p.getId() == FallableType.POINTS_UP){
            points+=10;
        }
        if(p.getId() == FallableType.POINTS_DOWN){
            points-=10;
        }
        if(p.getId() == FallableType.SPEED_DOWN){
            moveFactor = moveFactor >= BASE_MOVE ? moveFactor-=2 : moveFactor;
        }
        if(p.getId() == FallableType.SPEED_UP){
            moveFactor = moveFactor <= BASE_MOVE ? moveFactor+=2 : moveFactor;
        }
    }


    private void updateProtagonist(Protagonist e){
        // Update the protagonist's position in relation to touch.
        if(touchMonitor.getX() < miner.getX() && touchMonitor.isActivated()){
            miner.update(miner.getX(), miner.getY(), -moveFactor, 0);
        }else if (touchMonitor.getX() + miner.getSprite().getWidth() > miner.getX() && touchMonitor.isActivated()){
            miner.update(miner.getX(), miner.getY(), +moveFactor, 0);
        }else{
            miner.update(miner.getX(), miner.getY(), 0, 0);
        }

        // Check for collision with Rocks (using instanceof)
        for(int i = 0; i < fallables.size(); i++){
            if(miner.isCollidedWith(fallables.get(i)) && fallables.get(i) instanceof Rock){
                ((Protagonist)miner).setLives(((Protagonist)miner).getLives() - ((Rock)fallables.get(i)).getDamageLevel());
                fallables.remove(i);
            }else if(miner.isCollidedWith(fallables.get(i)) && fallables.get(i) instanceof Powerup){
                applyPowerup((Protagonist)miner, (Powerup)fallables.get(i));
                fallables.remove(i);
            }
        }
    }

    /**
     * This private class is a thread that executes the main game loop. The loop updates
     * 60 times per seconds whilst attempting to update the graphics as fast as possible
     * though this limit is capped at 60 FPS anyways on Android devices. The game thread
     * is fed methods from its parent public class (GameCanvas) which cater to updating the
     * game logic or the rendering to the canvas.
     */

    private class GameThread implements Runnable {

        @Override
        public void run() {
            final int TICKSET = 60;
            // Sets the timing variables.
            long lastTime = System.nanoTime();
            long timer = System.currentTimeMillis();
            // Delta regulates the distribution of ticks per second (for the updates)
            double delta = 0;

            // Frames, updates store information
            int frames = 0;
            int updates = 0;

            while (gameActive) {

                // Nanoseconds act as 1*10^9 / TICKSET
                double ns = 1000000000.0 / TICKSET;
                // Get the current time
                long now = System.nanoTime();
                // Delta gets the temporal difference and divides through by the the tick set, resulting in a fraction of 1
                delta += (now-lastTime) / ns;
                // Resets the timer.
                lastTime = now;

                // Update specific code is ran in here
                while(delta >= 1){
                    updates++;
                    delta--;
                    updateProtagonist((Protagonist)miner);
                    updateFallables(fallables);
                    checkTimerAndReset(stopWatch, 5000000000L);
                    if(((Protagonist)miner).getLives() <= 0){
                        gameActive = false;
                        break;
                    }
                }

                // Render specific code is ran in here
                canvas = surface.lockCanvas(null);
                drawAll(canvas);
                surface.unlockCanvasAndPost(canvas);
                frames++;

                // This is called when the second has passed
                if(System.currentTimeMillis() - timer > 1000){
                    // Adds one more second
                    timer += 1000;
                    // Solely for debug reasons.
                    Log.w(updates + " : UPS | " , frames + " : FPS");
                    // Reset updates & frames
                    updates = 0;
                    frames = 0;
                }


            }
            // The game loop has ended, time to switch back to the menu.
            if(!gameActive){
                canvas = surface.lockCanvas(null);
                // Render end game text, and destroy all fallables
                fallables.clear();
                drawAll(canvas);
                screen.renderText(screen.getWidth() / 6, screen.getHeight() / 2, canvas,
                context.getString(R.string.game_over) + " " + Integer.toString(points) + " " + context.getString(R.string.small_points), 80);
                surface.unlockCanvasAndPost(canvas);
                try {
                    Thread.sleep(3000);
                } catch (InterruptedException e1) {
                    e1.printStackTrace();
                }
                ((GameIntent)parent).switchToMenu();
            }
        }

    }
}




Java Source Code List

eu.raffprta.rockfall.app.GameCanvas.java
eu.raffprta.rockfall.app.GameIntent.java
eu.raffprta.rockfall.app.GameScreen.java
eu.raffprta.rockfall.app.MainGame.java
eu.raffprta.rockfall.app.MenuCanvas.java
eu.raffprta.rockfall.app.SpriteContainer.java
eu.raffprta.rockfall.app.StopWatch.java
eu.raffprta.rockfall.app.TouchHandler.java
eu.raffprta.rockfall.core.entity.AbstractEntity.java
eu.raffprta.rockfall.core.entity.EntityFactory.java
eu.raffprta.rockfall.core.entity.Entity.java
eu.raffprta.rockfall.core.entity.FallableType.java
eu.raffprta.rockfall.core.entity.Fallable.java
eu.raffprta.rockfall.core.entity.Powerup.java
eu.raffprta.rockfall.core.entity.Protagonist.java
eu.raffprta.rockfall.core.entity.Rock.java
eu.raffprta.rockfall.core.sprite.SpriteFactory.java
eu.raffprta.rockfall.core.sprite.SpriteSheet.java
eu.raffprta.rockfall.core.sprite.Sprite.java