伪 3D 相机转动
pseudo 3D camera turning
我正在尝试学习使用 HTML 2D canvas 在 JavaScript 中制作 3D 游戏。我一直在关注 this post 并制作了一个简单的场景,您可以在其中四处移动。
我需要帮助的是弄清楚如何让玩家转头、左右看和背后看的效果。
这是我的:
代码(也在 codepen 上)
html:
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>3d test</title>
</head>
<body>
<canvas id="canv"></canvas>
</body>
</html>
javascript
//use arrow keys to move around
var canvas = document.getElementById("canv");
var c = canvas.getContext("2d");
canvas.width = canvas.height = 800;
var crateImg = new Image();
class Entity {
constructor(x, y, z, w, h) {
this.x = x;
this.y = y;
this.z = z;
this.w = w;
this.h = h;
this.rx = 0;
this.ry = 0;
this.rs = 0;
}
render() {
//c.fillStyle = 'red';
//c.fillRect(this.rx, this.ry, this.rs*this.w, this.rs*this.h);
c.drawImage(crateImg, this.rx, this.ry, this.rs*this.w, this.rs*this.h);
}
update() {
//project to 3d
this.rs = 400/(400+this.z);
this.rx = ((this.x*this.rs) + 400);
this.ry = (this.y*this.rs) + 400;
//move
this.x += camera.xSpeed;
this.y += camera.ySpeed;
this.z += camera.zSpeed;
}
}
var camera = {
xSpeed: 0,
ySpeed: 0,
zSpeed: 0,
}
var entities = [];
function random(min, max) {
return Math.floor(Math.random() * (max - min) + min);
}
window.onload = function() {
start();
update();
}
function start() {
crateImg.src = "https://i.imgur.com/O9ForWS_d.webp?maxwidth=760&fidelity=grand";
for(let i = 0; i < 100; i++) {
entities.push(new Entity(random(-800, 800), 0, i*10, 50, 50));
}
}
function render() {
//fill background
c.fillStyle = 'skyblue';
c.fillRect(0, 0, 800, 800);
//draw flooor
c.fillStyle = 'green';
c.fillRect(0, 400, 800, 400);
//draw entities
for(let i = 0; i < entities.length; i++) {
if(entities[i].z > -400) {
entities[i].render();
}
}
}
function update() {
//updatre entities
for(let i = 0; i < entities.length; i++) {
entities[i].update();
}
entities.sort(function(i, i2) {
return i2.z - i.z;
})
//redraw current frame
render();
requestAnimationFrame(update);
}
function keyDown(e) {
switch(e.keyCode) {
case 39:
camera.xSpeed = -5;
break;
case 37:
camera.xSpeed = 5;
break;
case 38:
camera.zSpeed = -5;
break;
case 40:
camera.zSpeed = 5;
break;
}
}
function keyUp(e) {
switch(e.keyCode) {
case 39:
case 37:
camera.xSpeed = 0;
break;
case 38:
case 40:
camera.zSpeed = 0;
break;
}
}
document.onkeydown = keyDown;
document.onkeyup = keyUp;
首先,您不应该根据相机的移动来更新板条箱的坐标。相反,让相机在 3D space 中有自己的位置,当您希望玩家移动时更新该位置,然后在计算 2D space 坐标时从板条箱的位置减去相机位置。这将使您以后想要添加时变得容易得多,例如,相机旋转或板条箱本身移动的能力。
现在要为相机添加旋转功能,除了位置之外,您还需要为其定义一个旋转矩阵。然后,在渲染板条箱时,您使用相机旋转矩阵的逆矩阵来转换板条箱坐标(在减去相机的位置之后)。这将为您提供板条箱的视图 space 坐标,应将其投影到 2D space 上进行渲染。
创建旋转矩阵的方法有很多种,具体取决于您拥有的参数。一个常见的是 Rodrigues rotation formula or "axis-angle" formula, which is used when you have an axis of rotation and an angle to rotate about that axis. Another one is from Euler angles。如果您不熟悉矩阵和线性代数,我建议您学习它(网上有很多免费资源),因为它广泛用于 3D 游戏开发。
我正在尝试学习使用 HTML 2D canvas 在 JavaScript 中制作 3D 游戏。我一直在关注 this post 并制作了一个简单的场景,您可以在其中四处移动。
我需要帮助的是弄清楚如何让玩家转头、左右看和背后看的效果。
这是我的:
代码(也在 codepen 上)
html:
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>3d test</title>
</head>
<body>
<canvas id="canv"></canvas>
</body>
</html>
javascript
//use arrow keys to move around
var canvas = document.getElementById("canv");
var c = canvas.getContext("2d");
canvas.width = canvas.height = 800;
var crateImg = new Image();
class Entity {
constructor(x, y, z, w, h) {
this.x = x;
this.y = y;
this.z = z;
this.w = w;
this.h = h;
this.rx = 0;
this.ry = 0;
this.rs = 0;
}
render() {
//c.fillStyle = 'red';
//c.fillRect(this.rx, this.ry, this.rs*this.w, this.rs*this.h);
c.drawImage(crateImg, this.rx, this.ry, this.rs*this.w, this.rs*this.h);
}
update() {
//project to 3d
this.rs = 400/(400+this.z);
this.rx = ((this.x*this.rs) + 400);
this.ry = (this.y*this.rs) + 400;
//move
this.x += camera.xSpeed;
this.y += camera.ySpeed;
this.z += camera.zSpeed;
}
}
var camera = {
xSpeed: 0,
ySpeed: 0,
zSpeed: 0,
}
var entities = [];
function random(min, max) {
return Math.floor(Math.random() * (max - min) + min);
}
window.onload = function() {
start();
update();
}
function start() {
crateImg.src = "https://i.imgur.com/O9ForWS_d.webp?maxwidth=760&fidelity=grand";
for(let i = 0; i < 100; i++) {
entities.push(new Entity(random(-800, 800), 0, i*10, 50, 50));
}
}
function render() {
//fill background
c.fillStyle = 'skyblue';
c.fillRect(0, 0, 800, 800);
//draw flooor
c.fillStyle = 'green';
c.fillRect(0, 400, 800, 400);
//draw entities
for(let i = 0; i < entities.length; i++) {
if(entities[i].z > -400) {
entities[i].render();
}
}
}
function update() {
//updatre entities
for(let i = 0; i < entities.length; i++) {
entities[i].update();
}
entities.sort(function(i, i2) {
return i2.z - i.z;
})
//redraw current frame
render();
requestAnimationFrame(update);
}
function keyDown(e) {
switch(e.keyCode) {
case 39:
camera.xSpeed = -5;
break;
case 37:
camera.xSpeed = 5;
break;
case 38:
camera.zSpeed = -5;
break;
case 40:
camera.zSpeed = 5;
break;
}
}
function keyUp(e) {
switch(e.keyCode) {
case 39:
case 37:
camera.xSpeed = 0;
break;
case 38:
case 40:
camera.zSpeed = 0;
break;
}
}
document.onkeydown = keyDown;
document.onkeyup = keyUp;
首先,您不应该根据相机的移动来更新板条箱的坐标。相反,让相机在 3D space 中有自己的位置,当您希望玩家移动时更新该位置,然后在计算 2D space 坐标时从板条箱的位置减去相机位置。这将使您以后想要添加时变得容易得多,例如,相机旋转或板条箱本身移动的能力。
现在要为相机添加旋转功能,除了位置之外,您还需要为其定义一个旋转矩阵。然后,在渲染板条箱时,您使用相机旋转矩阵的逆矩阵来转换板条箱坐标(在减去相机的位置之后)。这将为您提供板条箱的视图 space 坐标,应将其投影到 2D space 上进行渲染。
创建旋转矩阵的方法有很多种,具体取决于您拥有的参数。一个常见的是 Rodrigues rotation formula or "axis-angle" formula, which is used when you have an axis of rotation and an angle to rotate about that axis. Another one is from Euler angles。如果您不熟悉矩阵和线性代数,我建议您学习它(网上有很多免费资源),因为它广泛用于 3D 游戏开发。