贪吃蛇小游戏

贪吃蛇游戏是一款比较经典的休闲游戏,文章包括项目的部分源码以及运行界面的一些图片,项目也参考学习了许多大佬的文章,会在文章最后面贴出参考文章,有什么问题也请大家指正。

一、游戏界面及游戏简介

贪吃蛇小游戏

说明:点击【START】开始游戏,点击【UP】【DOWN】【LEFT】【RIGHT】分别实现蛇头向【上】【下】【左】【右】方向移动,若蛇头位置超过边界则从另一侧穿出,若蛇头碰到随机生成的食物(及蓝色小方块)则蛇长增加;若蛇头碰撞到自己身上的部位,则视为蛇死亡,游戏结束!

二、游戏界面的布局xml

贪吃蛇小游戏

此布局使用的是ConstraintLayout约束性布局,实现基础游戏界面布局

代码如下

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.example.snack.MainActivity">

  <com.example.snack.SnakePanelView
      android:id="@+id/snake_view"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:orientation="horizontal"
      android:layout_marginTop="4dp"
      app:layout_constraintStart_toStartOf="parent"
      app:layout_constraintTop_toTopOf="parent" />

  <Button
      android:id="@+id/top_btn"
      android:layout_width="75dp"
      android:layout_height="45dp"
      android:layout_marginTop="28dp"
      android:background="@drawable/direction_btn_background"
      android:text="UP"
      android:textColor="@android:color/white"
      app:layout_constraintEnd_toEndOf="parent"
      app:layout_constraintHorizontal_bias="0.532"
      app:layout_constraintLeft_toLeftOf="parent"
      app:layout_constraintRight_toRightOf="parent"
      app:layout_constraintStart_toStartOf="parent"
      app:layout_constraintTop_toBottomOf="@+id/snake_view" />

  <Button
      android:id="@+id/left_btn"
      android:layout_width="75dp"
      android:layout_height="45dp"
      android:layout_marginStart="16dp"
      android:layout_marginTop="16dp"
      android:background="@drawable/direction_btn_background"
      android:text="LEFT"
      android:textColor="@android:color/white"
      app:layout_constraintEnd_toStartOf="@+id/top_btn"
      app:layout_constraintHorizontal_bias="0.659"
      app:layout_constraintStart_toStartOf="parent"
      app:layout_constraintTop_toBottomOf="@+id/top_btn" />

  <Button
      android:id="@+id/right_btn"
      android:layout_width="75dp"
      android:layout_height="45dp"
      android:layout_marginTop="8dp"
      android:layout_marginEnd="24dp"
      android:background="@drawable/direction_btn_background"
      android:text="RIGHT"
      android:textColor="@android:color/white"
      app:layout_constraintEnd_toEndOf="parent"
      app:layout_constraintHorizontal_bias="0.565"
      app:layout_constraintStart_toEndOf="@+id/top_btn"
      app:layout_constraintTop_toTopOf="@+id/left_btn" />

  <Button
      android:id="@+id/bottom_btn"
      android:layout_width="75dp"
      android:layout_height="45dp"
      android:layout_marginBottom="24dp"
      android:background="@drawable/direction_btn_background"
      android:text="DOWN"
      android:textColor="@android:color/white"
      app:layout_constraintBottom_toBottomOf="parent"
      app:layout_constraintEnd_toEndOf="parent"
      app:layout_constraintHorizontal_bias="0.532"
      app:layout_constraintLeft_toLeftOf="parent"
      app:layout_constraintRight_toRightOf="parent"
      app:layout_constraintStart_toStartOf="parent"
      app:layout_constraintTop_toBottomOf="@+id/top_btn"
      app:layout_constraintVertical_bias="0.334" />

  <Button
      android:id="@+id/start_btn"
      android:layout_width="75dp"
      android:layout_height="45dp"
      android:layout_marginStart="36dp"
      android:layout_marginTop="8dp"
      android:background="@drawable/restart_btn_background"
      android:text="START"
      android:textColor="@android:color/white"
      app:layout_constraintStart_toStartOf="parent"
      app:layout_constraintTop_toBottomOf="@+id/snake_view" />

</androidx.constraintlayout.widget.ConstraintLayout>


三、生成食物

随机生成,但不能生成在蛇身上。食物(蓝色小方块)是通过random产生随机坐标,存放到食物的Arraylist中,然后调用父类的方法将图片画在view上。
贪吃蛇小游戏


  //生成food
  private void generateFood() {
    Random random = new Random();
    int foodX = random.nextInt(mGridSize - 1);
    int foodY = random.nextInt(mGridSize - 1);
    for (int i = 0; i < mSnakePositions.size() - 1; i++) {
      if (foodX == mSnakePositions.get(i).getX() && foodY == mSnakePositions.get(i).getY()) {
   
        foodX = random.nextInt(mGridSize - 1);
        foodY = random.nextInt(mGridSize - 1);
        //如果生成在蛇身上则重新循环
        i = 0;
      }
    }
    mFoodPosition.setX(foodX);
    mFoodPosition.setY(foodY);
    refreshFood(mFoodPosition);
  }

