Vue+TailWindcss实现一个简单的闯关小游戏

目录
  • 游戏介绍
  • 实现技术
  • 本游特色
  • 技术实现
    • 初始化页面
    • 小方块设置
    • 主角移动
    • 自动索敌
    • 敌人移动
    • 胜利与失败
  • 编辑关卡
    • 移入移出变色
    • 点击设置
    • 保存关卡

游戏介绍

这是一款2d益智闯关游戏,玩家须躲避敌人与陷阱到达终点 拥有多个关卡

可进行关卡的自定义并留存数据

实现技术

vue tailwindcss

本游特色

  • 自定义关卡
  • 敌人自动索敌
  • 低技术力
  • you win!

技术实现

初始化页面

创建一个json文件,用来存放初始关卡的变量(只有一关。。。) 为方块设定大小,初始化变量speed设置为176,棋盘的宽高就各位4个speed,方块宽高就是1个speed,方块移动一格就是speed * 1,两格就是speed * 2

<!-- 棋盘 -->
<div :style="{ width: `${speed * 4}px`, height: `${speed * 4}px` }">
    <!-- 每一个小方块 -->
    <div :style="{ width: `${speed}px`,height: `${speed}px`,}"></div>
</div>
const speed = ref(176);

Level是一个json文件,里面放着第一关的各种变量,用来在没有关卡的时候初始化一个关卡

level.json

[
    {
        "id": 1,// 第一关
        "speed": 176,// 方块大小
        "top": 528,// 主角top值
        "left": 0,// 主角left值
        "enemy_top": 0,// 敌人top值
        "enemy_left": 352,// 敌人left值
        "enemy_top_2": 528,// 敌人2的top值
        "enemy_left_2": 352,// 敌人2的left值
        "obstacle_top": 176,// 障碍top值
        "obstacle_left": 352,// 障碍left值
        "trap_top": 352,// 陷阱top值
        "trap_left": 176,// 陷阱left值
        "spot_top": 0,// 终点top值
        "spot_left": 528// 终点left值
    }
]

在加载页面的时候判断是否有数据如果没有的话添加

import Level from "../../api/level.json";
let res = JSON.parse(localStorage.getItem("data"));
if (!res) {
    localStorage.setItem("data", JSON.stringify(Level));
}

小方块设置

使用绝对定位,用transition-all让方块看起来有动画效果

<div class="absolute transition-all"></div>

为小方块设置特定的top和left,声明变量然后设置给小方块上

<!-- 终点,我用的spot前缀 -->
<div :style="{ top: `${spot_top}px`,left: `${spot_left}px` }"></div>
<!-- 敌人,我用的enemy前缀(敌人2后缀直接-2) -->
<div :style="{ top: `${enemy_top}px`,left: `${enemy_left}px` }"></div>
const Level = JSON.parse(localStorage.getItem("data"));
const spot_top = ref(Level[index].spot_top);
const spot_left = ref(Level[index].spot_left);
const enemy_top = ref(Level[index].enemy_top);
const enemy_left = ref(Level[index].enemy_left);

主角移动

当按下相应按键后执行相应的函数

document.addEventListener("keydown", (e) => {
  switch (e.key) {
    case "a":
      if (is_run.value) {
        moveProtagonistA();
      }
      break;
    case "w":
      if (is_run.value) {
        moveProtagonistW();
      }
      break;
    case "d":
      if (is_run.value) {
        moveProtagonistD();
      }
      break;
    case "s":
      if (is_run.value) {
        moveProtagonistS();
      }
      break;
    case "r":
      againGame();// 重新开始
      break;
  }
});

四个函数的意思分别是主角块上下左右的移动,本质其实都差不多,差别就在于每个的top和left是不同的,所以咱就挑一个详细说明一下:

当想让主角向左移动时

const moveProtagonistA = () => {
  // 自杀判断
  if (
    left.value == enemy_left.value + speed.value &&
    top.value == enemy_top.value
  ) {
    left.value -= speed.value;
    return false;
  }
  if (left.value == 0) {
    // 边界判断
    left.value = -20;
    setTimeout(() => {
      left.value = 0;
    }, 100);
    return false;
  }
  // 障碍判断
  obstacle = obstacle_left.value + speed.value;
  if (top.value == obstacle_top.value && left.value == obstacle) {
    left.value = obstacle - 20;
    setTimeout(() => {
      left.value = obstacle;
    }, 100);
  } else {
    left.value -= speed.value;
    freeFindEnemy(enemy_top, enemy_left);
    freeFindEnemy(enemy_top_2, enemy_left_2);
  }
};

