安卓開發 貪吃蛇
阿新 • • 發佈:2020-12-12
技術標籤:安卓
GameView
package com.example.snake6.views;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.View;
import androidx.annotation. Nullable;
import com.example.snake6.control.GamePosition;
import com.example.snake6.control.GameStyle;
import com.example.snake6.control.GameType;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
public class SnakeGameView extends View {
private List<List<GameStyle> > mGameStyles = new ArrayList<>();
private List<GamePosition> mSnakePosition = new ArrayList<>();
private GamePosition mSnakeHeader;
private GamePosition mFoodPosition = new GamePosition(0, 0);
private int mStartX, mStartY;
private int mGameViewWH = getWH(getContext(), 30);
private int mGameViewSize = 20;
private int mCount = 0;
private int mSnakeLength = 3;
private int mSeep = 4;
private boolean mIsEnd = false;
private int mSnakeDirection = GameType.Right;
private Paint mGridPaint = new Paint();
private Paint mStrokePaint = new Paint();
private OnGameListener mListener;
public int getCount() {
return mCount;
}
public void setCount(int mCount) {
this.mCount = mCount;
}
private int getWH(Context context, int dpVal) {
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dpVal, context.getResources().getDisplayMetrics());
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
mStartX = w / 2 - mGameViewSize * mGameViewWH / 2;
mStartY = getWH(getContext(), 0);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int height = mStartX * 2 + mGameViewSize * mGameViewWH;
setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec), height);
}
private void init() {
mGameStyles.clear();
mSnakePosition.clear();
mCount = 0;
mSnakeLength = 3;
mSeep = 4;
mIsEnd = false;
mSnakeDirection = GameType.Right;
List<GameStyle> gameStyle;
for (int i = 0; i < mGameViewSize; i++) {
gameStyle = new ArrayList<>();
for (int j = 0; j < mGameViewSize; j++) {
gameStyle.add(new GameStyle(GameType.Grid));
}
mGameStyles.add(gameStyle);
}
mSnakeHeader = new GamePosition(10, 10);
mSnakePosition.add(new GamePosition(mSnakeHeader.getX(), mSnakeHeader.getY()));
// 生成食物
createFood();
mIsEnd = false;
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawColor(Color.BLACK);
mGridPaint.reset();
mGridPaint.setColor(Color.WHITE);
mGridPaint.setAntiAlias(true);
mStrokePaint.reset();
mStrokePaint.setAntiAlias(true);
mStrokePaint.setColor(Color.BLACK);
mStrokePaint.setStyle(Paint.Style.STROKE);
for (int i = 0; i < mGameViewSize; i++) {
for (int j = 0; j < mGameViewSize; j++) {
int left = mStartX + i * mGameViewWH;
int top = mStartY + j * mGameViewWH;
int right = left + mGameViewWH;
int bottom = top + mGameViewWH;
if (i == mSnakeHeader.getX() && j == mSnakeHeader.getY()) {
mGridPaint.setColor(new GameStyle(GameType.Head).setColor());
canvas.drawRect(left, top, right, bottom, mGridPaint);
} else {
mGridPaint.setColor(mGameStyles.get(i).get(j).setColor());
canvas.drawRect(left, top, right, bottom, mStrokePaint);
canvas.drawRect(left, top, right, bottom, mGridPaint);
}
}
}
}
public void startGame() {
init();
GameThread gameThread = new GameThread();
gameThread.start();
}
private class GameThread extends Thread {
@Override
public void run() {
while (!mIsEnd) {
moveSnake(mSnakeDirection);
refreshBody();
checkSnakeEat();
handleTail();
postInvalidate();
step();
}
}
private void step() {
try {
sleep(1000 / mSeep);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
private void checkSnakeEat() {
GamePosition headerPosition = mSnakePosition.get(mSnakePosition.size() - 1);
for (int i = 0; i < mSnakePosition.size() - 2; i++) {
GamePosition body = mSnakePosition.get(i);
if (headerPosition.getX() == body.getX() && headerPosition.getY() == body.getY()) {
mIsEnd = true;
if (mListener != null) {
mListener.gameOver();
}
}
}
if (headerPosition.getX() == mFoodPosition.getX() && headerPosition.getY() == mFoodPosition.getY()) {
mCount++;
mSnakeLength++;
if (mListener != null) {
mListener.getCount(mCount);
}
createFood();
}
}
private void createFood() {
Random random = new Random();
int foodX = random.nextInt(mGameViewSize - 1);
int foodY = random.nextInt(mGameViewSize - 1);
for (int i = 0; i < mSnakePosition.size() - 1; i++) {
if (foodX == mSnakePosition.get(i).getX() && foodY == mSnakePosition.get(i).getY()) {
foodX = random.nextInt(mGameViewSize - 1);
foodY = random.nextInt(mGameViewSize - 1);
i = 0;
}
}
mFoodPosition.setY(foodY);
mFoodPosition.setX(foodX);
refreshFood(mFoodPosition);
}
private void refreshFood(GamePosition foodPosition) {
mGameStyles.get(foodPosition.getX()).get(foodPosition.getY()).setType(GameType.Food);
}
public void setMove(int snakeDirection) {
if (snakeDirection == GameType.Left && mSnakeDirection == GameType.Right) return;
if (snakeDirection == GameType.Right && mSnakeDirection == GameType.Left) return;
if (snakeDirection == GameType.Top && mSnakeDirection == GameType.Bottom) return;
if (snakeDirection == GameType.Bottom && mSnakeDirection == GameType.Top) return;
mSnakeDirection = snakeDirection;
}
private void moveSnake(int snakeDirection) {
switch (snakeDirection) {
case GameType.Left:
if (mSnakeHeader.getX() - 1 < 0) {
mSnakeHeader.setX(mGameViewSize - 1);
} else {
mSnakeHeader.setX(mSnakeHeader.getX() - 1);
}
mSnakePosition.add(new GamePosition(mSnakeHeader.getX(), mSnakeHeader.getY()));
break;
case GameType.Right:
if (mSnakeHeader.getX() + 1 >= mGameViewSize) {
mSnakeHeader.setX(0);
} else {
mSnakeHeader.setX(mSnakeHeader.getX() + 1);
}
mSnakePosition.add(new GamePosition(mSnakeHeader.getX(), mSnakeHeader.getY()));
break;
case GameType.Top:
if (mSnakeHeader.getY() - 1 < 0) {
mSnakeHeader.setY(mGameViewSize - 1);
} else {
mSnakeHeader.setY(mSnakeHeader.getY() - 1);
}
mSnakePosition.add(new GamePosition(mSnakeHeader.getX(), mSnakeHeader.getY()));
break;
case GameType.Bottom:
if (mSnakeHeader.getY() + 1 >= mGameViewSize) {
mSnakeHeader.setY(0);
} else {
mSnakeHeader.setY(mSnakeHeader.getY() + 1);
}
mSnakePosition.add(new GamePosition(mSnakeHeader.getX(), mSnakeHeader.getY()));
break;
}
}
// 重新整理身體
private void refreshBody() {
for (GamePosition gamePosition : mSnakePosition) {
mGameStyles.get(gamePosition.getX()).get(gamePosition.getY()).setType(GameType.Body);
}
}
private void handleTail() {
int snakeLength = mSnakeLength;
// 將已經走過去的格子重置為普通格子
for (int i = mSnakePosition.size() - 1; i >= 0; i--) {
if (snakeLength >= 0) {
snakeLength--;
} else {
GamePosition position = mSnakePosition.get(i);
mGameStyles.get(position.getX()).get(position.getY()).setType(GameType.Grid);
}
}
snakeLength = mSnakeLength;
for (int i = mSnakePosition.size() - 1; i >= 0; i--) {
if (snakeLength >= 0) {
snakeLength--;
} else {
mSnakePosition.remove(i);
}
}
}
public interface OnGameListener {
void gameOver();
void getCount(int count);
}
public void setOnGameListener(OnGameListener listener) {
this.mListener = listener;
}
public SnakeGameView(Context context) {
this(context, null);
}
public SnakeGameView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public SnakeGameView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
}
GameStyle
package com.example.snake6.control;
import android.graphics.Color;
public class GameStyle {
private int type;
public GameStyle(int type) {
this.type = type;
}
public int setColor() {
switch (type) {
case GameType.Grid:
return Color.WHITE;
case GameType.Head:
return Color.RED;
case GameType.Body:
return Color.GREEN;
case GameType.Food:
return Color.parseColor("#FFB6C1");
}
return Color.WHITE;
}
public void setType(int type) {
this.type = type;
}
}
Game Type
package com.example.snake6.control;
public interface GameType {
int Grid = 1;
int Head = 2;
int Body = 3;
int Food = 4;
int Left = 1;
int Right = 2;
int Top = 3;
int Bottom = 4;
}