四、蛇的移动

蛇的移动是通过界面的重新绘制实现的,点击方向键就改变蛇头的坐标,往某一方向进行x坐标或y坐标的增加。通过遍历食物和障碍物的Arraylist进行检测是否吃到食物或撞到障碍物,如果超过边界坐标,则从另一边穿出。
贪吃蛇小游戏

贪吃蛇小游戏

 private void moveSnake(int snakeDirection) {
    switch (snakeDirection) {
      case GameType.LEFT:
        if (mSnakeHeader.getX() - 1 < 0) {//边界判断:如果到了最左边 让他穿过屏幕到最右边
          mSnakeHeader.setX(mGridSize - 1);
        } else {
          mSnakeHeader.setX(mSnakeHeader.getX() - 1);
        }
        mSnakePositions.add(new GridPosition(mSnakeHeader.getX(), mSnakeHeader.getY()));
        break;
      case GameType.TOP:
        if (mSnakeHeader.getY() - 1 < 0) {
          mSnakeHeader.setY(mGridSize - 1);
        } else {
          mSnakeHeader.setY(mSnakeHeader.getY() - 1);
        }
        mSnakePositions.add(new GridPosition(mSnakeHeader.getX(), mSnakeHeader.getY()));
        break;
      case GameType.RIGHT:
        if (mSnakeHeader.getX() + 1 >= mGridSize) {
          mSnakeHeader.setX(0);
        } else {
          mSnakeHeader.setX(mSnakeHeader.getX() + 1);
        }
        mSnakePositions.add(new GridPosition(mSnakeHeader.getX(), mSnakeHeader.getY()));
        break;
      case GameType.BOTTOM:
        if (mSnakeHeader.getY() + 1 >= mGridSize) {
          mSnakeHeader.setY(0);
        } else {
          mSnakeHeader.setY(mSnakeHeader.getY() + 1);
        }
        mSnakePositions.add(new GridPosition(mSnakeHeader.getX(), mSnakeHeader.getY()));
        break;
    }
  }

五、判断碰撞(生或死)

通过遍历食物和障碍物的Arraylist进行检测是否吃到食物或撞到自己,若撞到自己则游戏结束。
贪吃蛇小游戏

private void checkCollision() {
    //检测是否咬到自己
    GridPosition headerPosition = mSnakePositions.get(mSnakePositions.size() - 1);
    for (int i = 0; i < mSnakePositions.size() - 2; i++) {
      GridPosition position = mSnakePositions.get(i);
      if (headerPosition.getX() == position.getX() && headerPosition.getY() == position.getY()) {
        //咬到自己 停止游戏
        mIsEndGame = true;
        showMessageDialog();
        return;
      }
    }

    //判断是否吃到食物,吃到食物蛇长加一,游戏继续
    if (headerPosition.getX() == mFoodPosition.getX()
        && headerPosition.getY() == mFoodPosition.getY()) {
      mSnakeLength++;
      generateFood();
    }
  }
  
  
 //结束游戏的弹窗 
  private void showMessageDialog() {
    post(new Runnable() {
      @Override
      public void run() {
        new AlertDialog.Builder(getContext()).setMessage("Game " + "Over!")
            .setCancelable(false)
            .setPositiveButton("重新开始", new DialogInterface.OnClickListener() {
              @Override
              public void onClick(DialogInterface dialog, int which) {
                dialog.dismiss();
                reStartGame();
              }
            })
            .setNegativeButton("退出", new DialogInterface.OnClickListener() {
              @Override
              public void onClick(DialogInterface dialog, int which) {
                dialog.dismiss();
              }
            })
            .create()
            .show();
      }
    });
  }

六、Mainactivity

在窗体中设置一些按键的监听

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

  private SnakePanelView mSnakePanelView;

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    mSnakePanelView = findViewById(R.id.snake_view);

    findViewById(R.id.left_btn).setOnClickListener(this);
    findViewById(R.id.right_btn).setOnClickListener(this);
    findViewById(R.id.top_btn).setOnClickListener(this);
    findViewById(R.id.bottom_btn).setOnClickListener(this);
    findViewById(R.id.start_btn).setOnClickListener(this);
  }

  @Override
  public void onClick(View v) {
    switch (v.getId()) {
      case R.id.left_btn:
        mSnakePanelView.setSnakeDirection(GameType.LEFT);
        break;
      case R.id.right_btn:
        mSnakePanelView.setSnakeDirection(GameType.RIGHT);
        break;
      case R.id.top_btn:
        mSnakePanelView.setSnakeDirection(GameType.TOP);
        break;
      case R.id.bottom_btn:
        mSnakePanelView.setSnakeDirection(GameType.BOTTOM);
        break;
      case R.id.start_btn:
        mSnakePanelView.reStartGame();
        break;
    }
  }
}

参考文章

作者:刘淑慧
原文地址

上一篇:Activiti6.0实战-常用功能实战二(6)


下一篇:getX,getY,getScrollX,getScrollY,ScrollTo(),ScrollBy()辨析