android贪食蛇详细教程实现加源码

转载请注明出处:http://blog.csdn.net/b2569449528/article/details/78475327

工作需要开发了一个贪食蛇apk预装到公司产品,共10关。包含了游戏得分记录,升级地图切换,游戏音效,退出游戏可继续,游戏速度调节等等功能

游戏是基于重绘view机制开发的,没有使用surfaceview(因为之前已经写过一个),喜欢的可以参考下改改。英文不好大家将就着看看。

这是游戏界面实现,主要思路是通过开启一个线程,然后在线程中开启一个循环,不断的去改变蛇的位置,改变位置之后则调用刷新界面的方法重绘,实现小蛇移动。当然大家肯定也猜到了,游戏速度也是在其中控制的。

package com.example.snake.view;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.StreamCorruptedException;

import android.content.Context;
import android.content.SharedPreferences;
import android.content.res.Resources.NotFoundException;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.view.View;

import com.example.snake.R;
import com.example.snake.bean.BackGround;
import com.example.snake.bean.Food;
import com.example.snake.bean.Obstacle;
import com.example.snake.bean.Snake;
import com.example.snake.utils.LogUtils;
import com.example.snake.utils.ObjectOutputUtils;
import com.example.snake.utils.OnGameOverListener;

/**
 * @author dengjifu
 * @date 20171027
 */
public class SnakeView extends View implements Runnable {

	/*******************************************/
	private Context context;
	private BackGround backGround;
	private Snake snake;
	private Obstacle obstacle;
	private Food food;

	private Bitmap bgBitmap, snakeBitmap, obstacleBitmap, foodBitmap;

	private int width, height;
	// game state
	public static final int GAMEING = 1;
	public static final int GAME_OVER = 2;
	public static final int GAME_PAUSE = 3;
	public static final int GAME_WIN = 4;
	public static int gameState = GAMEING;
	// game is a new game or continue game
	public static final int NEW_GAME = 1;
	public static final int OLD_GAME = 2;
	public static int gameStore = NEW_GAME;

	private Thread gameThread;
	// when game over then let the Thread run end
	public static boolean endGame = false;
	// when level up then Thread sleep 1000ms
	public volatile static boolean isLevelUp = false;
	// when the application was in the background and the MainActivity is go
	// into onStop() method
	// then let the Thread sleep, until it back to front;
	public static volatile boolean sleepThread = false;
	// when the game is over,to execute the interface method and pass the length
	// of snake to calculate score
	private OnGameOverListener onGameOverListener;
	// game speed array
	public static long[] speedsArray = new long[] { 400, 350, 300, 250, 200,
			150, 120 };
	// to set the game speed
	public static long speed = speedsArray[0];

	/*******************************************/

	public void setOnGameOverListener(OnGameOverListener onGameOverListener) {
		this.onGameOverListener = onGameOverListener;
	}

	public long getSpeed() {
		return speed;
	}

	public void setSpeed(long speed) {
		SnakeView.speed = speed;
	}

	public SnakeView(Context context, AttributeSet attrs, int defStyleAttr) {
		super(context, attrs, defStyleAttr);
	}

	public SnakeView(Context context, AttributeSet attrs) {
		super(context, attrs);
	}

	public SnakeView(Context context, int width, int height) {
		super(context);
		this.context = context;
		this.width = width;
		this.height = height;
		initGame();
		gameThread = new Thread(this);
		gameThread.start();
	}

	private void initGame() {
		initBitMap();
		initBean();
		// if continue game then load the data
		if (gameStore == OLD_GAME) {
			getGameData();
		}
	}

	private void initBean() {
		backGround = new BackGround(bgBitmap, width, height);
		obstacle = new Obstacle(obstacleBitmap);
		snake = new Snake(snakeBitmap, getContext());
		food = new Food(foodBitmap, snake, obstacle);
		snake.setObstacle(obstacle);
		snake.setFood(food);
	}

	private void initBitMap() {
		bgBitmap = BitmapFactory.decodeResource(getResources(),
				R.drawable.block00);
		snakeBitmap = BitmapFactory.decodeResource(getResources(),
				R.drawable.block4);
		foodBitmap = BitmapFactory.decodeResource(getResources(),
				R.drawable.block6);
		obstacleBitmap = BitmapFactory.decodeResource(getResources(),
				R.drawable.block0);
	}

	@Override
	protected void onDraw(Canvas canvas) {
		backGround.draw(canvas);
		obstacle.draw(canvas);
		snake.draw(canvas);
		food.draw(canvas);
	}

