包装精灵
您提供的有趣链接。他们已经实现了完整的 CPU 仿真并运行了用汇编编写的游戏。
改进模数
无论如何,如果您使用画布来渲染精灵(图像),最简单的方法是使用简单的模数进行修改以处理负值。
使用负值时,正常的模数会失效。
x = 100 % 200; // 100
x = 300 % 200; // 100
x = -100 % 200; // -100 the wrong sign should be 100
x = -50 % 200; // -50 wrong sign wrong direction should be 150
您需要模数始终以正确的方向返回正值。要处理负数,请进行两次模运算,第一次将在您想要的范围内,但在 +/- 范围内。然后通过添加范围使负正。然后再做一次模数。
var range = 200;
var x = 150;
x = ((x % range) + range) % range; // result 150
x = -50;
x = ((x % range) + range) % range; // result 150 correct.
简单包装
使用上面的模算法,检查边界并根据需要渲染精灵是一件简单的事情。
// assuming ctx is canvas context 2D
// canvas is the canvas.
// img is a HTMLImageElement
var canW = canvas.width; // the canvas size
var canH = canvas.height;
// draw a sprite that is wrapped around the edges of the canvas
function drawWrappedSprite(img,x,y){
x1 = ((x % canW) + canW) % canW; // wrap around correcting for negative values
y1 = ((y % canH) + canH) % canH;
x2 = x1 + img.width; // get right and bottom
y2 = y1 + img.height;
ctx.drawImage(img, x1, y1); // draw first copy
if(x2 > canW){ // check if touching right side
ctx.drawImage(img, x1 - canW, y1); // draw left copy
if(y2 > canH){ // check if touching bottom
ctx.drawImage(img, x1 - canW, y1 - canH); // draw top copy
}
}
if(y2 > canH){
ctx.drawImage(img, x1 , y1 - canH); // draw top copy
}
}
包装旋转的精灵
由于游戏中有旋转的精灵,上述功能将不起作用,因为旋转会改变精灵的大小。要处理旋转的精灵,您需要检查它的最大尺寸。这是精灵对角线的长度,可以通过sqrt(width * width + height * height)找到
假设您希望精灵围绕其中心旋转,您可以通过在 x,y 中心位置减去和添加一半对角线来找到精灵最大范围(顶部、底部、左侧和右侧)。就像第一个函数一样,根据需要进行取模并绘制精灵。
在某些情况下,即使不可见,也会在另一侧绘制精灵。如果您正在绘制大量精灵(100+),您可能想要获得确切的范围而不是最大范围,但是您必须至少转换精灵的一个角以获得水平和垂直范围。然后只使用这些值而不是函数中的diag。
// assuming ctx is canvas context 2D
// canvas is the canvas.
// img is a HTMLImageElement
var canW = canvas.width; // the canvas size
var canH = canvas.height;
// draws sprite rotated about its center by r
function drawWrappedRotatedSprite(img,x,y,r){ // x,y center pos, r rotation in radians
var diag = Math.sqrt(img.width * img.width + img.height * img.height); // get diagonal size
diag /= 2; // half the diagonal
x1 = (((x - diag) % canW) + canW) % canW; // get left extent position and
y1 = (((y - diag) % canH) + canH) % canH; // wrap around correcting for negative values
var w = - img.width / 2; // get image width height
var h = - img.height / 2 // offset in rotated space
x2 = x1 + diag * 2; // get right and bottom max extent
y2 = y1 + diag * 2;
ctx.setTransform(1,0,0,1,x1 + diag, y1 + diag); // set origin
ctx.rotate(r); // set rotation
ctx.drawImage(img, w, h); // draw image rotated around its center
if(x2 > canW){ // check if touching right side
ctx.setTransform(1,0,0,1,x1 + diag - canW, y1 + diag); // set origin
ctx.rotate(r); // set rotation
ctx.drawImage(img,w,h); // draw image rotated around its center
if(y2 > canH){ // check if touching bottom
ctx.setTransform(1,0,0,1,x1 + diag - canW, y1 + diag - canH); // set origin
ctx.rotate(r); // set rotation
ctx.drawImage(img,w,h); // draw image rotated around its center
}
}
if(y2 > canH){
ctx.setTransform(1,0,0,1,x1 + diag, y1 + diag - canH); // set origin
ctx.rotate(r); // set rotation
ctx.drawImage(img,w,h); // draw top image rotated around its center
}
ctx.setTransform(1,0,0,1,0,0); // reset the transform (should only do this after all sprites
// using this function have been drawn
}