javascript - 如何检测 2D 瓷砖游戏 map 中的碰撞

标签 javascript canvas 2d tile

我制作了这个基本游戏,我画了一张 map 和一个玩家,玩家可以移动到任何地方,但我怎样才能使它在 map 中的图 block [1]上时不会移动? 另外,当我尝试检查 player.x 是否大于 50 时,它可能会向左移动,但如果我一次单击 2 个键,它就会通过 const context = document.querySelector("canvas").getContext("2d");

var rgb = 'rgb(' + Math.random()*256 + ',' + Math.random()*256 + ',' + Math.random()*256 + ','+Math.random() + ')';

document.onload = Loop();

var width = 1500;
var height = 800;

function Loop(){

  var width = 1500;
  var height = 800;

  context.canvas.height = height;
  context.canvas.width = width;

  this.interval = setInterval(Update, 1000/100);

}



const Player = function(x, y, w, h, color) {
  this.x = x; this.y = y; this.w = w; this.h = h;

  this.speedY = 0; this.speedX = 0;
  this.Draw = function(){
    context.fillStyle = this.color;
    context.fillRect(this.x, this.y, this.w, this.h);
  };
  this.Move = function(){
    this.x += this.speedX;
    this.y += this.speedY;
  };
};<code>

var player = new Player(100,100,50, 50, rgb);


var Key = {};
function Update(){
  context.clearRect(0, 0, width, height);
  Map();
  player.Draw();
  player.Move();

onkeydown = onkeyup = function(e){
  player.speedX = 0;
  player.speedY = 0;
  e = e || event;
  Key[e.keyCode] = e.type == 'keydown';
    if(Key[37] || Key[65]) {player.speedX -= 2}
    if(Key[38] || Key[87]) {player.speedY -= 2}
    if(Key[39] || Key[68]) {player.speedX += 2}
    if(Key[40] || Key[83]) {player.speedY += 2}
    if(Key[32]) {player.color = 'rgb(' + Math.random()*256 + ',' + Math.random()*256 + ',' + Math.random()*256 + ','+Math.random()*1 + ')';}
  };
}

var map = [
1, 1, 1, 1, 1,
1, 0, 0, 0, 1,
1, 0, 0, 0, 1,
1, 0, 0, 0, 1,
1, 1, 1, 1, 1
    ];

var row = 5;
var column = 5;


function Map(){
  for(let y = -1; y < column; y++){

    for(let x = -1; x < row; x++){
      switch(map[((y*row) + x)]) {
        case 0: context.fillStyle = player.color;
          break;
        case 1: context.fillStyle = "#ffffff";
          break;
        default: context.fillStyle = "#000000";
      }
    context.fillRect(x*50, y*50, 50, 50);

    }
  }
}

最佳答案