函数整体的内容有点小多,咱们来分开解释:

自杀判断

因为在主角移动时,敌人的自动索敌功能也会开启,所以导致当主角向敌人移动的时候因为敌人自动索敌的原因会与主角错开,于是便诞生了这个逻辑,就是判断如果主角的下一步有敌人的话,敌人原地不动,装上敌人game over

 // 自杀判断
  if (
    left.value == enemy_left.value + speed.value &&
    top.value == enemy_top.value
  ) {
    left.value -= speed.value;
    return false;// 如自杀成功则阻止下面的索敌判断
  }

边界判断

如果出界会被拦截并且给一个被拦截的效果提示,因为这个示例是想左移动的时候,所以判断条件也是左边

if (left.value == 0) {
    // 这个效果可以让方块回弹一下
    left.value = -20;
    setTimeout(() => {
      left.value = 0;
    }, 100);
    return false;// 如果碰到边界则阻止像下面的索敌判断
  }

障碍判断 && 索敌

如果关卡中存在障碍的话,当主角触碰到障碍的时候,会跟边界判断拥有一样回弹效果来提示此路不通

如果主角移动没有碰到障碍阻拦的话,则执行正常移动的命令并且执行自动索敌

obstacle = obstacle_left.value + speed.value;
if (top.value == obstacle_top.value && left.value == obstacle) {
    // 跟上面一样,回弹一下
  left.value = obstacle - 20;
  setTimeout(() => {
    left.value = obstacle;
  }, 100);
} else {
  left.value -= speed.value;// 移动命令
  freeFindEnemy(enemy_top, enemy_left);// 敌人1的索敌
  freeFindEnemy(enemy_top_2, enemy_left_2);// 敌人2的索敌
}

也许你已经看到了(朵拉摆手),在索敌的最后使用的两个函数,这个函数就是自动索敌的逻辑,接下来继续深入~

自动索敌

当主角移动时敌人自动索敌

// 自动索敌
const freeFindEnemy = (Etop: any, Eleft: any) => {
  let _top = top.value - Etop.value;
  let _left = left.value - Eleft.value;
  if (Math.abs(_top) > Math.abs(_left)) {
    if (_top > 0) {
      moveEnemyS(Etop, Eleft);
    } else {
      moveEnemyW(Etop, Eleft);
    }
  } else {
    if (_left > 0) {
      moveEnemyD(Etop, Eleft);
    } else {
      moveEnemyA(Etop, Eleft);
    }
  }
};

这个里面出现的函数moveEnemy系列是敌人方块的方向移动,逻辑就是判断主角距离敌人的top和left来决定敌人方块的走向,Etop与Eleft需要分别传入的敌人的top和left值,判断拿边距离大就往哪边行动,有大于、小于等于两种情况

由自动索敌又延申出了--敌人移动

敌人移动

敌人移动也是拥有四个函数,基本与主角移动没有区别,但是敌人在碰到障碍的时候会选择绕开,且敌人碰到陷阱的时候会被“吃掉”

拿敌人向下移动来举例

const moveEnemyS = (Etop: any, Eleft: any) => {
  // 陷阱判断
  if (trap_top.value == Etop.value && trap_left.value == Eleft.value) return;
  // 障碍检测判断
  obstacle = obstacle_top.value - speed.value;
  if (Etop.value == obstacle && Eleft.value == obstacle_left.value) {
    // 判断如果碰到障碍
    let _left = left.value - Eleft.value;
    if (_left > 0) {
      Eleft.value += speed.value;
    } else {
      Eleft.value -= speed.value;
    }
  } else {
    Etop.value += speed.value;
  }
};

首先是陷阱的判断,如果敌人的top和left与陷阱一致的话则判断敌人掉进了陷阱里,将终止敌人的所有移动

接下来是障碍,判断如果敌人即将要走的方向有障碍挡着的话,就去判断与主角的距离来向左或者向右避开

胜利与失败

在胜利和失败后肯定是要终止所有行动的,正好所有的行动也是由主角移动的函数来触发的,所以先声明一个变量用来控制游戏的进行,然后通过按键在判断这个变量,如果游戏正在进行中则触发移动函数函数,如果游戏未开始或已失败则跳过触发事件,即无响应

