2021-7-7 11:00:01 [显示全部楼层]
182浏览
查看: 182|回复: 0

[入门教程] Processing笔记05—贪吃蛇小游戏

[复制链接]
贪吃蛇是非常经典的小游戏,大家肯定接触过,它在当年只能打电话发短信的诺基亚手机中是唯一的娱乐项目了。它的操作非常简单,很多编程语言都可以来实现它。我们已经学习了Processing中基本图形的绘制以及鼠标键盘的识别响应,本篇我们使用Processing来编程实现贪吃蛇小游戏。

蛇身的绘制

这应该是贪吃蛇游戏中最主要的部分了,在程序中使用数组来保存组成蛇身的每个方块的坐标值。

// 保存组成蛇身的每个方格位置
int[] x = new int[snake_length_max];
int[] y = new int[snake_length_max];

当蛇头位置改变以后,我们从尾部开始遍历数组,将每个方块坐标位置向后移动,然后将新的蛇头位置赋值到数组第一元素,然后重新绘制所有方块。

void draw_snake()
{
  //从尾部开始更新蛇身方块坐标
  for (int i=snake_length-1; i>0; i--) {
    x = x[i-1];
    y = y[i-1];
  }

  // 设置蛇头新的坐标
  x[0] = snake_head_x;
  y[0] = snake_head_y;

  // 设置蛇身填充颜色
  fill(#3874F6);

  // 开始画蛇
  for (int i=0; i<snake_length; i++) {
    rect(x, y, grid, grid);
  }
}

食物的产生

当食物被吃掉以后,我们需要在指定长宽的区域内随机生成食物的坐标数据,这里使用了random()函数,用来生成坐标值,这个坐标值需要是方块边长的整数倍。

void draw_food(int max_width, int max_high)
{
  //食物填充颜色
  fill(#F71E1E);

  //如果食物被吃掉,则随机生成一个
  if (food_eaten)
  {
    food_x = int(random(0, max_width) / grid) * grid;
    food_y = int(random(0, max_high) / grid) * grid;
  }

  rect(food_x, food_y, grid, grid);
  food_eaten = false;
}

方向控制

这里使用前篇介绍的按键识别操作。对方向按键进行判断,然后对应改变蛇的运动方向。

if (snake_direction != 'P'&& keyPressed && key == CODED)
  {
    switch(keyCode) {
    case LEFT:
      if (snake_direction != 'R') {
        snake_direction = 'L';
      }
      break;
    case RIGHT:
      if (snake_direction != 'L') {
        snake_direction = 'R';
      }
      break;
    case DOWN:
      if (snake_direction != 'U') {
        snake_direction = 'D';
      }
      break;
    case UP:
      if (snake_direction != 'D') {
        snake_direction = 'U';
      }
      break;
    }

在刷新显示的时候,会根据移动方向的不同,对蛇头的坐标进行改变,当重新对蛇身进行绘制的时候,整个蛇就进行了一次移动。

//移动方向选择
switch(snake_direction) {
    case 'L':
        snake_head_x -= grid;
        break;
    case 'R':
        snake_head_x += grid;
        break;
    case 'D':
        snake_head_y += grid;
        break;
    case 'U':
        snake_head_y -= grid;
        break;
}

此外,增加了暂停键“P”或“p”,以及运行键“R”或“r”的判断。

if (key == 'p' || key == 'P')
  {
    game_pause++;
    if (game_pause%2 == 1)
    {
      snake_direction_temp = snake_direction;
      snake_direction = 'P';
    } else {
      snake_direction = snake_direction_temp;
    }
  }
....
if (keyPressed && (key == 'r' || key == 'R'))
  {
   ...
  }

值得注意的是,这些对于按键的监听,没有放在draw()函数中,而是使用了键盘事件函数keyPressed(),每当按下一个键,其中的代码就会运行一次,使用这种方式监听按键更加方便灵活。

判断游戏结束

当蛇头坐标超过显示区域,即蛇撞墙,或蛇头位置坐标与蛇身其他方块坐标相同,即自己吃了自己,都会导致游戏结束。

boolean check_snake_die()
{
  // 撞墙了
  if ( snake_head_x < 0 || snake_head_x >= width || snake_head_y < 0 || snake_head_y >= height) {
    show_game_over();
    return true;
  }

  // 自己吃自己
  if ( snake_length > 2 ) {
    for ( int i=1; i<snake_length; i++ ) {
      if ( snake_head_x == x && snake_head_y == y ) {
        show_game_over();
        return true;
      }
    }
  }
  return false;
}

移动速度

程序中使用millis()函数来获取自程序开始到当前的时间。每当draw()中代码运行一次,我们都重新获取一次当前时间,然后减掉之前的时间来计算出经过的时间,然后与移动间隔时间进行比较,当大于间隔时间时,说明需要刷新移动蛇身一次,然后重新获取一次时间,为后续比较做准备。

time_passed = millis() - time_start; //计算出经过的时间
time_interval = 1000 / speed; //计算移动间隔时间

if (time_passed > time_interval && snake_direction != 'P' && game_start)//游戏刷新条件
  {
     ...
    time_start = millis(); //重新获取时间
  }

吃到食物

当蛇头坐标移动到与食物坐标相同时,就代表食物被吃到,这时蛇身长度要加1,重新生成食物。程序中每吃掉5个食物,移动速度就会增加1。

//蛇吃到食物
if (snake_head_x == food_x && snake_head_y == food_y)
{
food_eaten = true; //可重新生成食物
snake_length++;

if ( snake_length%5 == 1) {
speed++;
}
speed = min(20, speed);//控制最大速度
}

实现效果

Processing笔记05—贪吃蛇小游戏qw2.jpg
贪吃蛇的实现还是非常简单的,当然代码还有很多需要优化的地方,比如说我们在随机生成食物坐标的时候,需要排除蛇身中方块的坐标,即食物不能直接出现在蛇身中,你可以试着来优化下。

我们还可以直接将代码导出成exe可执行文件,你也来试一试吧。

编辑:Tony来源:公众号TonyCode

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

为本项目制作心愿单
购买心愿单
心愿单 编辑
[[wsData.name]]

硬件清单

  • [[d.name]]
btnicon
我也要做!
点击进入购买页面
上海智位机器人股份有限公司 沪ICP备09038501号-4

© 2013-2021 Comsenz Inc. Powered by Discuz! X3.4 Licensed

mail