Javascript 不绘制所有图块的 2d tilemap
Javascript 2d tilemap without drawing all tiles
我正在 JavaScript 中创建 2D 平台游戏。我正在尝试创建一个 tilemap,它不会在应该有空气的块中生成(在 tilemap 中标记为 0)。我没有收到任何错误。但是,canvas 中没有生成任何方块。除非我删除碰撞检测,否则游戏也会崩溃。
主要js
//drawing variables
var canvas;
var context;
//game variables
var gameLoop;
var player;
var borders = [];
var mapHeight = 12;
var mapWidth = 22;
var tilesize = 50;
//input variables
var upKey;
var rightKey;
var downKey;
var leftKey;
//runs once pace has been loaded
window.onload = function(){
//canvas and context variable setup
canvas = document.getElementById("gameCanvas")
context = canvas.getContext("2d")
//key listeners
setupInputs();
//create player
player = new Player(400, 400);
//create border
let tilemap = [
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
]
//create a box (border) based on tilemap position. Let 0's be air
for (let row = 0; row < mapHeight; row++){
for(let col = 0; col < mapWidth; col++){
if(tilemap[row][col] !== 0){
borders.push(new Border(tilemap[row]*tilesize, tilemap[col]*tilesize, tilesize, tilesize, tilemap[row][col]));
}
}
}
//initialize main game loop. Framerate = 30/sec
gameLoop = setInterval(step, 1000/30);
//draw canvas
context.fillStyle = "#f4f4f4f4"
context.fillRect(0, 0, mapWidth*tilesize, mapHeight*tilesize);
}
function step(){
player.step();
//draw after updates
draw();
}
function draw(){
//Clear previous canvas
context.fillStyle = "#f4f4f4f4"
context.fillRect(0, 0, mapWidth*tilesize, mapHeight*tilesize);
//draw the player
player.draw();
//draw borders
for(let i = 0; i < borders.length; i++){
borders[i].draw();
}
}
//keyboard inputs
function setupInputs(){
document.addEventListener("keydown", function(event){
if(event.key === "w"){
upKey = true;
} else if(event.key === "a"){
leftKey = true;
} else if(event.key === "s"){
downKey = true;
} else if(event.key === "d"){
rightKey = true;
}
});
document.addEventListener("keyup", function(event){
if(event.key === "w"){
upKey = false;
} else if(event.key === "a"){
leftKey = false;
} else if(event.key === "s"){
downKey = false;
} else if(event.key === "d"){
rightKey = false;
}
});
}
//Checking to see if player and border intersect
function checkIntersection(r1, r2){
if (r1.x >= r2.x + r2.width){
return false;
} else if (r1.x + r1.width <= r2.x){
return false;
} else if (r1.y >= r2.y + r2.height){
return false;
} else if (r1.y + r1.height <= r2.y){
return false;
} else {
return true;
}
}
播放器 js
function Player(x, y){
//Player variables
this.x = x;
this.y = y;
this.xvel = 0;
this.yvel = 0;
this.friction = 0.6;
this.maxVel = 12;
this.width = tilesize;
this.height = tilesize;
this.active = true;
this.falling = false;
this.step = function(){
if(this.active){
if(!leftKey && !rightKey || leftKey && rightKey){
this.xvel *= this.friction;
} else if (rightKey){
this.xvel++;
} else if (leftKey){
this.xvel--;
}
if(upKey){
//check if standing on ground
if (this.yvel === 0 && this.falling === false){
this.yvel -= 70;
this.falling = true;
} else{
this.yvel += 0;
}
}
this.yvel += 1;
//not allowing velocity to surpass maximum velocity
if (this.xvel > this.maxVel){
this.xvel = this.maxVel;
} else if(this.xvel < -this.maxVel){
this.xvel = -this.maxVel;
}
if (this.yvel > this.maxVel){
this.yvel = this.maxVel;
} else if(this.yvel < -this.maxVel){
this.yvel = -this.maxVel;
}
if (this.xvel > 0){
this.xvel = Math.floor(this.xvel);
} else {
this.xvel = Math.ceil(this.xvel);
}
if (this.yvel > 0){
this.yvel = Math.floor(this.yvel);
} else {
this.yvel = Math.ceil(this.yvel);
}
//collision rectangles
let horizontalRect = {
x: this.x + this.xvel,
y: this.y,
width: this.width,
height: this.height
}
let verticalRect = {
x: this.x,
y: this.y + this.yvel,
width: this.width,
height: this.height
}
//Collision deteQction
for(let i = 0; i<borders.length; i++){
let borderRect = {
x: borders[i].x,
y: borders[i].y,
width: borders[i].width,
height: borders[i].height
}
if (checkIntersection(horizontalRect, borderRect)){
while (checkIntersection(horizontalRect, borderRect)){
horizontalRect.x -= Math.sign(this.xvel);
}
this.x = horizontalRect.x;
this.xvel = 0;
}
if (checkIntersection(verticalRect, borderRect)){
while(checkIntersection(verticalRect, borderRect)){
verticalRect.y -= Math.sign(this.yvel);
}
this.y = verticalRect.y;
this.yvel = 0;
this.falling = false;
}
}
if (this.x + this.xvel > mapWidth*tilesize - tileisze){
this.xvel = 0;
}
if (this.x + this.xvel < 0){
this.xvel = 0;
}
this.x += this.xvel;
this.y += this.yvel;
}
}
this.draw = function(){
context.fillStyle = "orange";
context.fillRect(this.x, this.y, this.width, this.height);
}
}
边框 js
function Border(x, y, width, height, type){
this.x = x;
this.y = y;
this.width = width;
this.height = height;
this.type = type;
this.draw = function(){
if (this.type === 1){
context.fillStyle = "#2C2C34";
} else if (this.type === 2){
context.fillStyle = "#39393A";
}
context.fillRect(this.x, this.y, this.width, this.height);
}
}
您的代码中似乎有几个错误,可能需要一段时间才能全部找到。你的十六进制颜色有 8 个字符 "#f4f4f4f4"
。您的地图宽度为 22,但二维数组中只有 21 列。在创建边界数组时,x
点中有 rows
,y
点中有 col
,这似乎也不对。我觉得应该反过来。无论如何,如果您不反对使用一维数组,这里是您代码的简化版本,没有播放器内容。
边框
function Border(type, x, y){
this.x = x;
this.y = y;
this.width = TILE_SIZE;
this.height = TILE_SIZE;
this.type = type;
this.draw = function(){
if (this.type === 1){
context.fillStyle = "purple";
context.fillRect(this.x, this.y, this.width, this.height);
} else if (this.type === 2){
context.fillStyle = "orange";
context.fillRect(this.x, this.y, this.width, this.height);
}
}
}
和主文件
const canvas = document.getElementById("canvas")
const context = canvas.getContext("2d")
const TILE_SIZE = 25; //50 was too big for my screen based on how many rows/columns you wanted
canvas.width = 525; //TILE_SIZE * columns
canvas.height = 300; //TILE_SIZE * rows
var borders = [];
let tileMap = {
mapHeight: 12,
mapWidth: 21,
size: TILE_SIZE,
grid: [
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 2, 0, 0, 2, 0, 2, 2, 2, 0, 2, 0, 2, 0, 2, 0, 0, 0, 0, 0,
0, 0, 2, 0, 0, 2, 0, 0, 2, 0, 0, 2, 0, 2, 0, 2, 0, 0, 0, 0, 0,
0, 0, 2, 2, 2, 2, 0, 0, 2, 0, 0, 2, 0, 2, 0, 2, 0, 0, 0, 0, 0,
0, 0, 2, 0, 0, 2, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 2, 0, 0, 2, 0, 2, 2, 2, 0, 2, 0, 2, 0, 2, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
]
}
//Uses 1 loop to create the grid
function createGrid() {
for (let i = 0; i < tileMap.grid.length; i++) {
let x = (i % tileMap.mapWidth) * tileMap.size;
let y = Math.floor((i / tileMap.mapWidth)) * tileMap.size;
let type = tileMap.grid[i];
borders.push(new Border(type, x, y));
}
};
createGrid(); //creates the grid when file is loaded
function animate() {
context.clearRect(0, 0, canvas.width, canvas.height);
for(let i = 0; i < borders.length; i++){
borders[i].draw();
}
requestAnimationFrame(animate);
}
animate()
我只是为了这个例子在 animate 函数中插入了 for 循环。通常它会是它自己的功能,您可以在其中处理碰撞检测或绘制图块或您想用它们做的任何其他事情。
如果您必须使用二维数组,这里有一个函数可以创建它
function createGrid() {
for (let row = 0; row < tileMap.mapHeight; row++) {
for (let col = 0; col < tileMap.mapWidth; col++) {
let type = tileMap.grid[row][col];
let x = col * TILE_SIZE;
let y = row * TILE_SIZE;
borders.push(new Border(type, x, y))
}
}
}
createGrid()
如果您使用我上面发布的地图,请务必将地图改回 2d。我还注意到在您的播放器文件中您有一处 tileisze
而不是 tilesize
。我会花一些时间仔细清理您的文件中的错误,因为这些可能是您出现某些问题的原因。
我正在 JavaScript 中创建 2D 平台游戏。我正在尝试创建一个 tilemap,它不会在应该有空气的块中生成(在 tilemap 中标记为 0)。我没有收到任何错误。但是,canvas 中没有生成任何方块。除非我删除碰撞检测,否则游戏也会崩溃。
主要js
//drawing variables
var canvas;
var context;
//game variables
var gameLoop;
var player;
var borders = [];
var mapHeight = 12;
var mapWidth = 22;
var tilesize = 50;
//input variables
var upKey;
var rightKey;
var downKey;
var leftKey;
//runs once pace has been loaded
window.onload = function(){
//canvas and context variable setup
canvas = document.getElementById("gameCanvas")
context = canvas.getContext("2d")
//key listeners
setupInputs();
//create player
player = new Player(400, 400);
//create border
let tilemap = [
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
]
//create a box (border) based on tilemap position. Let 0's be air
for (let row = 0; row < mapHeight; row++){
for(let col = 0; col < mapWidth; col++){
if(tilemap[row][col] !== 0){
borders.push(new Border(tilemap[row]*tilesize, tilemap[col]*tilesize, tilesize, tilesize, tilemap[row][col]));
}
}
}
//initialize main game loop. Framerate = 30/sec
gameLoop = setInterval(step, 1000/30);
//draw canvas
context.fillStyle = "#f4f4f4f4"
context.fillRect(0, 0, mapWidth*tilesize, mapHeight*tilesize);
}
function step(){
player.step();
//draw after updates
draw();
}
function draw(){
//Clear previous canvas
context.fillStyle = "#f4f4f4f4"
context.fillRect(0, 0, mapWidth*tilesize, mapHeight*tilesize);
//draw the player
player.draw();
//draw borders
for(let i = 0; i < borders.length; i++){
borders[i].draw();
}
}
//keyboard inputs
function setupInputs(){
document.addEventListener("keydown", function(event){
if(event.key === "w"){
upKey = true;
} else if(event.key === "a"){
leftKey = true;
} else if(event.key === "s"){
downKey = true;
} else if(event.key === "d"){
rightKey = true;
}
});
document.addEventListener("keyup", function(event){
if(event.key === "w"){
upKey = false;
} else if(event.key === "a"){
leftKey = false;
} else if(event.key === "s"){
downKey = false;
} else if(event.key === "d"){
rightKey = false;
}
});
}
//Checking to see if player and border intersect
function checkIntersection(r1, r2){
if (r1.x >= r2.x + r2.width){
return false;
} else if (r1.x + r1.width <= r2.x){
return false;
} else if (r1.y >= r2.y + r2.height){
return false;
} else if (r1.y + r1.height <= r2.y){
return false;
} else {
return true;
}
}
播放器 js
function Player(x, y){
//Player variables
this.x = x;
this.y = y;
this.xvel = 0;
this.yvel = 0;
this.friction = 0.6;
this.maxVel = 12;
this.width = tilesize;
this.height = tilesize;
this.active = true;
this.falling = false;
this.step = function(){
if(this.active){
if(!leftKey && !rightKey || leftKey && rightKey){
this.xvel *= this.friction;
} else if (rightKey){
this.xvel++;
} else if (leftKey){
this.xvel--;
}
if(upKey){
//check if standing on ground
if (this.yvel === 0 && this.falling === false){
this.yvel -= 70;
this.falling = true;
} else{
this.yvel += 0;
}
}
this.yvel += 1;
//not allowing velocity to surpass maximum velocity
if (this.xvel > this.maxVel){
this.xvel = this.maxVel;
} else if(this.xvel < -this.maxVel){
this.xvel = -this.maxVel;
}
if (this.yvel > this.maxVel){
this.yvel = this.maxVel;
} else if(this.yvel < -this.maxVel){
this.yvel = -this.maxVel;
}
if (this.xvel > 0){
this.xvel = Math.floor(this.xvel);
} else {
this.xvel = Math.ceil(this.xvel);
}
if (this.yvel > 0){
this.yvel = Math.floor(this.yvel);
} else {
this.yvel = Math.ceil(this.yvel);
}
//collision rectangles
let horizontalRect = {
x: this.x + this.xvel,
y: this.y,
width: this.width,
height: this.height
}
let verticalRect = {
x: this.x,
y: this.y + this.yvel,
width: this.width,
height: this.height
}
//Collision deteQction
for(let i = 0; i<borders.length; i++){
let borderRect = {
x: borders[i].x,
y: borders[i].y,
width: borders[i].width,
height: borders[i].height
}
if (checkIntersection(horizontalRect, borderRect)){
while (checkIntersection(horizontalRect, borderRect)){
horizontalRect.x -= Math.sign(this.xvel);
}
this.x = horizontalRect.x;
this.xvel = 0;
}
if (checkIntersection(verticalRect, borderRect)){
while(checkIntersection(verticalRect, borderRect)){
verticalRect.y -= Math.sign(this.yvel);
}
this.y = verticalRect.y;
this.yvel = 0;
this.falling = false;
}
}
if (this.x + this.xvel > mapWidth*tilesize - tileisze){
this.xvel = 0;
}
if (this.x + this.xvel < 0){
this.xvel = 0;
}
this.x += this.xvel;
this.y += this.yvel;
}
}
this.draw = function(){
context.fillStyle = "orange";
context.fillRect(this.x, this.y, this.width, this.height);
}
}
边框 js
function Border(x, y, width, height, type){
this.x = x;
this.y = y;
this.width = width;
this.height = height;
this.type = type;
this.draw = function(){
if (this.type === 1){
context.fillStyle = "#2C2C34";
} else if (this.type === 2){
context.fillStyle = "#39393A";
}
context.fillRect(this.x, this.y, this.width, this.height);
}
}
您的代码中似乎有几个错误,可能需要一段时间才能全部找到。你的十六进制颜色有 8 个字符 "#f4f4f4f4"
。您的地图宽度为 22,但二维数组中只有 21 列。在创建边界数组时,x
点中有 rows
,y
点中有 col
,这似乎也不对。我觉得应该反过来。无论如何,如果您不反对使用一维数组,这里是您代码的简化版本,没有播放器内容。
边框
function Border(type, x, y){
this.x = x;
this.y = y;
this.width = TILE_SIZE;
this.height = TILE_SIZE;
this.type = type;
this.draw = function(){
if (this.type === 1){
context.fillStyle = "purple";
context.fillRect(this.x, this.y, this.width, this.height);
} else if (this.type === 2){
context.fillStyle = "orange";
context.fillRect(this.x, this.y, this.width, this.height);
}
}
}
和主文件
const canvas = document.getElementById("canvas")
const context = canvas.getContext("2d")
const TILE_SIZE = 25; //50 was too big for my screen based on how many rows/columns you wanted
canvas.width = 525; //TILE_SIZE * columns
canvas.height = 300; //TILE_SIZE * rows
var borders = [];
let tileMap = {
mapHeight: 12,
mapWidth: 21,
size: TILE_SIZE,
grid: [
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 2, 0, 0, 2, 0, 2, 2, 2, 0, 2, 0, 2, 0, 2, 0, 0, 0, 0, 0,
0, 0, 2, 0, 0, 2, 0, 0, 2, 0, 0, 2, 0, 2, 0, 2, 0, 0, 0, 0, 0,
0, 0, 2, 2, 2, 2, 0, 0, 2, 0, 0, 2, 0, 2, 0, 2, 0, 0, 0, 0, 0,
0, 0, 2, 0, 0, 2, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 2, 0, 0, 2, 0, 2, 2, 2, 0, 2, 0, 2, 0, 2, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
]
}
//Uses 1 loop to create the grid
function createGrid() {
for (let i = 0; i < tileMap.grid.length; i++) {
let x = (i % tileMap.mapWidth) * tileMap.size;
let y = Math.floor((i / tileMap.mapWidth)) * tileMap.size;
let type = tileMap.grid[i];
borders.push(new Border(type, x, y));
}
};
createGrid(); //creates the grid when file is loaded
function animate() {
context.clearRect(0, 0, canvas.width, canvas.height);
for(let i = 0; i < borders.length; i++){
borders[i].draw();
}
requestAnimationFrame(animate);
}
animate()
我只是为了这个例子在 animate 函数中插入了 for 循环。通常它会是它自己的功能,您可以在其中处理碰撞检测或绘制图块或您想用它们做的任何其他事情。
如果您必须使用二维数组,这里有一个函数可以创建它
function createGrid() {
for (let row = 0; row < tileMap.mapHeight; row++) {
for (let col = 0; col < tileMap.mapWidth; col++) {
let type = tileMap.grid[row][col];
let x = col * TILE_SIZE;
let y = row * TILE_SIZE;
borders.push(new Border(type, x, y))
}
}
}
createGrid()
如果您使用我上面发布的地图,请务必将地图改回 2d。我还注意到在您的播放器文件中您有一处 tileisze
而不是 tilesize
。我会花一些时间仔细清理您的文件中的错误,因为这些可能是您出现某些问题的原因。