case "a":
  // is_run即声明的变量,在游戏失败或未开始阶段该变量为false
  if (is_run.value) {
    moveProtagonistA();
  }
  break;

当胜利条件符合(即主角碰到终点)时,触发win,即显示win字样并使is_run置为false

// 主角的topleft是否与终点的topleft重合
if (top.value == spot_top.value && left.value == spot_left.value) {
    winShow.value = true;
    is_run.value = false;
  }

当失败条件符合(即主角碰到敌人1或2或者陷阱)时,触发lose,即显示lose字样并使is_run置为false

if (
    (top.value == enemy_top.value && left.value == enemy_left.value) ||
    (top.value == enemy_top_2.value && left.value == enemy_left_2.value) ||
    (top.value == trap_top.value && left.value == trap_left.value)
  ) {
    is_run.value = false;
    loseShow.value = true;
    return;
  }

最后一个return的作用是截断,当触发了lose后就不再继续执行了(否则会接着执行win)

编辑关卡

移入移出变色

16个黑块,通过鼠标移入移出判断颜色

<div
  v-for="(item, index) in blockList"
  :key="index"
  :style="{
    width: `${speed}px`,
    height: `${speed}px`,
    background: item.background,
  }"
  @mousemove="editMove($event, item)"
  @mouseleave="editLeave"
  class="transition-all"
></div>
<!-- transition-all使样式变换具有过渡效果 -->
const editMove = (event, item) => {
  // 如果该方块已经被选中则什么都不做
  if (!item.is_confirm) {
    for (let i in blockList.value) {
      // 选中相应的方块进行变色
      if (blockList.value[i].id == item.id) {
        blockList.value[i].background = "";
      } else if (blockList.value[i].is_confirm) {
        blockList.value[i].background = "";
      } else {
        blockList.value[i].background = "#000";
      }
    }
  }
};
const editLeave = () => {
  for (let i in blockList.value) {
    // 如果该方块已经被选中则什么都不做
    if (blockList.value[i].is_confirm) {
      blockList.value[i].background = "";
    } else {
       // 选中相应的方块进行变色
      blockList.value[i].background = "#000";
    }
  }
};

因为方块被设置后是不能被改变颜色的,所以需要这两个方法对已经被设置的方块进行判断

点击设置

需先点击左侧图例使颜色选中,再点击方块使其变色

图例

<div
  v-for="(item, index) in legendList"
  :key="index"
  class="flex mb-4 items-center text-xl"
  @click="colorClick($event, item)"
>
  <div class="legend_sign" :class="item.color"></div>
  <div class="w-10"></div>
  <div
    class="transition-all p-2 rounded-lg"
    :class="color == item.color ? color : ''"
  >
    {{ item.introduce }}
  </div>
</div>
const legendList = [
  {
    id: 0,
    color: "bg-green-500",
    introduce: "终点",
  },
  {
    id: 1,
    color: "bg-red-500",
    introduce: "敌人",
  },
  {
    id: 2,
    color: "bg-blue-500",
    introduce: "主角",
  },
  {
    id: 3,
    color: "bg-gray-500",
    introduce: "障碍",
  },
  {
    id: 4,
    color: "bg-purple-500",
    introduce: "陷阱",
  },
];

变色逻辑

<!-- 跟移入移出变色的div是同一个div -->
<!-- 重点看这句::class="item.color" -->
<div
  v-for="(item, index) in blockList"
  :key="index"
  :style="{
    width: `${speed}px`,
    height: `${speed}px`,
    background: item.background,
  }"
  :class="item.color"
  @click="editClick($event, item)"
  @mousemove="editMove($event, item)"
  @mouseleave="editLeave"
  class="transition-all"
