我试图为我已经获得的画布游戏添加一些障碍,但似乎有些错误,我似乎无法将手指放在上面。
我只是想在这里和那里使用一些简单的墙壁来使游戏更难和与墙壁发生碰撞(这样如果玩家撞到了墙壁,它的游戏结束了)。
var
// variables
COLS = 25, // Columns
ROWS = 25, // Rows
EMPTY = 0, // Empty Cell
SNAKE = 1, // Snake
FRUIT = 2, // Fruit
LEFT = 0, // left direction (key)
UP = 1, // up direction (key)
RIGHT = 2, // right direction (key)
DOWN = 3, // down direction (key)
KEY_LEFT = 37, // key codes for keyboard input (Codes can be found online)
KEY_UP = 38, // key codes for keyboard input (Codes can be found online)
KEY_RIGHT = 39, // key codes for keyboard input (Codes can be found online)
KEY_DOWN = 40, // key codes for keyboard input (Codes can be found online)
obstacle = [[0,0,2,0,0,0,0,2,0,0,0,0,2,0,0,0,0,2,0,0,0,0,2,0,0]],
// [0,0,2,0,0,0,0,2,0,0,0,0,2,0,0,0,0,2,0,0,0,0,2,0,0],
// [0,0,2,0,0,0,0,2,0,0,0,0,2,0,0,0,0,2,0,0,0,0,2,0,0],
// [0,0,2,0,0,0,0,2,0,0,0,0,2,0,0,0,0,2,0,0,0,0,2,0,0],
// [0,0,2,0,0,0,0,2,0,0,0,0,2,0,0,0,0,2,0,0,0,0,2,0,0]],
// Objects
canvas, // Canvas
ctx, // Canvas render
keystate, // Key inputs
frames, // frames per second
score; // player score
grid = {
width: null, // Amount of columns
height: null, // Amount of rows
_grid: null, // Array
init: function(d, c, r) { // initiation with direction, columns and rows.
this.width = c; // Set width to number of columns (c)
this.height = r; // set height to number of rows (r)
this._grid = []; // Initiate grid with empty array
for (var x=0; x < c; x++) {
this._grid.push([]);
for (var y=0; y < r; y++) {
this._grid[x].push(d); // set current column and push new value for each row in column
}
}
},
set: function(val, x, y) { // set values for the grid cells with x and y position
this._grid[x][y] = val;
},
get: function(x, y) { // get the value of x and y position
return this._grid[x][y];
}
}
snake = { // Creating snake
direction: null, // Direction of snake
last: null, // last element in queue pointer
_queue: null, // queue array
// Sets start position of snake, same initiation method as before
init: function(d, x, y) {
this.direction = d; // Direction set to d
this._queue = []; // Another empty queue array
this.insert(x, y); // Inserting x & y position
},
// Insert method that adds elements to queue with x and y position
insert: function(x, y) {
this._queue.unshift({x:x, y:y}); // unshift prepends an element to array
this.last = this._queue[0];
},
// Remove function to remove and return element to queue
remove: function() {
return this._queue.pop(); // pop returns the last element of array
}
};
function obstacle() {
empty.push({obstacle});
ctx.beginPath();
ctx.rect(obstacle);
ctx.fillStyle = "#7a26ce";
ctx.fill();
ctx.closePath();
}
function setFood() { // Food for hungry snake
var empty = []; // tracks all empty places in the grid
// for loop to find all empty cells in grid
for (var x=0; x < grid.width; x++) {
for (var y=0; y < grid.height; y++) {
if (grid.get(x, y) === EMPTY) {
empty.push({x:x, y:y});
}
}
}
// variable randomposition to pick random empty cell
var randpos = empty[Math.round(Math.random()*(empty.length - 1))];
grid.set(FRUIT, randpos.x, randpos.y);
}
function main() { // call all the functions that we will use in the game
// canvas
canvas = document.createElement("canvas");
canvas.width = COLS*20; // Sets canvas width to columns * 20
canvas.height = ROWS*20; // Sets canvas height to columns * 20
ctx = canvas.getContext("2d");
document.body.appendChild(canvas); // Adds canvas element to the body of the document
ctx.font = "12px sans-serif"; // font
frames = 0;
keystate = {};
document.addEventListener("keydown", function(evt) { // Track all keyboard input
keystate[evt.keyCode] = true;
});
document.addEventListener("keyup", function(evt) { // Track all keyboard input
delete keystate[evt.keyCode];
});
init(); // Initiate Game Loop
loop(); // Start Game Loop
}
function init() { // Reset and intiate game objects
score = 0; // set start score to 0
grid.init(EMPTY, COLS, ROWS);
var sp = {x:Math.floor(COLS/2), y:ROWS-1};
snake.init(UP, sp.x, sp.y); // Start direction
grid.set(SNAKE, sp.x, sp.y);
setFood();
grid._grid = grid._grid.concat(obstacle);
}
function loop() { // Game loop for rendering and objects
update();
draw();
window.requestAnimationFrame(loop, canvas); // Canvas will call loop function when it needs to redraw
}
function update() { // update function
frames++;
// Keyboard input
if (keystate[KEY_LEFT] && snake.direction !== RIGHT) {
snake.direction = LEFT;
}
if (keystate[KEY_UP] && snake.direction !== DOWN) {
snake.direction = UP;
}
if (keystate[KEY_RIGHT] && snake.direction !== LEFT) {
snake.direction = RIGHT;
}
if (keystate[KEY_DOWN] && snake.direction !== UP) {
snake.direction = DOWN;
}
// Update game every 5 frames.
if (frames%5 === 0) {
// last element from the snake queue
var nx = snake.last.x;
var ny = snake.last.y;
// Updating the position of snake depending on the direction it is heading
switch (snake.direction) {
case LEFT:
nx--;
break;
case UP:
ny--;
break;
case RIGHT:
nx++;
break;
case DOWN:
ny++;
break;
}
// if statement checking conditions whether game should keep running or reset aka game over
if (0 > nx || nx > grid.width-1 ||
0 > ny || ny > grid.height-1 ||
grid.get(nx, ny) === SNAKE
) {
return init();
}
// Checks the new position of the snake and if it's on a fruit item or not.
if (grid.get(nx, ny) === FRUIT) {
// If it is on a fruit item it will increase your score and create a new food in a random cell.
score++;
setFood();
} else {
// Takes out the tail (first item) from queue and removes identifier from the grid.
var tail = snake.remove();
grid.set(EMPTY, tail.x, tail.y);
}
// Snake identifier that is created at the new position and is added to the queue
grid.set(SNAKE, nx, ny);
snake.insert(nx, ny);
}
}
function draw() { // render grid to canvas
var tw = canvas.width/grid.width; // Calculate tile width
var th = canvas.height/grid.height; // Calculate tile height
for (var x=0; x < grid.width; x++) { // for-loop loops through entire grid to draw cells
for (var y=0; y < grid.height; y++) {
// Depending on the identifier of each cell sets certain fillstyle defined below.
switch (grid.get(x, y)) {
case EMPTY:
ctx.fillStyle = "#5a5a5a";
break;
case SNAKE:
ctx.fillStyle = "#B54548";
break;
case FRUIT:
ctx.fillStyle = "lightblue";
break;
case obstacle:
ctx.fillStyle = "yellow";
break;
}
ctx.fillRect(x*tw, y*th, tw, th);
}
}
// Change fillstyle and show score on the screen.
ctx.fillStyle = "#000";
ctx.fillText("SCORE: " + score, 10, canvas.height-10);
}
// Game Start!
main();
&#13;
canvas {
display: block;
position: absolute;
border: 2px solid #000;
margin: auto;
top: 0;
bottom: 0;
right: 0;
left: 0;
}
&#13;
或 Fiddle 。
答案 0 :(得分:0)
我一直在用碰撞制作游戏,我发现使用碰撞图是最简单的方法,而不是让一个对象同时存储所有实体。这是一个例子:
var collisions = [];
function addCollision(x,y){
if(typeof collisions[x] == "undefined")collisions[x] = []; //If the row is empty, create it
collisions[x][y] = true; //Set the row and column to true
};
function checkCollision(x,y){
return (typeof collisions[x] != "undefined")?//If the row is undefined, there's nothing in it, so return false
((typeof collisions[x][y] != "undefined") //If not, but the column is undefined, return false
?true:false):false; //If the row and column is true, return true.
};
现在,addCollision(x,y)
会放置一个新作品,checkCollision(x,y)
会看到x,y处有任何内容。
这对(相对)小型地图很有用,因为大型地图会占用大量内存。我已经能够做500x500,但我不确定最大尺寸是多少。