最近学习到H5的canvas,一时兴起写了个经典的“贪吃蛇”小游戏

  1.     要完成这个游戏,首先要了解蛇是由一个一个的点组成的,然后这个点要有位置、颜色,关键的还要有下一个点的基本位置信息,不然怎么知道这个点的下一个运动位置呢。上代码:
    class Dot {
    		constructor(x,y,color){
    			this.color = color
    			this.x = x
    			this.y = y
    			this.next = null
    
    			ctx.fillStyle = this.color
    			ctx.beginPath()
    			ctx.arc(x,y,5,0,2*Math.PI)
    			ctx.fill()
    		}
    		reDraw() {
    			ctx.fillStyle = this.color
    			ctx.beginPath()
    			ctx.arc(this.x,this.y,5,0,2*Math.PI)
    			ctx.fill()
    		}
    
    	}

    reDraw()方法就是对这个点的重画,点位置移动后重新画上去。

  2. 随机点的生成。随机点的位置其实也不是随机的,最基本的它不能超出画布范围,还有重要的一点就是它的位置必须是蛇可以经过的地方,可能说的不是很明白。但是大家应该都能明白..比如上边的代码设置的点的半径为5px,所以这个随机点的x、y都必须是5的整数倍,不然的话蛇就可能不会和随机点正面相撞,也就是虽然相遇了,但不在一条直线上。代码:
     

    //生成随机点
    	function randomDot () {
    		let x = parseInt(Math.random()*10 + 1) * (width-100)/10
    		let y = parseInt(Math.random()*10 + 1) * (height-100)/10
    		//判断点不在snake上,如果存在,重新生成
    		for(let dot of snake){
    			if(dot.x == x && dot.y == y){
    				return randomDot()
    			}
    		}
    		return new Dot(x,y,'white')
    	}

     

  3. 碰撞的判断。我判断碰撞就是简单的比较一下蛇头的x、y坐标和随机点的坐标是否一致

  4. 方向的控制。这个我想大家都会就不多说了:
     

    window.onkeydown = function(eve){
    		switch(eve.keyCode){
            case 38:
                dir = 'up'
                break;
            case 40:
                dir = 'down'
                break;
            case 37:
                dir = 'left'
                break;
            case 39:
                dir = 'right'
                break;
        	}
    	}

     

  5. 最后一步就是贪吃蛇的移动(画布刷新)、判断碰撞、长大、游戏失败等等的逻辑了。
    通过setInterval来刷新画布,贪吃蛇使用一个存储‘点’的数组来表示,最后一个元素作为蛇头,通过点的next属性来判断每一个点下次的位置。需要注意的是蛇头的next为空,需要根据运动方向计算出来:nextDot(dot)。把点的x、y重新赋值,以及点的next信息重新赋值以后,调用reDraw()方法重新在画布上画出来就可以了。
    代码:

  6. let time = 500
    	let refresh =  setInterval(()=>updateCanvas(),time)
    
    	function updateCanvas(){
    		ctx.clearRect(0,0,width,height)
    		currentDot.reDraw()
    
    		let dot = snake[snake.length - 1]
    		snake[snake.length - 1] = nextDot(dot)
    		//非末尾元素
    		for(let i = 0; i < snake.length-1; i++){
    			let next = snake[i].next
    			let sNext = snake[i+1]
    			snake[i] = new Dot(next.x,next.y,'red')
    			if(sNext.next == null){
    				snake[i].next = new Dot(dot.x,dot.y,'red')
    			}else{
    				snake[i].next = new Dot(sNext.next.x,sNext.next.y,'red')
    			}
    			snake[i].reDraw()
    		}
    
    		if(dot.x < 0 || dot.y < 0 || dot.x > width || dot.y > height){
    			clearInterval(refresh)
    			alert("游戏结束...")
    		}
    
    		if(dot.x == currentDot.x && dot.y == currentDot.y){
    			score += 5
    			document.getElementById('score').innerHTML = score
    			dot.next = currentDot
    			dot.color = 'red'
    			snake.push(currentDot)
    			currentDot = randomDot()
    			//吃到一个点,速度变快
    			clearInterval(refresh)
    			time = time - 50
    			if(time <= 50) time  = 50
    			refresh = setInterval(()=>updateCanvas(),time)
    		}
    		dot.reDraw()
    	}

    下面是完整的代码:
     

    <!DOCTYPE html>
    <html>
    <head>
    	<title>贪吃蛇</title>
    </head>
    <body>
    <div style="width: 1030px">
    	<canvas id="canvas" width="900" height="500" style="background-color: #2a8e2a;float: left;"></canvas>
    	<div style="float: right;">得分:<h5 id="score" style="display: inline;">0</h5></div>
    	<div style="float: right;"><button onclick="stopOrRun(this)">暂停</button>&nbsp;&nbsp;&nbsp;</div>
    	<div><button onclick="speedUp()">加速</button> <button onclick="speedDown()">减速</button></div>
    </div>
    </body>
    <script type="text/javascript">
    	let ctx = document.getElementById('canvas').getContext('2d')
    	let width = 900
    	let height = 500
    	let score = 0
    	let isRun = true
    	class Dot {
    		constructor(x,y,color){
    			this.color = color
    			this.x = x
    			this.y = y
    			this.next = null
    
    			ctx.fillStyle = this.color
    			ctx.beginPath()
    			ctx.arc(x,y,5,0,2*Math.PI)
    			ctx.fill()
    		}
    		reDraw() {
    			ctx.fillStyle = this.color
    			ctx.beginPath()
    			ctx.arc(this.x,this.y,5,0,2*Math.PI)
    			ctx.fill()
    		}
    
    	}
    	let dir = 'right'
    	//初始化snake
    	let snake = new Array()
    	let len = 5
    	for(let i = 1; i <= len; i++){
    		let nextDot = null
    		if(i < len) nextDot = new Dot(10 * (i+1),50,'red')
    		let dot = new Dot(10 * i,50,'red')
    		if(i === len) dot.color = 'white'
    		dot.next = nextDot
    		snake.push(dot)
    	}
    
    	let currentDot = randomDot()
    
    	
    	//生成随机点
    	function randomDot () {
    		let x = parseInt(Math.random()*10 + 1) * (width-100)/10
    		let y = parseInt(Math.random()*10 + 1) * (height-100)/10
    		//判断点不在snake上,如果存在,重新生成
    		for(let dot of snake){
    			if(dot.x == x && dot.y == y){
    				return randomDot()
    			}
    		}
    		return new Dot(x,y,'white')
    	}
    
    
    	let time = 500
    	let refresh =  setInterval(()=>updateCanvas(),time)
    
    	function updateCanvas(){
    		ctx.clearRect(0,0,width,height)
    		currentDot.reDraw()
    
    		let dot = snake[snake.length - 1]
    		snake[snake.length - 1] = nextDot(dot)
    		//非末尾元素
    		for(let i = 0; i < snake.length-1; i++){
    			let next = snake[i].next
    			let sNext = snake[i+1]
    			snake[i] = new Dot(next.x,next.y,'red')
    			if(sNext.next == null){
    				snake[i].next = new Dot(dot.x,dot.y,'red')
    			}else{
    				snake[i].next = new Dot(sNext.next.x,sNext.next.y,'red')
    			}
    			snake[i].reDraw()
    		}
    
    		if(dot.x < 0 || dot.y < 0 || dot.x > width || dot.y > height){
    			clearInterval(refresh)
    			alert("游戏结束...")
    		}
    
    		if(dot.x == currentDot.x && dot.y == currentDot.y){
    			score += 5
    			document.getElementById('score').innerHTML = score
    			dot.next = currentDot
    			dot.color = 'red'
    			snake.push(currentDot)
    			currentDot = randomDot()
    			//吃到一个点,速度变快
    			clearInterval(refresh)
    			time = time - 50
    			if(time <= 50) time  = 50
    			refresh = setInterval(()=>updateCanvas(),time)
    		}
    		dot.reDraw()
    	}
    
    
    	function nextDot(dot){
    		switch(dir){
    			case 'right':
    				dot.x = dot.x + 10
    				break;
    			case 'left':
    				dot.x = dot.x - 10
    				break;
    			case 'up':
    				dot.y = dot.y - 10
    				break;
    			case 'down':
    				dot.y = dot.y + 10
    				break;
    		}
    		return dot
    	}
    
    	window.onkeydown = function(eve){
    		switch(eve.keyCode){
            case 38:
                dir = 'up'
                break;
            case 40:
                dir = 'down'
                break;
            case 37:
                dir = 'left'
                break;
            case 39:
                dir = 'right'
                break;
        	}
    	}
    
    	function stopOrRun (obj) {
    		if(isRun){
    			obj.innerHTML = '运行'
    			clearInterval(refresh)
    			isRun = false
    		}else{
    			obj.innerHTML = '暂停'
    			refresh = setInterval(()=>updateCanvas(),time)
    			isRun = true
    		}
    	}
    
    	function speedUp() {
    		time -= 10
    		clearInterval(refresh)
    		if(time <= 50) time  = 50
    		refresh = setInterval(()=>updateCanvas(),time)
    	}
    	function speedDown() {
    		time += 10
    		clearInterval(refresh)
    		if(time <= 50) time  = 50
    		refresh = setInterval(()=>updateCanvas(),time)
    	}
    </script>
    </html>

     

  7. over。

转载于:https://my.oschina.net/xiwanglr/blog/1493105

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值