疯狂贪吃蛇

前言

闲的无聊想写一点小游戏,虽然简单,但是可以在娱乐中学习一些小小的逻辑思维,本次需要写的小游戏 —— 贪吃蛇

细节不想细说,直接上代码,代码中都有注释。

注:代码中一些样式和一些方法啥的,都是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>
posted @ 2021-12-27 15:33  007的张大炮  阅读(95)  评论(0编辑  收藏  举报