Imitation of three-dimensional camera rotation

I've been exploring the realm of creating 3D games using JavaScript and HTML's 2D canvas. I recently came across a helpful tutorial that guided me in setting up a basic interactive scene.

Now, I'm facing a challenge in implementing the functionality for the player to turn their head, enabling them to look around from side to side and even behind.

Here is a link to my current progress:

Codepen demo

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 navigate

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 into 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 floor
    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() {
    // Update entities
    for(let i = 0; i < entities.length; i++) {
        entities[i].update();
    }
    entities.sort(function(i, i2) {
        return i2.z - i.z;
    })
    // Redraw the 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;

Answer №1

It's important to keep the camera separate from the crates when updating their coordinates in a 3D space. Instead of tying the crate positions directly to the camera movement, let the camera have its own position that gets updated independently. When calculating the 2D space coordinates for rendering, simply subtract the camera position from the crates' positions.

If you want to add rotation capabilities to the camera, you'll need to introduce a rotation matrix along with its position. This will allow you to transform the crate coordinates using the inverse of the camera's rotation matrix before projecting them onto 2D space for display.

There are various methods for creating a rotation matrix based on the parameters available. Popular options include the Rodrigues rotation formula or "axis-angle" formula, as well as Euler angles. If you're new to matrices and linear algebra, it's recommended to familiarize yourself with these concepts, as they are essential in 3D game development.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Omit specific module from a webpack 4 chunk

Is there a way to exclude a specific module from being included in a chunk using webpack 4? For example, let's say I do not want lodash to be included in the vendor file at all costs. How can this be achieved? Here is the current configuration: spli ...

PHP is unable to decode JSON that has been converted from JavaScript

When I send an array as a POST request, I first convert it to JSON using the JSON.stringify() method. However, I encountered an issue when trying to decode it in PHP. // JavaScript var arr1 = ['a', 'b', 'c', 'd', & ...

Guide on setting up a Redirect URL with React Router

I am aiming to trigger a redirect URL event using ReactJS. Is there a way to achieve this? I have already attempted the following: successRedirect(){ this.transitionTo('/'); } as well as successRedirect(){ this.router.transitionTo ...

Javascript - Transforming tabular information into a hierarchical tree structure (JSON)

When extracting JSON data from a table, the format typically resembles the following simplified structure: https://i.sstatic.net/eqfXM.png The JSON format obtained might look like this: const myObjOriginal = { "rows": [{ "name": "row 1", "cell ...

Synchronized scrolling and equal height for multiple divs

Looking to create a system similar to GitHub's conflict resolver for my project. I have multiple versions represented by values in columns, and I want to be able to select different values from each column to create a new solution. It's important ...

What are the reasons behind my item not triggering an alert even after I have created it, saved it, and attempted to alert it?

I am currently working on a code that allows users to input information which is then stored in an object. However, despite my efforts, when I attempt to retrieve the saved object by alerting one of its values, it indicates that the object does not exist. ...

Waiting for data to be passed from a parent component within a method

I have a situation where I need to make an API call in my layout and send the received data as an object to my component. The problem arises because the object is empty when the method is called inside the mounted() function. Therefore, I want to execute ...

Steps to implement an image zoom function triggered by a button click

I'm working on a school project that requires me to use only html, css, and javascript for creating a website. Currently, I'm designing a landing page with a button that will navigate the user to another page. My goal is to have the background im ...

Extract source, medium, etc. data from __utmz GA with the help of JavaScript

Is it possible to retrieve the campaign, source, and medium that Google Analytics records all at once when the page loads? If so, could I use jQuery to look up the values from __utmz? ...

Pass the most recent properties to the mousemove event handler

I am currently developing a click-and-drag feature, which involves: setting up a moveListener on the onMouseDown event having the moveListener trigger an action that updates certain props of the component (props.whichChange) cleaning up the mouseUp event ...

Using AngularJS to Bind HTML Safely: Understanding ngBindHtml and 'unsafe' HTML

I am facing an issue with displaying HTML content containing inline styling in my view. The code I currently have is: <div ng-repeat="snippet in snippets"> <div ng-bind-html="snippet.content"></div> </div> Unfortunately, all of ...

Why is it necessary to call the .call(this) method when extending a THREE.js "class"?

Currently, I am in the process of creating a new object that should inherit from THREE.Object3D(). In my code snippet, you can see how I have set it up: function myNewObject() { THREE.Object3D.call(this); //... } myNewObject.prototype = new THREE.O ...

Ways to resolve the error message "TypeError: 'setOption' is not a function on type 'MutableRefObject' in React"

CODE export default function EChart({ option, config, resize }) { let chart = useRef(null) let [chartEl, setChartEl] = useState(chart) useEffect(() => { if (resize) { chartEl.resize() } if (!chartEl.cu ...

Utilizing React JS to assign various state values from a dropdown menu selection

In my project, I have implemented a dropdown list populated from an array of values. This dropdown is linked to a handleSelect function. const handleSelect = (e) => { handleShow() setCommunityName(e) } <DropdownButton id="dropdown-basi ...

Does Vuejs emit an event when a specific tab becomes active in boostrap-vue?

I am looking for a way to display and hide a section on my page when a specific tab is active, and close it when the tab is inactive. I have tried using the forceOpenSettings and forceCloseSettings methods for opening and closing the div. Is there an event ...

There seems to be a column in the MySQL INSERT query that is unidentifiable and does not exist in the list of fields

id and cost are required as integers and cannot be left empty. I encountered the following error message: 'Error: ER_BAD_FIELD_ERROR: Unknown column 'undefined' in 'field list'' var sql = "INSERT INTO Paintings(` ...

I am looking to have the first option in the dropdown menu appear as a placeholder text

In my form, I have two phone number fields - one for mobile phone and the other for home phone. I need to make only one of them mandatory. Can someone please advise me on how to accomplish this? ...

How do I retrieve the class of an element nested within another element using jQuery?

If we consider a scenario where there is a table named unitTables with various rows, each containing the selected class that we want to retrieve for a variable. This specific table is just one of many similar tables on the webpage. Since other tables also ...

Disposing of memory in THREE JS when switching between routes in VUE

Currently, I am delving into the world of VUE JS and working on a basic SPA that navigates through different pages. In my spare time, I have developed several THREE JS demos which unfortunately tend to slow down and eventually halt when switching between ...

Exploring data elements using iteration in JavaScript

Here is some code that is functioning properly: Morris.Bar({ element: 'barchart', axes: true, data: [ json.bar.bar1 ], xkey: 'x', ykeys: ['y', 'z', ' ...