gpt4 book ai didi

javascript - 带有偏移量的 Canvas createPattern() 和 fill()

转载 作者:行者123 更新时间:2023-12-02 21:19:21 25 4
gpt4 key购买 nike

我使用 Canvas 绘制简单的矩形并用地板图案 (PNG) 填充它们。但是,如果我利用“相机”脚本来处理 HTML5 Canvas 的变换偏移,则矩形形状会适当移动,但填充图案似乎总是从屏幕上的固定点绘制(我假设在左上角)。有没有一种方法可以“确定”填充图案,使其始终与矩形对齐,无论 Canvas 变换如何,或者有一种方法可以在 fill() 上添加可以在代码中其他地方计算的偏移量?当然,我可以只使用drawImage(),但是绘制矩形对于我的目的来说更通用。

        sampleDrawFunction(fillTexture, x1, y1, x2, y2) {
// This is oversimplified, but best I can do with a ~10k lines of code
x1 -= Camera.posX;
x2 -= Camera.posX;
y1 = -1 * y1 - Camera.posY;
y2 = -1 * y2 - Camera.posY;

// Coordinates need to be adjusted for where the camera is positioned

var img = new Image();
img.src = fillTexture;
var pattern = this.ctx.createPattern(img, "repeat");
this.ctx.fillStyle = pattern;

// Translate canvas's coordinate pattern to match what the camera sees
this.ctx.save();
this.ctx.translate(Camera.posX - Camera.topLeftX, Camera.posY - Camera.topLeftY);
this.ctx.fillStyle = pattern;
this.ctx.fillRect(x1, y1, x2 - x1, y2 - y1);
this.ctx.restore();
}

谢谢。

最佳答案

Canvas 填充(CanvasPatterns 和 CanvasGradients)始终与上下文的变换矩阵相关,因此它们确实默认位于 Canvas 的左上角,并且并不真正关心使用它们的路径在哪里。

const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
const img = new Image();
img.onload = begin; //!\ ALWAYS WAIT FOR YOUR IMAGE TO LOAD BEFORE DOING ANYTHING WITH IT!
img.crossOrigin = "anonymous";
img.src = "https://upload.wikimedia.org/wikipedia/commons/4/47/PNG_transparency_demonstration_1.png";

function begin() {
const rect_size = 20;
ctx.fillStyle = ctx.createPattern( img, 'no-repeat' );
// drawing a checkerboard of several rects shows that the pattern doesn't move
for ( let y = 0; y < canvas.height; y += rect_size ) {
for ( let x = (y / rect_size % 2) ? rect_size : 0 ; x < canvas.width; x += rect_size * 2 ) {
ctx.fillRect( x, y, rect_size, rect_size );
}
}

}
<canvas id="canvas" width="500" height="500"></canvas>

现在,因为它们与上下文变换矩阵相关,这意味着我们还可以通过更改该变换矩阵来移动它们:

const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
const img = new Image();
img.onload = begin; //!\ ALWAYS WAIT FOR YOUR IMAGE TO LOAD BEFORE DOING ANYTHING WITH IT!
img.crossOrigin = "anonymous";
img.src = "https://upload.wikimedia.org/wikipedia/commons/f/f7/Cool_bunny_sprite.png";


function begin() {
const rect_size = 244;
const max_speed = 5;
let x_speed = Math.random() * max_speed;
let y_speed = Math.random() * max_speed;

ctx.fillStyle = ctx.createPattern( img, 'repeat' );

let x = 0;
let y = 0;
requestAnimationFrame( anim );

function anim( now ) {

clear();

x = (x + x_speed);
y = (y + y_speed);

if( x > canvas.width || x < -rect_size ) {
x_speed = Math.random() * max_speed * -Math.sign( x_speed );
x = Math.min( Math.max( x, -rect_size ), canvas.width );
}
if( y > canvas.height || y < -rect_size ) {
y_speed = Math.random() * max_speed * -Math.sign( y_speed )
y = Math.min( Math.max( y, -rect_size ), canvas.height );
}

// we change the transformation matrix of our context
ctx.setTransform( 1, 0, 0, 1, x, y );
// we thus always draw at coords 0,0
ctx.fillRect( 0, 0, rect_size, rect_size );
ctx.strokeRect( 0, 0, rect_size, rect_size );

requestAnimationFrame( anim );

}
function clear() {
// since we changed the tranform matrix we need to reset it to identity
ctx.setTransform( 1, 0, 0, 1, 0, 0 );
ctx.clearRect( 0, 0, canvas.width, canvas.height );

}
}
<canvas id="canvas" width="300" height="300"></canvas>

我们甚至可以通过在声明子路径后更改转换矩阵来将路径声明与填充分离,当然还可以通过替换简写 fillRect()beginPath(); rect(); fill()

const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
const img = new Image();
img.onload = begin; //!\ ALWAYS WAIT FOR YOUR IMAGE TO LOAD BEFORE DOING ANYTHING WITH IT!
img.crossOrigin = "anonymous";
img.src = "https://upload.wikimedia.org/wikipedia/commons/f/f7/Cool_bunny_sprite.png";


function begin() {
const rect_size = 244;
const max_speed = 5;
let x_speed = Math.random() * max_speed;
let y_speed = Math.random() * max_speed;

ctx.fillStyle = ctx.createPattern( img, 'repeat' );

let x = 0;
let y = 0;
requestAnimationFrame( anim );

function anim( now ) {

clear();

x = (x + x_speed);
y = (y + y_speed);

if( x > canvas.width || x < -rect_size ) {
x_speed = Math.random() * max_speed * -Math.sign( x_speed );
x = Math.min( Math.max( x, -rect_size ), canvas.width );
}
if( y > canvas.height || y < -rect_size ) {
y_speed = Math.random() * max_speed * -Math.sign( y_speed )
y = Math.min( Math.max( y, -rect_size ), canvas.height );
}

// we declare the sub-path first, with identity matrix applied
ctx.beginPath();
ctx.rect( 50, 50, rect_size, rect_size );
// we change the transformation matrix of our context
ctx.setTransform( 1, 0, 0, 1, x, y );
// and now we fill
ctx.fill();
ctx.stroke();

requestAnimationFrame( anim );

}
function clear() {
// since we changed the tranform matrix we need to reset it to identity
ctx.setTransform( 1, 0, 0, 1, 0, 0 );
ctx.clearRect( 0, 0, canvas.width, canvas.height );

}
}
<canvas id="canvas" width="300" height="300"></canvas>

但就你的情况而言,听起来改变整个绘图是最简单、最惯用的方法。不太确定为什么要修改相对于相机的 x 和 y 坐标。一般来说,如果我们使用相机对象,那么场景中的对象不必关心它,并且与世界保持相对关系。

关于javascript - 带有偏移量的 Canvas createPattern() 和 fill(),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60893667/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com