转载请注明出处: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哦!谢谢大家,下面是贴图。
截图如下:
原文链接:http://blog.csdn.net/b2569449528/article/details/78475327