></div>
const editMove = (event, item) => {
  if (!item.is_confirm) {
    for (let i in blockList.value) {
      if (blockList.value[i].id == item.id) {
        // 重点在这两句
        blockList.value[i].background = "";
        blockList.value[i].color = color.value;
      } else if (blockList.value[i].is_confirm) {
        blockList.value[i].background = "";
      } else {
        blockList.value[i].background = "#000";
      }
    }
  }
};
const editClick = (event, item) => {
  // json添加
  switch (color.value) {
    case "bg-green-500":
      if (json.spot_top != 9999) {
        tips.value = "终点只能有一个";
        return;
      }
      json.spot_top = item.top;
      json.spot_left = item.left;
      break;
    case "bg-red-500":
      if (json.enemy_top != 9999) {
        if (json.enemy_top_2 != 9999) {
          tips.value = "敌人只能有两个";
          return;
        }
        json.enemy_top_2 = item.top;
        json.enemy_left_2 = item.left;
        break;
      }
      json.enemy_top = item.top;
      json.enemy_left = item.left;
      break;
    case "bg-blue-500":
      if (json.top != 9999) {
        tips.value = "主角只能有一个";
        return;
      }
      json.top = item.top;
      json.left = item.left;
      break;
    case "bg-gray-500":
      if (json.obstacle_top != 9999) {
        tips.value = "障碍只能有一个";
        return;
      }
      json.obstacle_top = item.top;
      json.obstacle_left = item.left;
      break;
    case "bg-purple-500":
      if (json.trap_top != 9999) {
        tips.value = "陷阱只能有一个";
        return;
      }
      json.trap_top = item.top;
      json.trap_left = item.left;
      break;
    default:
      tips.value = "请先选择颜色~";
      return;
  }
  // 状态保留
  for (let i in blockList.value) {
    if (blockList.value[i].id == item.id) {
      blockList.value[i].background = "";
      blockList.value[i].color = color.value;
      blockList.value[i].is_confirm = true;
    } else if (blockList.value[i].is_confirm) {
      blockList.value[i].background = "";
    } else {
      blockList.value[i].background = "#000";
    }
  }
};

首先是通过点击图例来保存颜色,然后在鼠标移入黑块的时候不再是白色,而是选中的颜色,在点击的时候能将颜色固定到黑块上

因为style的优先级要比class大(background比bg-red-500大),所以在悬浮时需要将背景颜色去掉:

blockList.value[i].background = "";
blockList.value[i].color = color.value;

在点击的时候需要保留这个颜色,所以在点击的时候要将本来的颜色改变,并且在悬浮上去后不会变色

blockList.value[i].background = "";
blockList.value[i].color = color.value;
blockList.value[i].is_confirm = true;

is_confirm在上面已经出现过一两次,表示的是这个块是否被设置,如果被设置了则不对它做任何操作

const editMove = (event, item) => {
  if (!item.is_confirm) {
    ...
  }
};

保存关卡

对每个被设置的块记住位置,在点击保存关卡的时候将它放到本地存储里,这样一个新的关卡就生成了

【gif保存关卡】

初始时将所有top left全都设置为9999,在点击方块的时候记录方块的top left和颜色来向一个数组中传入数据,并且对块的数量做出限制,这里拿主角来举例:

switch(color.value){
  case "bg-blue-500":
      if (json.top != 9999) {
        tips.value = "主角只能有一个";
        return;
      }
      // 将主角的top lef填入对应的地方
      json.top = item.top;
      json.left = item.left;
      break;
}

在点击保存关卡时将数组添加进本地存储

const Level = JSON.parse(localStorage.getItem("data"));
let json = {
  id: Level.length + 1,
  speed: 176,
  top: 9999,
  left: 9999,
  enemy_top: 9999,
  enemy_left: 9999,
  enemy_top_2: 9999,
  enemy_left_2: 9999,
  obstacle_top: 9999,
  obstacle_left: 9999,
  trap_top: 9999,
  trap_left: 9999,
  spot_top: 9999,
  spot_left: 9999,
};

...

const saveClick = () => {
  Level.push(json);
  localStorage.setItem("data", JSON.stringify(Level));
  button_text.value = "保存成功";
  router.push("/main");
};

以上就是Vue+TailWindcss实现一个简单的闯关小游戏的详细内容,更多关于Vue TailWindcss闯关游戏的资料请关注我们其它相关文章!

(0)