	@Override
	public void run() {
		while (true && !endGame) {
			try {
				LogUtils.d("thread", "name="+Thread.currentThread().getName());
				long start = System.currentTimeMillis();
				while (sleepThread) {
					Thread.sleep(3000);
				}
				while(isLevelUp){
					
					Thread.sleep(2000);
					snake.initSnake();
					obstacle.initObstacle(snake.getLastLength() / snake.levelNum);
					isLevelUp = false;
					
				}
				if (gameState == GAMEING) {
					snake.move();
					// Invalidate SnakeView
					postInvalidate();
				} else if (gameState == GAME_OVER) {
					backGround.initPoint();
					if (onGameOverListener != null) {
						onGameOverListener.afterGameOver(GAME_OVER,
								calculScore());
					}
					clearCache();
					clearGameData();
					saveGameStateToshareprefernce();
					endGame = true;
				} else if (gameState == GAME_WIN) {
					backGround.initPoint();
					clearCache();
					clearGameData();
					if (onGameOverListener != null) {
						onGameOverListener.afterGameOver(GAME_WIN,
								calculScore());
					}
					saveGameStateToshareprefernce();
					endGame = true;
				}
				long end = System.currentTimeMillis();
				long time = end - start;
				if (time < speed) {
					Thread.sleep(speed - time);
				} else {

				}
			} catch (InterruptedException e) {
				LogUtils.d("thread", "interrupt name="+Thread.currentThread().getName());
			}
		}
	}

	private void saveGameStateToshareprefernce() {
		SharedPreferences.Editor edit = context.getSharedPreferences(
				"levelint", Context.MODE_PRIVATE).edit();
		edit.putInt("gameState", SnakeView.gameState);
		edit.apply();
	}

	// calculate score
	private int calculScore() {
		int eatLength = snake.getLength() + snake.getLastLength();
		int level = obstacle.getLevel();
		int Score = (int) (level * 100 + eatLength * 20 * ((600 - speed) / 100));
		return Score;
	}

	private void clearCache() {
		food.clearCache();
		snake.clearCache();
		obstacle.clearCache();
	}

	@Override
	public void onWindowFocusChanged(boolean hasWindowFocus) {
		super.onWindowFocusChanged(hasWindowFocus);
	}

	// save the game data
	public void saveGameData() {
		LogUtils.d("saveObj", "--------saveGameData----");
		ObjectOutputUtils objectOutputUtils = new ObjectOutputUtils(context);
		try {
			objectOutputUtils.outPutObj(food, "food");
			objectOutputUtils.outPutObj(snake, "snake");
			objectOutputUtils.outPutObj(obstacle, "obstacle");
		} catch (FileNotFoundException e) {
			e.printStackTrace();
			LogUtils.d("saveObj", "--saveGameData-e---" + e.getMessage());
		} catch (NotFoundException e) {
			e.printStackTrace();
			LogUtils.d("saveObj", "--saveGameData-e---" + e.getMessage());
		} catch (IOException e) {
			e.printStackTrace();
			LogUtils.d("saveObj", "--saveGameData-e---" + e.getMessage());
		}
	}

	// read game data
	public void getGameData() {
		LogUtils.d("saveObj", "--------getGameData----");
		ObjectOutputUtils objectOutputUtils = new ObjectOutputUtils(context);
		try {
			Food objFood = (Food) objectOutputUtils.inPutObj("food");
			Snake objSnake = (Snake) objectOutputUtils.inPutObj("snake");
			Obstacle objobstacle = (Obstacle) objectOutputUtils
					.inPutObj("obstacle");
			if (objFood != null && objFood.getListFood() != null
					&& objFood.getListFood().size() > 0) {
				food.setData(objFood);
			}
			if (objSnake != null && objSnake.getPosition() != null
					&& objSnake.getPosition().size() > 0) {
				snake.setData(objSnake);
			}
			if (objobstacle != null && objobstacle.getList() != null
					&& objobstacle.getList().size() > 0) {
				obstacle.setData(objobstacle);
			}
		} catch (StreamCorruptedException e) {
			e.printStackTrace();
			LogUtils.d("saveObj", "--getGameData-e---" + e.getMessage());
		} catch (FileNotFoundException e) {
			e.printStackTrace();
			LogUtils.d("saveObj", "--getGameData-e---" + e.getMessage());
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
			LogUtils.d("saveObj", "--getGameData-e---" + e.getMessage());
		} catch (NotFoundException e) {
			e.printStackTrace();
			LogUtils.d("saveObj", "--getGameData-e---" + e.getMessage());
		} catch (IOException e) {
			e.printStackTrace();
			LogUtils.d("saveObj", "--getGameData-e---" + e.getMessage());
		}
	}

	// clear data
	public void clearGameData() {
		LogUtils.d("saveObj", "--------clearGameData----");
		ObjectOutputUtils objectOutputUtils = new ObjectOutputUtils(context);
		try {
			objectOutputUtils.outPutObj(null, "food");
			objectOutputUtils.outPutObj(null, "snake");
			objectOutputUtils.outPutObj(null, "obstacle");
		} catch (FileNotFoundException e) {
			e.printStackTrace();
			LogUtils.d("saveObj", "--clearGameData-e---" + e.getMessage());
		} catch (NotFoundException e) {
			LogUtils.d("saveObj", "--clearGameData-e---" + e.getMessage());
			e.printStackTrace();
		} catch (IOException e) {
			LogUtils.d("saveObj", "--clearGameData-e---" + e.getMessage());
			e.printStackTrace();
		}
	}

