javascript - 防止蛇向反方向移动

标签 javascript

为了周末的乐趣,我正在用 JavaScript 重制一个经典的蛇,我遇到了这个问题,如果我相当快地按下按钮 - 蛇(在我的例子中是毛毛虫)能够改变方向相反并撞到自己.

重现这种情况的方法如下:

方向例如'left'

向上(或向下)按下然后快速向右按下

现在毛毛虫倒退了。我的目标是掉头

我检查了相反的目录,但这并不能阻止这种情况

update = function() {
    if (cat.direction != 'right' && key[37] === true) {
        cat.direction = 'left';
    }
    if (cat.direction != 'left' && key[39] === true) {
        cat.direction = 'right';
    }
    if (cat.direction != 'down' && key[38] === true) {
        cat.direction = 'up';
    }
    if (cat.direction != 'up' && key[40] === true) {
        cat.direction = 'down';
    }
};

the full code

我使用普通的 addEventListener 进行按键监听,但我将其更改为另一种方法(在某处找到),我经常更新按键并且毛毛虫移动只是不时发生,因为我认为在同一时间间隔内直接关联绘图、改变方向和移动可能是一个问题。我希望我是可以理解的,如果有什么不清楚的话,我很抱歉 - 如果是的话,我很乐意提供更多信息。

最佳答案

一个解决方案是每次移动不处理多个键,但为了允许更多的响应,您可以实现一个键缓冲区,而不是像您所知道的那样维护键状态。您只会在该缓冲区中收集箭头键按下操作,而不会将任何重复的相同按键插入其中。

以下是对代码的相关更改:

初始化 key 缓冲区:

var keyBuffer = [];

按下时将箭头键插入缓冲区:

var keyDown = function(e) {
    var keyCode = e.which ? e.which : e.keyCode;
    // *** Queue the arrow key presses
    if (keyCode >= 37 && keyCode <= 40 && 
            keyCode !== keyBuffer[keyBuffer.length-1] && ) {
        keyBuffer.push(keyCode);
    }
};

一次处理缓冲区中的一个键:

var update = function() {
    // *** Extract next key from buffer, and only treat that one
    // -- could be `undefined`, but that is not a problem:
    var key = keyBuffer.shift();
    if(cat.direction != 'right' && key === 37){
        cat.direction = 'left';
    } else if(cat.direction != 'left' && key === 39){
        cat.direction = 'right';
    } else if(cat.direction != 'down' && key === 38){
        cat.direction = 'up';
    } else if(cat.direction != 'up' && key === 40){
        cat.direction = 'down';
    }
};

只有在要移动时才处理下一个键:

function loop() {
    board.resetCanvas();
    if(counter > 1000){
        update(); // ***only process buffered keys when moving
        cat.move();
        counter = 0;
    }
    cat.draw();
    counter += 5*cat.multiplier;
};

就是这样。请参阅下面的 fiddle :

var canvas = document.getElementById("board");
var context = canvas.getContext("2d", {alpha:false});
var pieceSideLength = canvas.width / 40;
var key = [];
var keyBuffer = [];

window.addEventListener('keyup', function(e) {
    this.keyUp.call(this, e);
}, false);
window.addEventListener('keydown', function(e) {
    this.keyDown.call(this, e); 
}, false);
				
function Piece(x,y){
		this.x = x;
		this.y = y;
}

