【发布时间】:2021-09-11 08:09:06
【问题描述】:
我制作了一个 javascript tilemap 渲染器,为了渲染单个图块,它从特定偏移量获取 tileatlas 的内容:
ctx.drawImage(this.tileAtlas, tileXIndex, tileYIndex, 16, 16, x, y, this.singleTileSize, this.singleTileSize);
其中 tileIndexX 和 Y 是预先计算的偏移量,但我认为这会减慢我的程序速度,所以我的问题是:是否可以在启动时执行此操作,所以当我将 tileAtlas 初始化为图像时,存储单个瓷砖作为单独的图像?喜欢这个伪代码:
function onStartup(){
tileSprites = [];
for(let i = 0; i < amountOfTiles){
// calculate offsets based off of i
tileSprites.push(tileAtlas.getImageAtOffset(offsetX, offsetY))
}
return tileSprites;
}
或者有什么我缺少的更有效的东西吗?它会减慢我的代码速度吗?
编辑,如果有帮助,这里是完整的渲染代码:
function Layer(w, h){
let t = {};
t.can = document.createElement("canvas");
t.ctx = t.can.getContext("2d");
t.can.width = w;
t.can.height = h;
return t;
}
class Renderer extends MapHandler{
_tileAtlas;
_layers;
singleTileSize;
width;
height;
constructor(){
super();
this.width = innerWidth;
this.height = innerHeight;
this.tileAtlas = new Image();
this.tileAtlas.src = "src/assets/tileatlas.png";
this.singleTileSize = 16;
this._layers = [];
let t = {};
t.can = document.getElementById("GameScreen");
t.ctx = t.can.getContext("2d");
this._layers.push(t);
// Map layer
this._layers.push(new Layer(this.width, this.height));
// Still unused entity sprite layer
this._layers.push(new Layer(this.width, this.height));
this.resetSize();
}
drawTile(ctx, val, x, y){
let tileXIndex = (val % 112) * 16;
let tileYIndex = Math.floor(val / 112);
ctx.drawImage(this.tileAtlas, tileXIndex, tileYIndex, 16, 16, x, y, this.singleTileSize, this.singleTileSize);
}
resetSize(){
let w = innerWidth;
let h = innerHeight;
for(let i in this._layers){
this._layers[i].can.height = h;
this._layers[i].can.width = w;
}
}
renderMap(ctx, map, offsetX, offsetY){
ctx.imageSmoothingEnabled = false;
if(typeof(map)!="object"){console.log("Error rendering map: typeof map isn't 'object'");return;}
for(let y = 0, a = map.length; y < a; y++){
let mapY = Math.round(y * this.singleTileSize + offsetY * this.singleTileSize);
if(mapY<-this.singleTileSize){continue};
if(mapY>this.height){break};
for(let x = 0, aa = map[y].length; x < aa; x++){
let c = map[y][x];
let mapX = Math.round(x * this.singleTileSize + offsetX * this.singleTileSize);
if(mapX<-this.singleTileSize){continue};
if(mapX>this.width){break};
this.drawTile(ctx, c.val, mapX, mapY);
}
}
}
clear(){
for(let i = 0; i < this._layers.length; i++){
this._layers[i].ctx.clearRect(0, 0, this.width, this.height);
}
}
renderToCanvas(){
for(let i = this._layers.length-2; i >= 0; i--){
this._layers[i].ctx.drawImage(this._layers[i+1].can, 0, 0);
}
}
getRenderingContext(layer){
return this._layers[layer].ctx;
}
}
extends MapHandler 部分仅提供当前地图和可用地图列表。此外,赋予 renderMap() 函数的地图是一个二维数组,其中填充了“平铺”对象,代码如下:
function Tile(val){
this.val=val;
}
我认为没那么重要,但实际上里面有对象而不只是图块的单个值这一事实可能很重要,我真的不知道。
再次编辑
我找到了另一种主要加快速度的方法,我突然觉得每帧重绘所有内容是一个非常糟糕的主意,所以我在启动时(在屏幕外画布上)绘制了一张巨大的地图,然后将其渲染到每次都在屏幕上,而不是在所有不同的块中循环。所以,是的,找到答案了哈哈。
【问题讨论】:
标签: javascript rendering