疯狂贪吃蛇
前言
闲的无聊想写一点小游戏,虽然简单,但是可以在娱乐中学习一些小小的逻辑思维,本次需要写的小游戏 —— 贪吃蛇
细节不想细说,直接上代码,代码中都有注释。
注:代码中一些样式和一些方法啥的,都是uview自带的,比如样式u-xx、方法$u.xx
1、游戏界面
<template>
<!-- 贪吃蛇 -->
<view class="snake u-rela hidden z-height flexColumn">
<!-- 地图 -->
<view class="snake-map">
<view class="snake-map-box">
<view class="snake-tr" v-for="(item1,index1) in map" :key="index1">
<view class="snake-td flexCenter" v-for="(item2,index2) in item1" :key="index2" :class="{'snakeHeadRotate':(snakeMove == 'up' || snakeMove == 'down') && item2.z == 0}">
<view class="snake-head" v-show="item2.z == 0"></view>
<view class="snake-body" v-show="item2.z == 1"></view>
<u-icon name="/static/image/snake/food.png" size="52" v-show="item2.z == 2"></u-icon>
</view>
</view>
</view>
</view>
<!-- 操作 -->
<view class="snake-box flex1 flexColumn">
<!-- 方向键 -->
<view class="snake-control flex1 flexWrap box">
<view class="snake-control-btn"></view>
<button class="snake-control-btn" @click="bindMove('up')">
<u-icon name="arrow-up" size="50" color="#111"></u-icon>
</button>
<view class="snake-control-btn"></view>
<button class="snake-control-btn" @click="bindMove('left')">
<u-icon name="arrow-left" size="50" color="#111"></u-icon>
</button>
<button class="snake-control-btn snake-control-btn-start" @click="start">{{isOver? "重来" : isStop ? '开始' : '暂停'}}</button>
<button class="snake-control-btn" @click="bindMove('right')">
<u-icon name="arrow-right" size="50" color="#111"></u-icon>
</button>
<view class="snake-control-btn"></view>
<button class="snake-control-btn" @click="bindMove('down')">
<u-icon name="arrow-down" size="50" color="#111"></u-icon>
</button>
<view class="snake-control-btn"></view >
</view>
</view>
</view>
</template>
2、游戏样式
<style>
page{background-color: #111;}
</style>
<style lang="scss" scoped>
// 布局样式 (255,87,87)
.snake-map-box{
width: 100%;height: auto;background-color: #000;display: flex;flex-direction: column;
border-left: 2rpx solid rgba(255,255,255,.2);
border-bottom: 4rpx solid rgba(255,255,255,.5);
.snake-tr{flex: 1;display: flex;}
.snake-td{
flex: 1;height: 50rpx; overflow: hidden;position: relative;
&::before{position: absolute;content: "";width: 2rpx;height: 100%;right: 0;top: 0;background-color: rgba(255,255,255,0);}
&::after{position: absolute;content: "";width: 100%;height: 2rpx;left: 0;bottom: 0;background-color: rgba(255,255,255,0);}
}
.snake-head{
width: 100%;height: 100%;background-color: rgb(0,255,1);position: relative;
&::before{position: absolute;content: "";width: 10rpx;height: 10rpx;background-color: #000;border: 6rpx solid #fff;top: 0; right: 50%;transform: translateX(80%);}
&::after{position: absolute;content: "";width: 10rpx;height: 10rpx;background-color: #000;border: 6rpx solid #fff;bottom: 0;right: 50%;transform: translateX(80%);}
}
.snake-body{width: 100%;height: 100%;background-color: rgb(0,255,1);}
}
// 操作按钮
.snake-control{
uni-button.snake-control-btn{border: 4rpx solid #111;border-radius: 20rpx;}
.snake-control-btn{
width: 33.333%;height: 33.333%;display: flex;align-items: center;justify-content: center;
&::after{border: 0;}
&.snake-control-btn-start{border: 4rpx solid #111;font-weight: bold;font-size: 50rpx;}
}
}
// 改变蛇头方向
.snakeHeadRotate{transform: rotate(90deg);}
</style>
3、游戏逻辑
<script>
export default {
data() {
return {
num: 0,
map: [],
row: 15,
col: 15,
snake: [ // 默认蛇 x=行 y=列 z=0头 z=1尾 z=2食物
{x: 0, y: 2, z: 0},
{x: 0, y: 1, z: 1},
{x: 0, y: 0, z: 1}
],
food: {x: null, y: null}, // 食物
snakeTimer: null, // 蛇自己动
snakeSpeed: 200, // 蛇移动速度
snakeMove: 'right', // 蛇移动方向 默认开始向右移动
isOver: false, // 游戏是否结束
isStop: true, // 游戏是否暂停
};
},
onLoad() {
this.snake_style();
this.food_style();
},
onUnload() {
clearInterval(this.snakeTimer);
},
methods:{
// 初始化地图
init_map(){
for(let i = 0; i < this.row; i++){
this.map[i] = [];
for(let j = 0; j < this.col; j++){
this.map[i][j] = {
x: i,
y: j,
z: null
};
}
}
},
// 渲染蛇
snake_style(){
this.init_map(); // 每次渲染蛇的时候,都要重置一下地图, 为了清除蛇之前的轨迹
this.snake.forEach((item,index) => {
item.z = index == 0 ? 0 : 1;
})
this.map.forEach(item => {
item.forEach(item1 => {
this.snake.forEach(item2 => {
if(item1.x == item2.x && item1.y == item2.y) item1.z = item2.z;
})
// 因为重新渲染了地图,那么食物的位置也要重新渲染
if(item1.x == this.food.x && item1.y == this.food.y) item1.z = 2;
})
})
this.$forceUpdate();
},
// 渲染食物
// 用两个随机数生成食物的纵横坐标,食物不能落在蛇身上
food_style(){
let randomX = null, randomY = null, bool = false;
while(true){
randomX = Math.floor(Math.random() * this.row);
randomY = Math.floor(Math.random() * this.col);
this.snake.forEach(item => {
if(item.x != randomX && item.y != randomY){
bool = true
}
})
if(bool) break;
}
this.food = { x: randomX, y: randomY };
this.map.forEach(item => {
item.forEach(item1 => {
if(item1.x == this.food.x && item1.y == this.food.y) item1.z = 2;
})
})
},
// 让蛇移动
snakeMoveTimer(){
return setInterval(() => {
let zX = null, zY = null;
switch(this.snakeMove){
case 'right':
zX = this.snake[0].x;
zY = this.snake[0].y + 1;
this.snake.unshift({x: zX, y: zY, z: 1});
break;
case 'down':
zX = this.snake[0].x + 1;
zY = this.snake[0].y;
this.snake.unshift({x: zX, y: zY, z: 1});
break;
case 'left':
zX = this.snake[0].x;
zY = this.snake[0].y - 1;
this.snake.unshift({x: zX, y: zY, z: 1});
break;
case 'up':
zX = this.snake[0].x - 1;
zY = this.snake[0].y;
this.snake.unshift({x: zX, y: zY, z: 1});
break;
}
// 到这里我们需要判断 蛇头是否吃到食物。如果没吃到,减一个;反之我们就不用删除最后一个
if(!this.eat()){
this.snake.pop();
}
// 判断是否撞到自己或者是墙
if(this.die()){
clearInterval(this.snakeTimer);
this.isOver = true;
uni.showToast({title: "撞死了?实在不行,人生重来算了",icon: 'none'});
}
// 移动完成要重新渲染
this.snake_style();
}, this.snakeSpeed);
},
// 是否吃到食物
eat(){
let bool = false;
this.snake.forEach(item=>{
if(item.x == this.food.x && item.y == this.food.y){
bool = true;
this.food_style();
}
})
return bool;
},
// 是否撞死
die(){
let bool = false;
// 1.撞到自己,就是头部是否与身体其他部分重合
for(let i = 1; i < this.snake.length; i++){
if(this.snake[0].x == this.snake[i].x && this.snake[0].y == this.snake[i].y){
bool = true;
}
}
// 2.撞到墙,就是横坐标或者纵坐标超出或者低于地图范围
if(this.snake[0].x > this.row-1 || this.snake[0].x < 0 || this.snake[0].y > this.col-1 || this.snake[0].y < 0){
bool = true;
}
return bool;
},
// 方向控制
bindMove(move){
if(this.isOver){
uni.showToast({title: "游戏已结束,重新开始吧", icon:'none'});
return;
}
if(this.isStop){
uni.showToast({title: "游戏已暂停或还未开始", icon:'none'});
return;
}
if(move == 'right' && this.snakeMove != 'left'){
this.snakeMove = 'right';
}else if(move == 'down' && this.snakeMove != 'up'){
this.snakeMove = 'down';
}else if(move == 'left' && this.snakeMove != 'right'){
this.snakeMove = 'left';
}else if(move == 'up' && this.snakeMove != 'down'){
this.snakeMove = 'up';
}
this.snake_style();
},
// 开始 暂停
start(){
if(this.isOver){
this.reset()
}else{
this.isStop = !this.isStop;
if(!this.isStop){
this.snakeTimer = this.snakeMoveTimer();
}else{
clearInterval(this.snakeTimer);
}
}
},
// 重新开始
reset(){
this.isOver = false;
this.isStop = true;
this.snakeMove = 'right';
this.snake = [
{x: 0, y: 2, z: 0},
{x: 0, y: 1, z: 1},
{x: 0, y: 0, z: 1},
];
this.food = {x: null, y: null};
this.snakeTimer = null;
this.snake_style();
this.food_style();
},
}
}
</script>