<!doctype html>
<html>
	<head>
		<meta charset="utf-8">
		<style>
			body {
				background-color: black;
			}
			
			canvas {
				display: block;
				margin: auto;
				border: solid 1px white;
				border-radius: 10px;
			}
			
			script {
				display: none;
			}
		</style>
	</head>
	
	<body>
		<canvas id="canvas"></canvas>
		<script type="application/javascript">
		
		void function() {
			
			"use strict";
			
			// Classes
			function Camera(x,y) {
				this.x = x || 0.0;
				this.y = y || 0.0;
			}
			
			Camera.prototype = {
				set: function(x,y) {
					this.x = x || 0.0;
					this.y = y || 0.0;
				},
				
				pan: function(x,y) {
					this.x += x || 0.0;
					this.y += y || 0.0;
				}
			};
			
			var nextID = 0;
			
			function Tile(colour) {
				this.id = nextID++;
				this.colour = colour || "black";
			}
			
			function Map(width,height) {
				this.width = width || 1;
				this.height = height || 1;
				this.map = [];
				this.map.length = this.height;
				
				for (var y = 0; y < this.height; ++y) {
					this.map[y] = [];
					this.map[y].length = width;
					
					for (var x = 0; x < this.width; ++x) {
						this.map[y][x] = Math.random() < 0.2 ?
							this.TILE_WALL:
							this.TILE_GRASS;
					}
					
					this.map[y][0] = this.TILE_WALL;
					this.map[y][this.width - 1] = this.TILE_WALL;
				}
				
				for (var x = 0; x < this.width; ++x) {
					this.map[0][x] = this.TILE_WALL;
					this.map[this.height - 1][x] = this.TILE_WALL;
				}
			}
			
			Map.prototype = {
				TILE_WIDTH: 32.0,
				TILE_HEIGHT: 32.0,
				INV_TILE_WIDTH: 0.0,
				INV_TILE_HEIGHT: 0.0,
			
				TILE_AIR: new Tile("#00000000"),
				TILE_GRASS: new Tile("#00AA00FF"),
				TILE_WALL: new Tile("#555555FF"),
			
				set: function(x,y,tile) {
					this.map[y][x] = tile;
				},
			
				scaleX: function(x) {
					return (x * this.INV_TILE_WIDTH) | 0;
				},
			
				scaleY: function(y) {
					return (y * this.INV_TILE_HEIGHT) | 0;
				},
			
				isColliding: function(x,y) {
					return x > -1 && x < this.width
						&& y > -1 && y < this.height
						&& this.map[y][x].id > 1;
				},
			
				render: function(ctx,camera) {
					for (var y = 0; y < this.height; ++y) {
						for (var x = 0; x < this.width; ++x) {
							var tile = this.map[y][x];
							var _x = x * this.TILE_WIDTH - camera.x;
							var _y = y * this.TILE_HEIGHT - camera.y;
							
							ctx.fillStyle = tile.colour;
							ctx.fillRect(_x,_y,this.TILE_WIDTH - 1,this.TILE_HEIGHT - 1);
						}
					}
				}
			};
			
			Map.prototype.INV_TILE_WIDTH = 1.0 / Map.prototype.TILE_WIDTH;
			Map.prototype.INV_TILE_HEIGHT = 1.0 / Map.prototype.TILE_HEIGHT;
			
			function Player(x,y) {
				this.x = x || 0.0;
				this.y = y || 0.0;
				this.dx = 0.0;
				this.dy = 0.0;
				this.isUp = false;
				this.isDown = false;
				this.isLeft = false;
				this.isRight = false;
			}
			
			Player.prototype = {
				WIDTH: 20.0,
				HEIGHT: 20.0,
				
				ACCELERATION: 1.0,
				DEACCELERATION: 0.5,
				MAX_SPEED: 3.0,
				
				tick: function(map) {
					// Movement
					if (this.isUp) {
						this.dy -= this.ACCELERATION;
						
						if (this.dy < -this.MAX_SPEED) {
							this.dy = -this.MAX_SPEED;
						}
					} else if (this.dy < 0.0) {
						this.dy += this.DEACCELERATION;
						
						if (this.dy > 0.0) {
							this.dy = 0.0;
						}
					}
					
					if (this.isDown) {
						this.dy += this.ACCELERATION;
						
						if (this.dy > this.MAX_SPEED) {
							this.dy = this.MAX_SPEED;
						}
					} else if (this.dy > 0.0) {
						this.dy -= this.DEACCELERATION;
						
						if (this.dy < 0.0) {
							this.dy = 0.0;
						}
					}
					
					if (this.isLeft) {
						this.dx -= this.ACCELERATION;
						
						if (this.dx < -this.MAX_SPEED) {
							this.dx = -this.MAX_SPEED;
						}
					} else if (this.dx < 0.0) {
						this.dx += this.DEACCELERATION;
						
						if (this.dx > 0.0) {
							this.dx = 0.0;
						}
					}
					
					if (this.isRight) {
						this.dx += this.ACCELERATION;
						
						if (this.dx > this.MAX_SPEED) {
							this.dx = this.MAX_SPEED;
						}
					} else if (this.dx > 0.0) {
						this.dx -= this.DEACCELERATION;
						
						if (this.dx < 0.0) {
							this.dx = 0.0;
						}
					}
					
					// Collision
					if (this.dx !== 0.0) {
						var minY = map.scaleY(this.y);
						var maxY = map.scaleY(this.y + this.HEIGHT);
						var minX = 0;
						var maxX = 0;
						
						if (this.dx < 0.0) {
							minX = map.scaleX(this.x + this.dx);
							maxX = map.scaleX(this.x);
						} else {
							minX = map.scaleX(this.x + this.WIDTH);
							maxX = map.scaleX(this.x + this.WIDTH + this.dx);
						}
						
						loop:
						for (var y = minY; y <= maxY; ++y) {
							for (var x = minX; x <= maxX; ++x) {
								if (map.isColliding(x,y)) {
									this.x = this.dx < 0.0 ?
										(x + 1) * map.TILE_WIDTH:
										x * map.TILE_WIDTH - this.WIDTH - 1;
								
									this.dx = 0.0;
									break loop;
								}
							}
						}
					}
					
					if (this.dy !== 0.0) {
						var minX = map.scaleX(this.x);
						var maxX = map.scaleX(this.x + this.WIDTH);
						var minY = 0;
						var maxY = 0;
						
						if (this.dy < 0.0) {
							minY = map.scaleY(this.y + this.dy);
							maxY = map.scaleY(this.y);
						} else {
							minY = map.scaleY(this.y + this.HEIGHT);
							maxY = map.scaleY(this.y + this.HEIGHT + this.dy);
						}
						
						loop:
						for (var y = minY; y <= maxY; ++y) {
							for (var x = minX; x <= maxX; ++x) {
								if (map.isColliding(x,y)) {
									this.y = this.dy < 0.0 ?
										(y + 1) * map.TILE_HEIGHT:
										y * map.TILE_HEIGHT - this.HEIGHT - 1;
								
									this.dy = 0.0;
									break loop;
								}
							}
						}
					}
					
					this.x += this.dx;
					this.y += this.dy;
				},
				
				render: function(ctx,camera) {
					camera.set(this.x,this.y);
				
					ctx.lineWidth = 1;
					ctx.strokeStyle = "black";
					ctx.fillStyle = "darkred";
					ctx.beginPath();
					ctx.rect(this.x - camera.x,this.y - camera.y,this.WIDTH,this.HEIGHT);
					ctx.fill();
					ctx.stroke();
				}
			};
			
			// Variables
			var canvasWidth = 180;
			var canvasHeight = 160;
			var canvas = null;
			var ctx = null;
			var camera = null;
			var map = null;
			var player = null;
			
			// Functions
			function onKeyDown(e) {
				switch(e.key.toUpperCase()) {
					case "W": player.isUp = true; break;
					case "S": player.isDown = true; break;
					case "A": player.isLeft = true; break;
					case "D": player.isRight = true; break;
				}
			}
			
			function onKeyUp(e) {
				switch(e.key.toUpperCase()) {
					case "W": player.isUp = false; break;
					case "S": player.isDown = false; break;
					case "A": player.isLeft = false; break;
					case "D": player.isRight = false; break;
				}
			}
			
			function loop() {
				// Tick
				player.tick(map);
				
				// Render
				ctx.fillStyle = "gray";
				ctx.fillRect(-canvasWidth >> 1,-canvasHeight >> 1,canvasWidth,canvasHeight);
				
				map.render(ctx,camera);
				player.render(ctx,camera);
				
				//
				requestAnimationFrame(loop);
			}
			
			// Entry point (first to execute)
			onload = function() {
				canvas = document.getElementById("canvas");
				canvas.width = canvasWidth;
				canvas.height = canvasHeight;
				
				ctx = canvas.getContext("2d");
				ctx.translate(canvasWidth >> 1,canvasHeight >> 1);
				
				camera = new Camera(0.0,0.0);
				map = new Map(10,10);
				player = new Player(40.0,40.0);
				
				map.set(1,1,map.TILE_GRASS);
				
				addEventListener("keydown",onKeyDown);
				addEventListener("keyup",onKeyUp);
				
				loop();
			}
			
		}();
		
		</script>
	</body>
</html>

关于javascript - 如何检测 2D 瓷砖游戏 map 中的碰撞,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51127865/

相关文章:

javascript - typescript 编译为单个文件

javascript - 使用Javascript添加 `nofollow`是没有用的吗?

javascript - Canvas 按点绘制图像

javascript - 使 Canvas 游戏响应调整大小

C 动态分配的数组未正确传递

javascript - 继续不会自动滚动

javascript - 如何动态使用 for 循环,将具有不同参数的函数推送到数组?

javascript - html Canvas 中的关键灵敏度

c - 如何在 C 中将 token 字符中的值设置为名为 customerData[][] 的数组?

c++ - 将动态二维数组在 C++ 和 Fortran 之间传递