相关推荐

  • vue实现打地鼠小游戏

    本文实例为大家分享了vue实现打地鼠小游戏的具体代码,供大家参考,具体内容如下 效果图如下: 代码如下: <template> <div class="game"> <h2>打地鼠游戏</h2> <div class="wraper"> <div class="item" v-for="n in TOTAL" :key="n"> <

  • 利用Vue.js制作一个拼图华容道小游戏

    目录 游戏介绍 核心思路 核心代码 html games 类 生成随机图片数量 移动图片 键盘事件 拼图完成 结语 游戏介绍 先看看界面 这是一个拼图游戏,可以自选难度和自选闯关图片 游戏开始后根据不同难度,生成与所选主图 对应的 不同张数的 随机顺序的小图,然后只要把乱序的小图片还原成完整的图片就闯关成功 游戏区域有一个空白位置,可以用鼠标点击空白位相邻的图片完成替换,也就是移动,也可以用键盘上下左右操作 游戏好玩,可不要贪杯哦,学习也不能落下,不管什么游戏都一样 这个虽然用到的技术很一般很简

  • VUE+Canvas 实现桌面弹球消砖块小游戏的示例代码

    大家都玩过弹球消砖块游戏,左右键控制最底端的一个小木板平移,接住掉落的小球,将球弹起后消除画面上方的一堆砖块. 那么用VUE+Canvas如何来实现呢?实现思路很简单,首先来拆分一下要画在画布上的内容: (1)用键盘左右按键控制平移的木板: (2)在画布内四处弹跳的小球: (3)固定在画面上方,并且被球碰撞后就消失的一堆砖块. 将上述三种对象,用requestAnimationFrame()函数平移运动起来,再结合各种碰撞检查,就可以得到最终的结果. 先看看最终的效果: 一.左右平移的木板 最底

  • 基于Vue.js实现数字拼图游戏

    先来看看效果图: 功能分析 当然玩归玩,作为一名Vue爱好者,我们理应深入游戏内部,一探代码的实现.接下来我们就先来分析一下要完成这样的一个游戏,主要需要实现哪些功能.下面我就直接将此实例的功能点罗列在下了: 1.随机生成1~15的数字格子,每一个数字都必须出现且仅出现一次 2.点击一个数字方块后,如其上下左右有一处为空,则两者交换位置 3.格子每移动一步,我们都需要校验其是否闯关成功 4.点击重置游戏按钮后需对拼图进行重新排序 以上便是本实例的主要功能点,可见游戏功能并不复杂,我们只需一个个攻

  • VUE+Canvas实现简单五子棋游戏的全过程

    前言 在布局上,五子棋相比那些目标是随机运动的游戏,实现起来相对简单许多,思路也很清晰,总共分为: (1)画棋盘: (2)监听点击事件画黑白棋子: (3)每次落子之后判断是否有5子相连,有则赢. 最复杂的恐怕就是如何判断五子棋赢了,那么就先从简单的开始,画个棋盘吧~ 1.画棋盘 棋盘很简单,我们画个15*15的棋盘,横线竖线相交错: drawCheckerboard() { // 画棋盘 let _this = this; _this.ctx.beginPath(); _this.ctx.fil

  • Vue+TailWindcss实现一个简单的闯关小游戏

    目录 游戏介绍 实现技术 本游特色 技术实现 初始化页面 小方块设置 主角移动 自动索敌 敌人移动 胜利与失败 编辑关卡 移入移出变色 点击设置 保存关卡 游戏介绍 这是一款2d益智闯关游戏,玩家须躲避敌人与陷阱到达终点 拥有多个关卡 可进行关卡的自定义并留存数据 实现技术 vue tailwindcss 本游特色 自定义关卡 敌人自动索敌 低技术力 you win! 技术实现 初始化页面 创建一个json文件,用来存放初始关卡的变量(只有一关...) 为方块设定大小,初始化变量speed设置为

  • 利用c++写一个简单的推箱子小游戏

    效果图 相信各位都肯定完整这种推箱子的小游戏.游戏玩法很简单,那就是一个人把所有的箱子推动到对应的位置那就可以赢了. 那么我们接下来看看这个推箱子的游戏改怎么写 char map[10][10]= { {'#','#','#','#','#','#','#','#','#','#'}, {'#','#','#','#',' ',' ','!',' ',' ','#'}, {'#',' ',' ',' ',' ','o',' ',' ',' ','#'}, {'#',' ',' ',' ',' '

  • 基于C语言编写一个简单的抽卡小游戏

    目录 效果图展示 开始的界面 输入1 输入10 输入0 实现代码 test4.26.c 许愿.c game.h 下载 小奔最近学了C语言不少的东西,但是想用学到的东西来搞一个小游戏. 不过小奔就不做那些猜数字等小游戏了,虽然很经典,但是可以尝试一下其他比较好玩的. 小奔喜欢玩原神,但它抽卡系统的中奖概率太低了,所以就类似做一个它的抽卡系统吧,不过没有保底功能哦(小奔还不想搞,还要学习新的知识,不过以后熟练了就可能会搞一个),是全角色抽卡,只有角色没有武器的,可以十连抽,没有保底功能,抽中的概率只

  • 使用Vue组件实现一个简单弹窗效果

    最近在使用element-ui框架,用到了Dialog对话框组件,大致实现的效果,跟我之前自己在移动端项目里面弄的一个弹窗组件差不太多.然后就想着把这种弹窗组件的实现方式与大家分享一下,下面本文会带着大家手摸手实现一个弹窗组件. 本文主要内容会涉及到弹窗遮罩的实现, slot 插槽的使用方式, props . $emit 传参,具体组件代码也传上去了.如果喜欢的话可以点波赞/关注,支持一下,希望大家看完本文可以有所收获. 组件最后实现的效果 实现步骤 先搭建组件的html和css样式,遮罩层和内

  • vue.js做一个简单的编辑菜谱功能

    先给大家展示下效果图,如果感觉不错,请参考实现代码 1.先获取门店下的所有菜品类型.菜品名称.菜品id(list),也就是最大数据量 this.$http.post(ceshiApi+'getCyFoodAndFoodTypeForShopId',{shopId:this.shopId},{emulateJSON:true,credentials: true}).then(function(res){ if(res.data.type=='success'){ this.foodList = r

  • 如何用VUE和Canvas实现雷霆战机打字类小游戏

    今天就来实现一个雷霆战机打字游戏,玩法很简单,每一个"敌人"都是一些英文单词,键盘正确打出单词的字母,飞机就会发射一个个子弹消灭"敌人",每次需要击毙当前"敌人"后才能击毙下一个,一个比手速和单词熟练度的游戏. 首先来看看最终效果图: emmmmmmmmmmmmm,界面UI做的很简单,先实现基本功能,再考虑高大上的UI吧. 首先依旧是来分析界面组成: (1)固定在画面底部中间的飞机: (2)从画面上方随机产生的敌人(单词): (3)从飞机头部发射

  • 用Python写一个无界面的2048小游戏

    以前游戏2048火的时候,正好用其他的语言编写了一个,现在学习python,正好想起来,便决定用python写一个2048,由于没学过python里面的界面编程,所以写了一个极其简单的无界面2048.游戏2048的原理和实现都不难,正好可以拿来练手,要是不知道这游戏的话,可以去网上查一下,或者下载一个到手机来玩一下,我就不在说其原理.我知道不放图的话大家一点兴趣都没,下面首先放一张游戏成型图,然后我们在来讲如何一步步用最基础的知识来实现. 一.生成4*4的矩阵 游戏的第一步便是生成一个4*4的矩

  • js实现一款简单踩白块小游戏(曾经很火)

    效果图如下所示: html <div class="bigbox"> <!-- 显示游戏的区域 --> <div class="gamequyu"> <!-- 上面显示一个游戏开始的按钮 --> <div class="start">游戏开始</div> <!-- 再显示一个游戏的主体部分 --> <div class="zhuti"&g

  • Java实现简单的贪吃蛇小游戏

    本文实例为大家分享了Java实现简单的贪吃蛇小游戏的具体代码,供大家参考,具体内容如下 1. 程序结构 程序结构图如图: 2. 程序设计思路 2.1 Data类 作用:连接statics文件夹,将静态资源包中的图片转化为图标 方便在面板上绘制. 实现:使用class.getResource(String path)方法. 代码如下: package com.snake; import javax.swing.*; import java.net.URL; public class Data {

  • 基于Python编写一个宝石消消乐小游戏

    目录 开发工具 环境搭建 原理简介 开发工具 python版本:3.6.4 相关模块: pygame:以及一些python自带的模块. 环境搭建 安装python并添加到环境变量,pip安装需要的相关模块即可. 原理简介 游戏规则: 玩家通过鼠标交换相邻的拼图,若交换后水平/竖直方向存在连续三个相同的拼图,则这些拼图消失,玩家得分,同时生成新的拼图以补充消失的部分,否则,交换失败,玩家不得分.玩家需要在规定时间内获取尽可能高的得分. 实现过程: 首先加载一些必要的游戏素材: 加载背景音乐: py

随机推荐