我想将每个矩形表示为具有宽度和高度的2d矩形。 因此,当您在编辑器中创建地图时,可以绘制2d矩形,并且可以将此创建转换为等距平面。 等距平面的宽度为北向东南(从钻石形状的顶部到右侧。) 高度从北到西南。 (从上到下)
现在我有两个问题。
第一个问题
我在画布上绘制这个等距地图,我正在使用屏幕外画布单独绘制每个平面。我想计算屏幕外画布的2d宽度和高度。我用这个数学来做这个:
var canvasWidth = Math.cos(30) * planeWidth + Math.cos(30) * planeHeight;
var canvasHeight = Math.sin(30) * planeWidth + Math.cos(30) * planeHeight;
// still remember that planeWidth and planeHeight are isometric, so oblique sides
但这并不能为画布提供合适的尺寸。 我想知道的是用像素计算倾斜边是否明智。
第二个问题 我想为飞机使用'纹理'图像。所以,我有像这样的图像:
我的想法是存储每个图像的斜边,就像平面的宽度和高度一样。 当我想绘制具有特定图像的平面时,我可以重复该图像。
主要目标是创建具有像素精确给定宽度和高度的等距平面。平面应该有一个图像作为纹理。图像已经是等距的,因此它们可以像等距瓷砖一样重复和剪裁。
我的问题: 1.我不知道使用斜边作为宽度和高度是明智的,不管怎么说,不管怎样才能找到继续使用2d尺寸的方法?
在屏幕外画布上创建一个2d矩形不是更聪明,并用非等距纹理图像填充它们,然后转换该画布。
如果我使用斜边来表示我的平面和图像的宽度/高度,这些长度是真的吗?它就像一个线性函数:它只是像素。每2个水平,1个垂直。水平方向的奇数,不会给出垂直方向的整数。 (我认为这会给我带来不必要的麻烦)。
答案 0 :(得分:1)
要绘制等轴测平面,请使用变换矩阵设置x和y轴。
假设x轴沿着矢量(1,0.5),y轴沿着矢量(-1,0.5),原点仍然在左上角。
如此定义。
var xAxis = {
x : 1,
y : 0.5,
}
var yAxis = {
x : -1,
y : 0.5,
}
var origin = {
x : 0,
y : 0,
}
设置转换只需使用
ctx.setTransform(xAxis.x, xAxis.y, yAxis.x, yAxis.y, origin.x, origin.y);
现在所有渲染都在等距平面上。
您可以设置所需的等轴投影轴。我使用的那个会增加像素的面积。这将取决于x轴和y轴的长度和相对方向。
<强>更新强>
只是出于兴趣。
由于许多等距投影都倾向于改变每个像素的总面积,因此我已经包含了一个简单的计算,无论使用何种投影,都会对像素区域进行标准化。 (对于我给出的投影恰好是2的平方根上的投影)
使用xAxis
和yAxis
计算该投影的像素区域
var area = (xAxis.x * ( xAxis.y + yAxis.y ) + ( xAxis.x + yAxis.x ) * yAxis.y) - (xAxis.y * ( xAxis.x + yAxis.x ) + ( xAxis.y + yAxis.y ) * yAxis.x)
该区域的平方根上的那个是所需的比例
var scaleBy = 1 / Math.sqrt(area);
您可以直接将其应用于轴......
xAxis.x *= scaleBy;
xAxis.y *= scaleBy;
yAxis.x *= scaleBy;
yAxis.y *= scaleBy;
ctx.setTransform(xAxis.x, xAxis.y, yAxis.x, yAxis.y, origin.x, origin.y);
或者在设置转换
后通过ctx.scale
应用它
ctx.setTransform(xAxis.x, xAxis.y, yAxis.x, yAxis.y, origin.x, origin.y);
ctx.scale(scaleBy, scaleBy);
示例强>
演示显示了此方法的简单应用(没有像素规范化)。
var canvas = document.createElement("canvas");
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
canvas.style.position = "absolute";
canvas.style.left = "0px";
canvas.style.top = "0px";
document.body.appendChild(canvas);
function demo(){
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
var ctx = canvas.getContext("2d");
ctx.font = "80px arial black";
ctx.lineWidth = 8;
ctx.lineJoin = "round"
ctx.strokeStyle = "green";
ctx.fillStyle = "#aF6";
ctx.textAlign = "center";
ctx.textBaseline = "middle";
// the axis and origin
var xAxis = {x : 1, y: 0.5};
var yAxis = {x : -1, y: 0.5};
var origin = {x : 0, y : 0};
// cludge factor dividing by two to fit the display area
ctx.setTransform(xAxis.x / 2, xAxis.y / 2, yAxis.x / 2, yAxis.y / 2, origin.x, origin.y);
// draw big text
ctx.strokeText("Isometric",ctx.canvas.width/2,0);
ctx.fillText("Isometric",ctx.canvas.width/2,0);
// half size text
ctx.font = "40px arial black";
ctx.lineWidth = "4";
ctx.strokeText("projection",ctx.canvas.width/2,60);
ctx.fillText("projection",ctx.canvas.width/2,60);
// tiny text
ctx.font = "16px arial black";
ctx.lineWidth = "3";
ctx.strokeText("using 2D context transformation",ctx.canvas.width/2,100);
ctx.fillText("using 2D context transformation",ctx.canvas.width/2,100);
// add an image to demonstrate that the project will be applied to
// anything that is rendered.
var image = new Image();
image.src = "https://i.stack.imgur.com/C7qq2.png?s=328&g=1";
image.addEventListener("load",function(){
ctx.drawImage(this,ctx.canvas.width-this.width,-this.height * 1.2);
});
}
demo();
window.addEventListener("resize",demo);