贪吃蛇游戏是一款经典休闲游戏,本文将在android上实现经典的贪吃蛇游戏,操作界面和以前那些游戏机一样。
该游戏的实现思路主要是在一个View中将贪吃蛇的游戏界面绘制出来,游戏空间由16*32个小方块组成,使用一个LinkedList记录当前蛇的位置和用一个变量记录食物的位置。
private int snakeFood; // 记录当前食物的位置,横坐标*100+纵坐标
private LinkedList snakeArray; // 记录蛇的位置信息,每一节的坐标和食物的一致,横坐标*100+纵坐标
新建SnakeSpace继承自View。在onDraw方法中绘制游戏空间的界面,如下代码:
@Override
protected void onDraw(Canvas canvas) {
int width = getWidth();
int height = getHeight();
int dx = width / 16;
Paint paint = new Paint();
paint.setStrokeWidth(4);
canvas.drawColor(0xffFCBD00);
canvas.drawLine(0, 0, width, 0, paint);
canvas.drawLine(width, 0, width, height, paint);
canvas.drawLine(0, height, width, height, paint);
canvas.drawLine(0, 0, 0, height, paint);
Paint paint2 = new Paint();
paint2.setColor(0x50000000);
for (int i = 0; i < 16; i++){
for (int j = 0; j < 32; j++) {
if (snakeArray.contains(i*100+j) || snakeFood == (i*100+j)){
canvas.drawRect((dx * i) + 1, (dx * j) + 1, (dx * i) + dx - 1, (dx * j) + dx - 1, paint);
}else{
canvas.drawRect((dx * i) + 1, (dx * j) + 1, (dx * i) + dx - 1, (dx * j) + dx - 1, paint2);
}
}
}
super.onDraw(canvas);
}
在代码中,首先获取width和height以便后续绘图使用,绘制空间周围的小黑边,然后双重循环绘制控制中的26*32个小方块,这里判断绘制的坐标如果是蛇或者食物,则绘制全黑的方块,否则绘制有透明度的方块。这样的话,在游戏过程中,改变蛇和食物变量的值,即可改变界面显示。
按下界面上的上下左右按键可以让蛇移动,这里将蛇移动的方法暴露出来,通过Dir参数设置移动的方向。
public static final int DIRECTION_UP = 1;
public static final int DIRECTION_DOWN = 2;
public static final int DIRECTION_LEFT = 3;
public static final int DIRECTION_RIGHT = 4;
private int direction;
public void move(int dir){
if ((dir <= 2 && direction <= 2) || (dir > 2 && direction > 2)){
return;
}
direction = dir;
}
public void move(){
int firstIndex = snakeArray.getFirst();
switch (direction){
case DIRECTION_LEFT:
if (firstIndex >= 100){
firstIndex -= 100;
}else{
return;
}
break;
case DIRECTION_UP:
if (firstIndex%100 > 0){
firstIndex -= 1;
}else{
return;
}
break;
case DIRECTION_RIGHT:
if (firstIndex < 1500){
firstIndex += 100;
}else{
return;
}
break;
case DIRECTION_DOWN:
if (firstIndex%100 < 31){
firstIndex += 1;
}else{
return;
}
break;
}
snakeArray.addFirst(firstIndex);
if (firstIndex == snakeFood){
showFood();
}else{
snakeArray.removeLast();
}
postInvalidate();
}
代码中主要是设置蛇头和蛇尾的位置,因为每一次移动只移动一步,所以都是只需要改变蛇头和蛇尾而已。在该方法中做了食物处理,即蛇吃到食物后,随机显示下一个食物,蛇身变长。
private void showFood(){
int x = (int) Math.round(Math.random() * 16);
int y = (int) Math.round(Math.random() * 32);
// 该方法存在一个很大的BUG,即可能在生成食物时会占用大量的时间甚至进入死循环,即游戏空间上已经没有合适的位置了。后续的文章中将修改这个。
while (snakeArray.contains(x*100 + y)){ // 判断直到随机产生的位置是一个空位置,
x = (int) Math.round(Math.random() * 16);
y = (int) Math.round(Math.random() * 32);
}
Log.e("SnakeSpace", "food pos = " + snakeFood);
snakeFood = x*100 + y;
}
在MainActivity的布局文件中引入我们创建的贪吃蛇View,和上下左右四个按键。
在MainActivity中的使用代码如下:
class MainActivity : AppCompatActivity() {
private val glRenderer: GLRenderer? = null
private lateinit var snake: SnakeSpace
private var mTimer: Timer? = null
private var mTimerTask: TimerTask? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
snake = findViewById(R.id.snake_view)
startTimer()
}
private fun startTimer(){
stopTimer()
mTimer = Timer()
mTimerTask = object : TimerTask(){
override fun run() {
snake.move()
}
}
mTimer!!.schedule(mTimerTask, 1000, 500)
}
private fun stopTimer(){
if (mTimer != null){
mTimer!!.cancel()
mTimer = null
}
if (mTimerTask != null){
mTimerTask!!.cancel()
mTimerTask = null
}
}
public fun upMove(view: View){
snake.move(SnakeSpace.DIRECTION_UP)
}
public fun downMove(view: View){
snake.move(SnakeSpace.DIRECTION_DOWN)
}
public fun leftMove(view: View){
snake.move(SnakeSpace.DIRECTION_LEFT)
}
public fun rightMove(view: View){
snake.move(SnakeSpace.DIRECTION_RIGHT)
}
代码主要思路是使用定时器控制游戏速度,上下左右按键改变蛇的移动方向。
至此,已经实现了一个简单的可以移动的贪吃蛇游戏雏形了,项目源码可参考Github项目。
https://github.com/dgutkai/RetroSnake.git
https://github.com/dgutkai/RetroSnake.gi