	public void setDirection(int direction) {
		snake.setDIRECTION(direction);
	}

	public int getDirection() {
		return snake.getDIRECTION();
	}

}

MainActivity主要的工作呢就是实现界面初始化以及按键监听,还有一个游戏结束时的回调。

MainActivity的代码:

package com.example.snake.activity;

import android.content.Intent;
import android.os.Bundle;
import android.util.DisplayMetrics;
import android.view.KeyEvent;

import com.example.snake.bean.Snake;
import com.example.snake.utils.LogUtils;
import com.example.snake.utils.OnGameOverListener;
import com.example.snake.view.SnakeView;
/**
 * @author dengjifu
 * @date 20171027
 */
public class MainActivity extends BaseActivity implements OnGameOverListener{

	SnakeView snakeView;
	
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);

		DisplayMetrics metric = new DisplayMetrics();
		getWindowManager().getDefaultDisplay().getMetrics(metric);
		int width = metric.widthPixels; //width px
		int height = metric.heightPixels; // height px

		snakeView = new SnakeView(this, width, height);
		
		setContentView(snakeView);
		
		snakeView.setClickable(false);
		snakeView.setOnGameOverListener(this);
	}

	@Override
	public boolean onKeyDown(int keyCode, KeyEvent event) {
		switch (keyCode) {
		case KeyEvent.KEYCODE_DPAD_LEFT:
			if(snakeView.getDirection()!=Snake.RIGHT && !Snake.isDirectionPressed){
				snakeView.setDirection(Snake.LEFT);
				Snake.isDirectionPressed = true;
			}
			return true;
		case KeyEvent.KEYCODE_DPAD_UP:
			if(snakeView.getDirection()!=Snake.BOTTOM && !Snake.isDirectionPressed){
				snakeView.setDirection(Snake.TOP);
				Snake.isDirectionPressed = true;
			}
			return true;
		case KeyEvent.KEYCODE_DPAD_RIGHT:
			if(snakeView.getDirection()!=Snake.LEFT && !Snake.isDirectionPressed){
				snakeView.setDirection(Snake.RIGHT);
				Snake.isDirectionPressed = true;
			}
			return true;
		case KeyEvent.KEYCODE_DPAD_DOWN:
			if(snakeView.getDirection()!=Snake.TOP && !Snake.isDirectionPressed){
				snakeView.setDirection(Snake.BOTTOM);
				Snake.isDirectionPressed = true;
			}
			return true;
		case KeyEvent.KEYCODE_ENTER:
//			if(SnakeView.gameState!=SnakeView.GAME_PAUSE){
//				SnakeView.gameState = SnakeView.GAME_PAUSE;
//			}else {
//				SnakeView.gameState = SnakeView.GAMEING;
//			}
			return true;
		}
		return super.onKeyDown(keyCode, event);
	}
	
	@Override
	public void onBackPressed() {
		SnakeView.endGame = true;
		snakeView.saveGameData();
		LogUtils.d("saveObj", "-------onBackPressed--------");
		MainActivity.this.finish();
	}

	@Override
	public void afterGameOver(int game,int score) {
		Intent intent = new Intent(this, DialogActivity.class);
		intent.putExtra("game", game);
		intent.putExtra("score", score);
		startActivity(intent);
		MainActivity.this.finish();
	}

	@Override
	protected void onPause() {
		super.onPause();
	}
	
	@Override
	protected void onDestroy() {
		super.onDestroy();
	}
	
	@Override
	protected void onStop() {
		SnakeView.sleepThread = true;
		snakeView.saveGameData();
		LogUtils.d("saveObj", "-------onStop--------");
		super.onStop();
	}
	
	@Override
	protected void onRestart() {
		LogUtils.d("saveObj", "-------onRestart--------");
		SnakeView.sleepThread = false;
		super.onRestart();
	}
}

代码比较多就不一一贴出来了,喜欢的可以去github上下载,别忘了给我个start哦!谢谢大家,下面是贴图。


截图如下:

android贪食蛇详细教程实现加源码_第1张图片android贪食蛇详细教程实现加源码_第2张图片android贪食蛇详细教程实现加源码_第3张图片android贪食蛇详细教程实现加源码_第4张图片android贪食蛇详细教程实现加源码_第5张图片android贪食蛇详细教程实现加源码_第6张图片android贪食蛇详细教程实现加源码_第7张图片

原文链接:http://blog.csdn.net/b2569449528/article/details/78475327

下载链接:

http://download.csdn.net/download/b2569449528/10108784

GitHub链接:

https://github.com/1994jeff/MyDemo

你可能感兴趣的:(Android学习之路)