Android Open Source - Snake Game






From Project

Back to project page Snake.

License

The source code is released under:

GNU General Public License

If you think the Android project Snake 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

/*
Snake - an Android Game/*from   ww  w  .  j a  v a  2 s.  c o m*/
Copyright 2012 Nick Eyre <nick@nickeyre.com>

Snake is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

Snake is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with Snake.  If not, see <http://www.gnu.org/licenses/>.
*/

package com.nickeyre.snake;

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

import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.drawable.ShapeDrawable;
import android.graphics.drawable.shapes.RectShape;
import android.view.View;
import android.widget.TextView;

public class Game extends View {

  private boolean setupComplete = false;
  private int pxSquare, squaresWidth, squaresHeight,sqBorder=0,padding=0;
  private ArrayList<Block> walls;
  public Snake snake;
  private Food food;
  private Random random;
  private TextView scoreView;
  private GameScreen mActivity;
  public boolean gameOver=false;
  private int score,frameRate;
  private boolean darkTheme,classicMode,snakeOriented;

  public Game(Context context,GameScreen activity,TextView scoreView,boolean darkTheme,boolean classicMode,boolean snakeOriented,int speed) {
    super(context);
    mActivity = activity;
    random = new Random();
    this.scoreView = scoreView;
    this.darkTheme = darkTheme;
    this.classicMode = classicMode;
    this.snakeOriented = snakeOriented;
    this.frameRate = 5*(speed+1);
  }

  // If User Scores
  private void score(){
    score++;
    scoreView.setText(Integer.toString(this.score));
  }

  // Draw View
  @SuppressLint("DrawAllocation")
  protected void onDraw(Canvas canvas){
    if(!setupComplete) {
      setup();
      this.invalidate();
      return;
    }

    //Draw Walls
    for(Block block:walls){
      block.draw(canvas);
    }

    //Move & Draw Snake
    snake.draw(canvas);

    //Draw Food
    food.draw(canvas);

    //Invalidate View After Timer, Using New Thread to prevent Blocking UI Thread
    //If Snake is Stopped, Wait and then call game over
    final View parent = this;
    if(!snake.stopped){
      new Thread(new Runnable() {
        public void run() {
          parent.postDelayed(new Runnable() {
            public void run() {
              parent.invalidate();
            }
          },1000/frameRate);
        }
      }).start();
    }else if(gameOver){
      new Thread(new Runnable() {
        public void run() {
          parent.postDelayed(new Runnable() {
            public void run() {
              mActivity.gameOver();
            }
          },500);
        }
      }).start();
    }
  }

  // Setup View
  public void setup(){
    //Reset Score
    score = -1;
    this.score();
    gameOver=false;

    //Calculate Width of View in Inches
    int pxWidth = getWidth();
    int pxHeight = getHeight();
    int dpi = getResources().getDisplayMetrics().densityDpi;
    float inWidth = ((float) pxWidth) / dpi;
    float inHeight = ((float) pxHeight) / dpi;

    //Calculate Number of Squares Based on View Size (Minimum 15 x 15)
    squaresWidth  = (int) (inWidth * 10.0);
    squaresHeight = (int) (inHeight * 10.0);
    if(squaresHeight < 15) squaresHeight = 15;
    if(squaresWidth < 15)  squaresWidth = 15;

    //Calculate Size of Squares
    int pxSquareWidth = pxWidth / squaresWidth;
    int pxSquareHeight = pxHeight / squaresHeight;
    if(pxSquareWidth > pxSquareHeight)
      pxSquare = pxSquareHeight; //Extra Space on Sides
    else
      pxSquare = pxSquareWidth;  //Extra Space on Top

    //Calculate Padding Around & Between Squares
    padding = (pxWidth - squaresWidth * pxSquare)/2;
    if(classicMode) sqBorder = pxSquare / 20;

    //Build List of Wall Objects
    walls = new ArrayList<Block>();
    for(int j=0;j<squaresWidth;j++){
      walls.add(new Block(j,0,0));  //Top Walls
      walls.add(new Block(j,squaresHeight-1,0));  //Bottom Walls
    }for(int j=1;j<(squaresHeight-1);j++){ //Left Walls
      walls.add(new Block(0,j,0));  //Left Walls
      walls.add(new Block(squaresWidth-1,j,0)); //Right Walls
    }

    //Create Snake
    snake = new Snake();

    //Create Food
    food = new Food(snake,walls);

    setupComplete = true;
  }

  // Snake Object contains a list of blocks, knows if it is moving and
  // which direction it is moving
  public class Snake{

    public ArrayList<Block> blocks;
    private int direction,length;
    public boolean stopped=false;

    // Create Snake with 3 Blocks
    public Snake(){

      // Create Leading Block
      blocks = new ArrayList<Block>();
      blocks.add(new Block(squaresWidth/2,squaresHeight/2,1));
      length=3;

      // Calculate Random Initial Direction and Add 2 Remaining Blocks
      direction = random.nextInt(4);
      switch(direction){
        case 0: //Going Right
          blocks.add(new Block(squaresWidth/2-1,squaresHeight/2,1));
          blocks.add(new Block(squaresWidth/2-2,squaresHeight/2,1));
          break;
        case 1: //Going Down
          blocks.add(new Block(squaresWidth/2,squaresHeight/2-1,1));
          blocks.add(new Block(squaresWidth/2,squaresHeight/2-2,1));
          break;
        case 2: //Going Left
          blocks.add(new Block(squaresWidth/2+1,squaresHeight/2,1));
          blocks.add(new Block(squaresWidth/2+2,squaresHeight/2,1));
          break;
        case 3: //Going Up
          blocks.add(new Block(squaresWidth/2,squaresHeight/2+1,1));
          blocks.add(new Block(squaresWidth/2,squaresHeight/2+2,1));
      }
    }