board = {
	
    leftBound: 0,
    rightBound: canvas.width / pieceSideLength,
    topBound: 0,
    bottomBound: canvas.height / pieceSideLength,
   
	drawPiece: function(x, y, color){
		context.fillStyle = color;
		context.fillRect(x*pieceSideLength,y*pieceSideLength,pieceSideLength,pieceSideLength);
		context.strokeStyle = 'white';
		context.strokeRect(x*pieceSideLength,y*pieceSideLength,pieceSideLength,pieceSideLength);
	},
	
	resetCanvas: function(){
		context.clearRect(0,0,canvas.width,canvas.height);
	}
	
};
//cat as for caterpillar
cat = {

	x: canvas.width/pieceSideLength/2, //initial x 
	y: canvas.height/pieceSideLength/2, //initial y
	pieces: [],
	direction: 'up',
	color: '#5da03c',
	shouldGrow: false,
	multiplier: 5,
   
    init: function(){
		cat.pieces.push(new Piece(this.x, this.y));
    },
   
    move: function(){
		if(cat.pieces.length <= 10){
			cat.shouldGrow = true;
		}
        var newX = cat.pieces[cat.pieces.length-1].x;
        var newY = cat.pieces[cat.pieces.length-1].y;
		if(cat.direction=='up'){
			cat.makeNewHeadAt(newX,newY-1);
		  }
		if(cat.direction=='down'){
			cat.makeNewHeadAt(newX,newY+1);
		  }
		if(cat.direction=='left'){
			cat.makeNewHeadAt(newX-1,newY);
		  }
		if(cat.direction=='right'){
			cat.makeNewHeadAt(newX+1,newY);
		  }
		  cat.grow();
		},
   
    makeNewHeadAt: function(x,y){
		cat.pieces.push(new Piece(x,y));
    },
   
    grow: function(){
		if(cat.shouldGrow == false){
			cat.pieces.shift();
		} else {
			cat.shouldGrow = false;
		}
    },
   
    draw: function(){
		for(i=0;i<cat.pieces.length;i++){
			var p = cat.pieces[i];
			board.drawPiece(p.x,p.y,cat.color);
		}
    }
   
   
   
   
   
   
   
};
cat.init();
update = function() {
    // *** Extract next key from buffer, and only treat that one
    // -- could be `undefined`, but that is not a problem:
    var key = keyBuffer.shift();
	if(cat.direction != 'right' && key === 37){
		cat.direction = 'left';
	} else if(cat.direction != 'left' && key === 39){
		cat.direction = 'right';
	} else if(cat.direction != 'down' && key === 38){
		cat.direction = 'up';
	} else if(cat.direction != 'up' && key === 40){
		cat.direction = 'down';
	}
};
keyUp = function(e) {
    var keyCode = e.which ? e.which : e.keyCode;
    this.key[keyCode] = false;
};
keyDown = function(e) {
    var keyCode = e.which ? e.which : e.keyCode;
    // *** Queue the key presses
    if (keyCode >= 37 && keyCode <= 40 && 
            keyCode !== keyBuffer[keyBuffer.length-1]) {
        keyBuffer.push(keyCode);
    }
    this.key[keyCode] = true;
};

var counter = 0;
function loop() {

    board.resetCanvas();
	if(counter > 1000){
        update(); // ***only process buffered keys when moving
		cat.move();
		counter = 0;
	}
	cat.draw();
    
    counter += 5*cat.multiplier;

};
setInterval(loop, 1);
body { margin: 0px }
<div>
    <canvas id="board" width="300" height="200" style="display: block; margin: 0 auto; background-color: #553300; border-style: solid; border-color: green;"></canvas>
</div>

限制缓冲区大小

您可以通过替换此限制缓冲区大小:

keyBuffer.push(keyCode);

与:

keyBuffer = keyBuffer.slice(-2).concat(keyCode);

这会将大小限制为 3。根据需要调整 slice 参数。

关于javascript - 防止蛇向反方向移动,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43032014/

相关文章:

javascript - 带选项的温泉对话框

javascript - 将表单提交到 2 个不同的操作页面

javascript - 变量未定义 node.js

javascript - 将对象附加到 Javascript 数组

javascript - 如何在javascript中获取实际的类类型

javascript - 如何先按数字排序,再按字母顺序排序

javascript - Flot 或 Flotr2 CandleStick 带线条(组合系列)

javascript - 如何在不确定数组上使用 Promise all

javascript - 纯javascript拉动刷新

javascript - react 。如何取消订阅 React componentWillUnmount 中的事件处理程序?