-1

我正在尝试学习使用 HTML 2D 画布在 JavaScript 中制作 3D 游戏。我正在关注这篇关于它的帖子,并制作了一个简单的场景,您可以在其中移动。

我需要帮助的是弄清楚如何制作玩家转过头、左右看和身后的效果。

这是我所拥有的:

代码笔链接

代码(也在 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&amp;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;
4

1 回答 1

0

首先,您不应该根据相机的移动来更新箱子的坐标。相反,让相机在 3D 空间中拥有自己的位置,当您希望玩家移动时更新该位置,然后在计算 2D 空间坐标时从箱子的位置中减去相机位置。当您以后想要添加例如相机旋转或板条箱本身移动的能力时,这将使事情变得更加容易。

现在要为相机添加旋转功能,除了位置之外,您还需要为它定义一个旋转矩阵。然后,在渲染 crate 时,使用相机旋转矩阵的倒数变换 crate 坐标(在减去相机的位置之后)。这将为您提供 crates 的视图空间坐标,该坐标应投影到 2D 空间进行渲染。

根据您拥有的参数,有很多方法可以创建旋转矩阵。一个常见的是Rodrigues 旋转公式或“轴角”公式,当您有一个旋转轴和一个围绕该轴旋转的角度时使用。另一个是欧拉角。如果您不熟悉矩阵和线性代数,我建议您学习它(网上有很多免费资源),因为它广泛用于 3D 游戏开发。

于 2021-06-14T02:20:08.633 回答