- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我在 WebGL(html 和 javascript)中创建了一个简单的动画,其中 2D 形状在 Canvas 上进行动画处理和操作。默认动画是形状以设定速度向右移动,然后使用“WASD”更改其方向。即使形状离开 Canvas 并超出剪辑空间,形状也会无限期地沿给定方向移动。我想让形状环绕 Canvas ,而不是在看不见它之后继续。例如,如果形状向右移动并完全移出 Canvas ,我希望它出现在左侧,但仍向右移动并继续循环。如果向左、向上或向下移动,情况也是如此。
关于如何实现这一点有什么建议吗?
最佳答案
你必须绘制它 2 到 4 次,具体取决于你是否想同时包裹左/右和上/下
假设我们只想水平环绕。如果玩家靠近左边缘,我们还需要将玩家 1 屏幕宽度向右绘制。如果玩家靠近右边缘,我们需要将玩家再次向左绘制一屏。与上、下相同
这是一个使用 canvas 2D 的示例,但 WebGL 的唯一区别是您可以使用 WebGL 进行绘制。概念是一样的。
示例:
var x = 150;
var y = 100;
var vx = 0;
var vy = 0;
const maxSpeed = 250;
const acceleration = 1000;
const ctx = document.querySelector("canvas").getContext("2d");
const keys = {};
const LEFT = 65;
const RIGHT = 68;
const DOWN = 83;
const UP = 87;
const width = ctx.canvas.width;
const height = ctx.canvas.height;
var then = 0;
function render(now) {
now *= 0.001; // seconds
const deltaTime = now - then;
then = now;
ctx.clearRect(0, 0, width, height);
if (keys[UP]) { vy -= acceleration * deltaTime; }
if (keys[DOWN]) { vy += acceleration * deltaTime; }
if (keys[LEFT]) { vx -= acceleration * deltaTime; }
if (keys[RIGHT]) { vx += acceleration * deltaTime; }
// keep speed under max
vx = absmin(vx, maxSpeed);
vy = absmin(vy, maxSpeed);
// move based on velociy
x += vx * deltaTime;
y += vy * deltaTime;
// wrap
x = euclideanModulo(x, width);
y = euclideanModulo(y, height);
// draw player 4 times
const xoff = x < width / 2 ? width : -width;
const yoff = y < height / 2 ? height : -height;
drawPlayer(x, y);
drawPlayer(x + xoff, y);
drawPlayer(x, y + yoff);
drawPlayer(x + xoff, y + yoff);
requestAnimationFrame(render);
}
requestAnimationFrame(render);
function drawPlayer(x, y) {
ctx.fillStyle = "blue";
ctx.strokeStyle = "red";
ctx.lineWidth = 4;
ctx.beginPath();
ctx.arc(x, y, 20, 0, Math.PI * 2, false);
ctx.fill();
ctx.stroke();
}
function absmin(v, max) {
return Math.min(Math.abs(v), max) * Math.sign(v);
}
function euclideanModulo(n, m) {
return ((n % m) + m) % m;
}
window.addEventListener('keydown', e => {
keys[e.keyCode] = true;
});
window.addEventListener('keyup', e => {
keys[e.keyCode] = false;
});
canvas {
display: block;
border: 1px solid black;
}
<canvas></canvas>
<p><span style="color:red;">click here</span> then use ASWD to move</p>
WebGL 版本没有更改与包装相关的代码。
var x = 150;
var y = 100;
var vx = 0;
var vy = 0;
const maxSpeed = 250;
const acceleration = 1000;
const gl = document.querySelector("canvas").getContext("webgl");
const keys = {};
const LEFT = 65;
const RIGHT = 68;
const DOWN = 83;
const UP = 87;
const width = gl.canvas.width;
const height = gl.canvas.height;
var program = setupWebGL();
var positionLoc = gl.getAttribLocation(program, "position");
var then = 0;
function render(now) {
now *= 0.001; // seconds
const deltaTime = now - then;
then = now;
if (keys[UP]) { vy -= acceleration * deltaTime; }
if (keys[DOWN]) { vy += acceleration * deltaTime; }
if (keys[LEFT]) { vx -= acceleration * deltaTime; }
if (keys[RIGHT]) { vx += acceleration * deltaTime; }
// keep speed under max
vx = absmin(vx, maxSpeed);
vy = absmin(vy, maxSpeed);
// move based on velociy
x += vx * deltaTime;
y += vy * deltaTime;
// wrap
x = euclideanModulo(x, width);
y = euclideanModulo(y, height);
// draw player 4 times
const xoff = x < width / 2 ? width : -width;
const yoff = y < height / 2 ? height : -height;
drawPlayer(x, y);
drawPlayer(x + xoff, y);
drawPlayer(x, y + yoff);
drawPlayer(x + xoff, y + yoff);
requestAnimationFrame(render);
}
requestAnimationFrame(render);
function drawPlayer(x, y) {
gl.useProgram(program);
// only drawing a single point so no need to use a buffer
gl.vertexAttrib2f(
positionLoc,
x / width * 2 - 1,
y / height * -2 + 1);
gl.drawArrays(gl.POINTS, 0, 1);
}
function absmin(v, max) {
return Math.min(Math.abs(v), max) * Math.sign(v);
}
function euclideanModulo(n, m) {
return ((n % m) + m) % m;
}
window.addEventListener('keydown', e => {
keys[e.keyCode] = true;
});
window.addEventListener('keyup', e => {
keys[e.keyCode] = false;
});
function setupWebGL() {
const vs = `
attribute vec4 position;
void main() {
gl_Position = position;
gl_PointSize = 40.;
}
`;
const fs = `
void main() {
gl_FragColor = vec4(1,0,1,1);
}
`;
// compiles and links shaders and assigns position to location 0
return twgl.createProgramFromSources(gl, [vs, fs]);
}
canvas {
display: block;
border: 1px solid black;
}
<canvas></canvas>
<p><span style="color:red;">click here</span> then use ASWD to move</p>
<script src="https://twgljs.org/dist/3.x/twgl-full.min.js"></script>
如果您不希望玩家出现在两侧,那么您的问题与图形无关,您只需等到玩家的 x 位置至少为 screenWidth + haflPlayerWidth
即可。这意味着它们完全偏离右侧,然后您将它们的 x 位置设置为 -halfPlayerWidth
这将使它们位于左侧,反之亦然
var x = 150;
var y = 100;
var vx = 0;
var vy = 0;
const maxSpeed = 250;
const acceleration = 1000;
const ctx = document.querySelector("canvas").getContext("2d");
const keys = {};
const LEFT = 65;
const RIGHT = 68;
const DOWN = 83;
const UP = 87;
const width = ctx.canvas.width;
const height = ctx.canvas.height;
const playerSize = 40;
const halfPlayerSize = playerSize / 2;
var then = 0;
function render(now) {
now *= 0.001; // seconds
const deltaTime = now - then;
then = now;
ctx.clearRect(0, 0, width, height);
if (keys[UP]) { vy -= acceleration * deltaTime; }
if (keys[DOWN]) { vy += acceleration * deltaTime; }
if (keys[LEFT]) { vx -= acceleration * deltaTime; }
if (keys[RIGHT]) { vx += acceleration * deltaTime; }
// keep speed under max
vx = absmin(vx, maxSpeed);
vy = absmin(vy, maxSpeed);
// move based on velociy
x += vx * deltaTime;
y += vy * deltaTime;
// wrap
x = euclideanModulo(x + halfPlayerSize, width + playerSize) - halfPlayerSize;
y = euclideanModulo(y + halfPlayerSize, height + playerSize) - halfPlayerSize;
// draw player
drawPlayer(x, y);
requestAnimationFrame(render);
}
requestAnimationFrame(render);
function drawPlayer(x, y) {
ctx.fillStyle = "blue";
ctx.strokeStyle = "red";
ctx.lineWidth = 4;
ctx.beginPath();
ctx.arc(x, y, halfPlayerSize, 0, Math.PI * 2, false);
ctx.fill();
ctx.stroke();
}
function absmin(v, max) {
return Math.min(Math.abs(v), max) * Math.sign(v);
}
function euclideanModulo(n, m) {
return ((n % m) + m) % m;
}
window.addEventListener('keydown', e => {
keys[e.keyCode] = true;
});
window.addEventListener('keyup', e => {
keys[e.keyCode] = false;
});
canvas {
display: block;
border: 1px solid black;
}
<canvas></canvas>
<p><span style="color:red;">click here</span> then use ASWD to move</p>
这段代码可能需要解释
x = euclideanModulo(x + haflPlayerSize, width + playerSize) - haflPlayerSize;
y = euclideanModulo(y + haflPlayerSize, height + playerSize) - haflPlayerSize;
首先euclideanModulo
就像正常的 %
模运算符,它返回除法后的余数,但欧几里得模即使对于负数也保持相同的余数。换句话说
3 % 5 = 3
8 % 5 = 3
13 % 5 = 3
-2 % 5 = -2
-7 % 5 = -2
-12 % 5 = -2
但是
3 euclideanMod 5 = 3
8 euclideanMod 5 = 3
13 euclideanMod 5 = 3
-2 euclideanMod 5 = 3
-7 euclideanMod 5 = 3
-12 euclideanMod 5 = 3
所以这是一种非常简单的包装方式。
x = euclideanModulo(x, screenWidth)
类似于
if (x < 0) x += screenWidth;
if (x >= screenWidth) x -= screenWidth;
除非如果 x > screenWidth * 2
则会失败例如,使用 euclideanModulo 的人不会。
所以,回到
x = euclideanModulo(x + haflPlayerSize, width + playerSize) - haflPlayerSize;
y = euclideanModulo(y + haflPlayerSize, height + playerSize) - haflPlayerSize;
我们知道玩家(在本例中是一个圆圈)的位置位于其中心。因此,我们知道当它的中心距离屏幕左侧或右侧玩家大小的一半时,它就完全离开屏幕,因此我们希望将其移动到另一侧。这意味着我们可以想象屏幕实际上是 width + halfPlayerSize + halfPlayerSize
宽的。第一个halfPlayerSize
是为了从左侧迈出,第二个halfPlayerSize
是为了从右侧迈出。换句话说,它只是 width + playerSize
宽的。然后,我们希望播放器在 x < -halfPlayerSize
时从左到右换行。 。所以我们添加halfPlayerSize
到玩家的位置,然后执行 euclideanModulo 来包裹该位置,然后减去 halfPlayerSize。
关于javascript - 如何使用 WebGL 让 2D 形状环绕 Canvas ?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42291249/
关闭。这个问题需要debugging details .它目前不接受答案。 编辑问题以包含 desired behavior, a specific problem or error, and th
我试图用这种形式简单地获取数字 28 integer+space+integer+integer+space+integer我试过这个正则表达式 \\s\\d\\d\\s 但我得到了两个数字11 和
最近一直在学习D语言。我一直对运行时感到困惑。 从我能收集到的关于它的信息中,(这不是很多)我知道它是一种有助于 D 的一些特性的运行时。像垃圾收集一样,它与您自己的程序一起运行。但是既然 D 是编译
想问一下这两个正则表达式有区别吗? \d\d\d 与 \d{3} 我已经在我的本地机器上使用 Java 和 Windows 操作系统对此进行了测试,两者都工作正常并且结果相同。但是,当在 linux
我正在学习 Go,而且我坚持使用 Go 之旅(exercise-stringer.go:https://tour.golang.org/methods/7)。 这是一些代码: type IPAddr
我在Java正则表达式中发现了一段令我困惑的代码: Pattern.compile( "J.*\\d[0-35-9]-\\d\\d-\\d\\d" ); 要编译的字符串是: String string
我在 ruby 代码上偶然发现了这个。我知道\d{4})\/(\d\d)\/(\d\d)\/(.*)/是什么意思,但是\1-\2-\3-\4 是什么意思? 最佳答案 \1-\2-\3-\4 是 b
我一直在努力解决这个问题,这让我很恼火。我了解 D 运行时库。它是什么,它做什么。我也明白你可以在没有它的情况下编译 D 应用程序。就像 XoMB 所做的那样。好吧,XoMB 定义了自己的运行时,但是
我有两个列表列表,子列表代表路径。我想找到所有路径。 List> pathList1 List> pathList2 当然是天真的解决方案: List> result = new ArrayList>
我需要使用 Regex 格式化一个字符串,该字符串包含数字、字母 a-z 和 A-Z,同时还包含破折号和空格。 从用户输入我有02-219 8 53 24 输出应该是022 198 53 24 我正在
目标是达到与this C++ example相同的效果: 避免创建临时文件。我曾尝试将 C++ 示例翻译为 D,但没有成功。我也尝试过不同的方法。 import std.datetime : benc
tl;dr:你好吗perfect forwarding在 D? 该链接有一个很好的解释,但例如,假设我有这个方法: void foo(T)(in int a, out int b, ref int c
有什么方法可以在 D 中使用abstract auto 函数吗? 如果我声明一个类如下: class MyClass { abstract auto foo(); } 我收到以下错误: mai
有没有人为内存中重叠的数组切片实现交集?算法在没有重叠时返回 []。 当 pretty-print (使用重叠缩进)内存中重叠的数组切片时,我想要这个。 最佳答案 如果您确定它们是数组,那么只需取 p
我已经开始学习 D,但我在使用 Andrei Alexandrescu 所著的 The D Programming Language 一书中提供的示例时遇到了一些麻烦。由于 int 和 ulong 类
如何创建一个不可变的类? 我的目标是创建一个实例始终不可变的类。现在我只是用不可变的方法和构造函数创建了一个“可变”类。我将其称为 mData,m 表示可变。然后我创建一个别名 alias immut
不久前我买了《The D Programming Language》。好书,很有教育意义。但是,我在尝试编译书中列出的语言功能时遇到了麻烦:扩展函数。 在这本书中,Andrei 写了任何可以像这样调用
我在 D http://www.digitalmars.com/d/2.0/lazy-evaluation.html 中找到了函数参数的惰性求值示例 我想知道如何在 D 中实现可能的无限数据结构,就像
这个问题在这里已经有了答案: 12 年前关闭。 Possible Duplicate: Could anyone explain these undefined behaviors (i = i++
当前是否可以跨模块扫描/查询/迭代具有某些属性的所有函数(或类)? 例如: source/packageA/something.d: @sillyWalk(10) void doSomething()
我是一名优秀的程序员,十分优秀!