如何解决不绘制所有瓷砖的Javascript 2d tilemap
我正在用 JavaScript 创建一个 2D 平台游戏。我正在尝试创建一个 tilemap,它不会在应该有空气的块中生成(在 tilemap 中标记为 0)。我没有收到任何错误。但是,画布中不会生成任何块。除非我取消碰撞检测,否则游戏也会崩溃。
主要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,[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,tilemap[row][col]));
}
}
}
//initialize main game loop. Framerate = 30/sec
gameLoop = setInterval(step,1000/30);
//draw canvas
context.fillStyle = "#f4f4f4f4"
context.fillRect(0,mapWidth*tilesize,mapHeight*tilesize);
}
function step(){
player.step();
//draw after updates
draw();
}
function draw(){
//Clear previous canvas
context.fillStyle = "#f4f4f4f4"
context.fillRect(0,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,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.height);
}
}
解决方法
您的代码中似乎有几个错误,可能需要一段时间才能找到所有错误。您的十六进制颜色有 8 个字符 "#f4f4f4f4"
。您的地图宽度为 22,但二维数组中只有 21 列。当您创建边界数组时,rows
位置的 x
和 col
位置的 y
似乎也是错误的。我好像应该反过来。无论如何,如果你不反对使用一维数组,这里是你的代码的简化版本,没有播放器的东西。
边框
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.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,2,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,y));
}
};
createGrid(); //creates the grid when file is loaded
function animate() {
context.clearRect(0,canvas.width,canvas.height);
for(let i = 0; i < borders.length; i++){
borders[i].draw();
}
requestAnimationFrame(animate);
}
animate()
我仅在此示例中将 for 循环插入到 animate 函数中。通常它会是它自己的功能,在那里你可以处理碰撞检测或绘制瓦片或任何你想用它们做的事情。
如果你必须使用二维数组,这里有一个函数可以创建它
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,y))
}
}
}
createGrid()
如果您使用我上面发布的地图,请务必将地图改回 2d。我还注意到在您的播放器文件中,您有一次使用 tileisze
而不是 tilesize
。我会花一些时间仔细检查您的文件中是否有错误,因为这些可能是导致您出现某些问题的原因。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。