    // Move & Draw Snake
    public void draw(Canvas canvas){
      if(!stopped) move();
      for(Block block:blocks) block.draw(canvas);
    }

    // Turn One Direction Left from Current Orientation (Snake Oriented)
    // If Not Going Left or Right, Go Left (Four Direction)
    public void turnLeft(){
      if(snakeOriented){
        this.direction -= 1;
        if(this.direction < 0) this.direction = 3;
      }else if(this.direction != 0 && this.direction != 2)
        this.direction = 2;
    }

    // Turn One Direction Right from Current Orientation (Snake Oriented)
    // If Not Going Left or Right, Go Right (Four Direction)
    public void turnRight(){
      if(snakeOriented){
        this.direction += 1;
        if(this.direction > 3) this.direction = 0;
      }else if(this.direction != 0 && this.direction != 2)
        this.direction = 0;
    }

    // If Not Going Down or Up, Go Down (Four Direction Only)
    public void turnDown(){
      if(!snakeOriented && this.direction != 1 && this.direction != 3)
        this.direction = 1;
    }

    // If Not Going Down or Up, Go Up (Four Direction Only)
    public void turnUp(){
      if(!snakeOriented && this.direction != 1 && this.direction != 3)
        this.direction = 3;
    }

    // Move Snake 1 Space in Current Direction
    public void move(){

      // Grab Current Front Block
      Block frontBlock = blocks.get(0);

      // Create New Block at Front of Snake
      Block newBlock;
      switch(direction){
        case 0: //Going Right
          newBlock = new Block(frontBlock.x+1,frontBlock.y,1);
          break;
        case 1: //Going Down
          newBlock = new Block(frontBlock.x,frontBlock.y+1,1);
          break;
        case 2: //Going Left
          newBlock = new Block(frontBlock.x-1,frontBlock.y,1);
          break;
        default:  //Going Up
          newBlock = new Block(frontBlock.x,frontBlock.y-1,1);
      }

      // If New Front Block Collides with Walls
      if(this.collides(newBlock) || newBlock.collides(walls)){
        stopped = true;
        for(Block block:blocks){
          block.setType(3);
        }
        newBlock.setType(0);
        gameOver=true;

      // If New Block is Clear
      }else{

        // Add New Block to the Front
        blocks.add(0,newBlock);

        // If Collision with Food
        if(this.collides(food)){
          food.move(this,walls);
          length++;
          score();

        // If No Collision with Food, Remove Last Block
        }else
          blocks.remove(length);
      }
    }

    // Check for Collisions with a Block
    public boolean collides(Block block){
      for(Block oneBlock:this.blocks)
        if(block.collides(oneBlock)) return true;
      return false;
    }

  }

  public class Block {
    public int x=0,y=0;
    ShapeDrawable shape;

    public Block(){}

    public Block(int x,int y,int type){
      this.x = x;
      this.y = y;

      shape = new ShapeDrawable(new RectShape());
      shape.setBounds(padding+x*pxSquare+sqBorder,padding+y*pxSquare+sqBorder,padding+(x+1)*pxSquare-sqBorder,padding+(y+1)*pxSquare-sqBorder);

      this.setType(type);
    }

    public void draw(Canvas canvas){
      shape.draw(canvas);
    }

    public boolean collides(Block block){
      return block.x == this.x && block.y == this.y;
    }

    public boolean collides(ArrayList<Block> blocks){
      for(Block block:blocks){
        if(this.collides(block)) return true;
      }
      return false;
    }

    public void setType(int type){
      switch(type){
        case 0: //If Wall, Paint Black
          if(darkTheme) shape.getPaint().setColor(Color.parseColor("#fff3f3f3"));
          else shape.getPaint().setColor(Color.BLACK);
          break;
        case 1: //If Snake, Paint Blue
          shape.getPaint().setColor(Color.parseColor("#ff33b5e5"));
          break;
        case 2: //If Food, Paint Grey
          shape.getPaint().setColor(Color.GRAY);
          break;
        case 3: //If Collision, Paint Red
          shape.getPaint().setColor(Color.RED);
      }
    }

  }

  class Food extends Block {

    public Food(Snake snake, ArrayList<Block> blocks){
      shape = new ShapeDrawable(new RectShape());
      this.setType(2);
      this.move(snake,blocks);
    }

    public void move(Snake snake, ArrayList<Block> blocks){
      while(true){
        this.x = random.nextInt(squaresWidth-3)+1;
        this.y = random.nextInt(squaresHeight-3)+1;
        if(!snake.collides(this) && !this.collides(blocks)) break;
      }
      shape.setBounds(padding+x*pxSquare+sqBorder,padding+y*pxSquare+sqBorder,padding+(x+1)*pxSquare-sqBorder,padding+(y+1)*pxSquare-sqBorder);
    }

  }
}




Java Source Code List

com.nickeyre.snake.GameScreen.java
com.nickeyre.snake.Game.java
com.nickeyre.snake.OptionsScreen.java
com.nickeyre.snake.SnakeBackup.java
com.nickeyre.snake.TitleScreen.java