添加障碍&碰撞到画布游戏

时间:2015-06-03 18:28:00

标签: javascript canvas collision-detection

我试图为我已经获得的画布游戏添加一些障碍,但似乎有些错误,我似乎无法将手指放在上面。

我只是想在这里和那里使用一些简单的墙壁来使游戏更难和与墙壁发生碰撞(这样如果玩家撞到了墙壁,它的游戏结束了)。



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;
&#13;
&#13;

Fiddle

1 个答案:

答案 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,但我不确定最大尺寸是多少。