Creating a dynamic sliding feature in Three.js: A step-by-step guide

Recently, I came across three.js and fell in love with it. I managed to create a rotating car animation controlled by keyboard arrows, but now I'm facing a challenge in creating a sliding animation (similar to -> -> ->) instead of a rotation animation. I've tried searching for solutions, but I struggle to articulate the concept other than calling it a sliding animation. Does anyone have any ideas on how to achieve this effect?

Below is the code for my current project:

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <title>ThreeJS Animation</title>
        <style>            
            body {
              margin: 0;
              font-weight: 100;
              float: none;
              overflow: hidden;
            }
            canvas {
              width: 100%;
              height: 100%;
              margin: 0;
              padding: 0;
            }
        </style>
    </head>
    <body>
        <script src="https://threejs.org/build/three.js"></script>
        <script>
// JavaScript code goes here
        </script>
    </body>
</html>

Answer №1

I've taken some liberties with the assumptions, but it seems like you're aiming to rotate the car around the y-axis by using the left/right arrow keys and move it forward by using the up/down arrow keys. If this is correct, you can achieve this by calling car.translateX() to control forward/backward motion and car.rotation.y to handle the car turning.

Here's an updated example:

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <title>ThreeJS Animation</title>
        <style>            
            body {
              margin: 0;
              font-weight: 100;
              float: none;
              overflow: hidden;
            }
            canvas {
              width: 100%;
              height: 100%;
              margin: 0;
              padding: 0;
            }
        </style>
    </head>
    <body>
        <script src="https://threejs.org/build/three.js"></script>
        <script>
let carBottomColor = "#999";
let carTopColor = "#FFF";
let carWindowColor = "#666";
const scene = new THREE.Scene();
scene.background = new THREE.Color("#f1f1f1");
const car = createCar();
scene.add(car);

const ambientLight = new THREE.AmbientLight(0xffffff, 0.6);
scene.add(ambientLight);

const dirLight = new THREE.DirectionalLight(0xffffff, 0.8);
dirLight.position.set(200, 500, 300);
scene.add(dirLight);

const aspectRatio = window.innerWidth / window.innerHeight;
const cameraWidth = 300;
const cameraHeight = cameraWidth / aspectRatio;
const camera = new THREE.OrthographicCamera(
  cameraWidth / -2, // left
  cameraWidth / 2, // right
  cameraHeight / 2, // top
  cameraHeight / -2, // bottom
  200, // near plane
  800 // far plane
);
camera.position.set(200, 200, 200);
camera.lookAt(0, 10, 0);
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.render(scene, camera);

let x = 0;
let y = 0;
let keydown = '';
document.body.addEventListener('keydown', e => {
  e.preventDefault();
  keydown = e.key;
});
document.body.addEventListener('keyup', e => {
  keydown = '';
});
const update = () => {
    switch (keydown) {
    case 'ArrowUp':
      car.translateX(1.0);
      break;
    case 'ArrowDown':
      car.translateX(-1.0);
      break;
    case 'ArrowLeft':
      y += 0.1;
      car.rotation.y = y;
      break;
    case 'ArrowRight':
      y -= 0.1;
      car.rotation.y = y;
      break;
  }
  window.requestAnimationFrame(update);
}
window.requestAnimationFrame(update);


renderer.setAnimationLoop(() => {
  renderer.render(scene, camera);
});

document.body.appendChild(renderer.domElement);

function createCar() {
  const car = new THREE.Group();
  const backWheel = createWheels();
  backWheel.position.y = 6;
  backWheel.position.x = -18;
  car.add(backWheel);

  const frontWheel = createWheels();
  frontWheel.position.y = 6;
  frontWheel.position.x = 18;
  car.add(frontWheel);

  const main = new THREE.Mesh(
    new THREE.BoxGeometry(60, 15, 30),
    new THREE.MeshLambertMaterial({ color: carBottomColor })
  );
  main.position.y = 12;
  car.add(main);

  const carFrontTexture = getCarFrontTexture();

  const carBackTexture = getCarFrontTexture();

  const carRightSideTexture = getCarSideTexture();

  const carLeftSideTexture = getCarSideTexture();
  carLeftSideTexture.center = new THREE.Vector2(0.5, 0.5);
  carLeftSideTexture.rotation = Math.PI;
  carLeftSideTexture.flipY = false;

  const cabin = new THREE.Mesh(new THREE.BoxGeometry(33, 12, 24), [
    new THREE.MeshLambertMaterial({ map: carFrontTexture }),
    new THREE.MeshLambertMaterial({ map: carBackTexture }),
    new THREE.MeshLambertMaterial({ color: carTopColor }), // top
    new THREE.MeshLambertMaterial({ color: carTopColor }), // bottom
    new THREE.MeshLambertMaterial({ map: carRightSideTexture }),
    new THREE.MeshLambertMaterial({ map: carLeftSideTexture })
  ]);
  cabin.position.x = -6;
  cabin.position.y = 25.5;
  car.add(cabin);
  return car;
}

function createWheels() {
  const geometry = new THREE.BoxGeometry(12, 12, 33);
  const material = new THREE.MeshLambertMaterial({ color: "#333" });
  const wheel = new THREE.Mesh(geometry, material);
  return wheel;
}

function getCarFrontTexture() {
  const canvas = document.createElement("canvas");
  canvas.width = 64;
  canvas.height = 32;
  const context = canvas.getContext("2d");

  context.fillStyle = "#ffffff";
  context.fillRect(0, 0, 64, 32);

  context.fillStyle = carWindowColor || carBaseColor; 
  context.fillRect(8, 8, 48, 24);

  return new THREE.CanvasTexture(canvas);
}

function getCarSideTexture() {
  const canvas = document.createElement("canvas");
  canvas.width = 128;
  canvas.height = 32;
  const context = canvas.getContext("2d");

  context.fillStyle = "#ffffff";
  context.fillRect(0, 0, 128, 32);

  context.fillStyle = carWindowColor || carBaseColor; 
  context.fillRect(10, 8, 38, 24);
  context.fillRect(58, 8, 60, 24);

  return new THREE.CanvasTexture(canvas);
}
        </script>
    </body>
</html>

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

Live updates are shown in a format similar to a friend feed or the top tweets on Twitter

I'm currently utilizing PubSubHubbub to obtain the latest updates from the feed. Once the callback URL receives an update, it should be displayed on the webpage in a format similar to Friend Feed or Twitter's top tweets (with content moving down ...

Energetic flair for Vue animations

I am currently developing a VueJS sidebar component. The objective is to allow the parent to define a width and display a toggle button that smoothly slides the sidebar in and out. Here is an example: <template> <div class="sidebarContainer ...

Vue project missing required NPM dependency

Everything was going smoothly with my Vue project. However, when I changed the file name of one component, I encountered an error. After fixing the code, I restarted the npm server by running npn run serve. That's when the following errors popped up: ...

How does the position of the scroll affect the height of an element on a webpage

Currently, I'm exploring the 'scroll' eventlistener in web development to incorporate some motion design elements into my projects. For this particular experiment, I am making a div element react to the user's scrolling actions on the p ...

Exploring the concept of JavaScript Variablesqueries

I need help understanding why the results are different in these three examples related to JavaScript. Case 1. var x = 5 + 2 + 3; document.getElementById("demo").innerHTML = x; Result: 10 Case 2. var x = 5 + 2 + "3"; document.getElementById("demo").in ...

Utilize state objects and child components by accessing sub-values within the object

I have a Dropzone component where multiple uploads can happen simultaneously and I want to display the progress of each upload. Within my Dropzone component, there is a state array called uploads: const [uploads, setUploads] = useState([]) Each element i ...

Adjust the color of radio button text with Jquery

Here is a sample of radio buttons: <input type='radio' name='ans' value='0'> Apple <input type='radio' name='ans' value='1'> Banana <input type='radio' name='ans&apo ...

Instantly refreshing the Angular DOM following data modifications and retrieval from the database

I am currently working on a Single Page Application that uses Angular 8 for the frontend and Laravel for the backend. This application is a CRUD (Create, Read, Update, Delete) system. The delete functionality is working as expected, deleting users with spe ...

smoothly slides into view and playfully bounces

http://jsfiddle.net/E6cUF/ The concept involves a grey box sliding left from behind a green box after the page is fully loaded, with a slight bouncing effect if possible. Update: I created a new version inspired by modifications made by others on the jsf ...

Steps on how to trigger an onmouseover event for entire blocks of text:

I'm currently in search of an onmouseover code that seems to be elusive on the vast internet. A CSS box format has been successfully created: .box { float: left; width: 740px; height: 300px; margin-left: 10px; margin-top: 10px; padding: 5px; border: ...

Sum values in project pipeline based on conditions with Mongo

I am currently implementing a project pipeline that involves filtering values greater than 100 from fields within an object that is part of an array. Here's an example of the database structure: Database: ---Clients Collection--- client: { _id: ...

The functionality of OBJLoader has ceased to function properly following the implementation of revision

Recently, I encountered an issue while working with the objloader feature of the three.js library to display a cube in a web browser. Everything was working perfectly until I updated to revision 55 from git. Since then, I have been unable to render the c ...

Canvas renderer creating a gradient with three.js

Is it possible to achieve a linear gradient using vertexColors on a material when utilizing the webgl renderer? I read that this method is not compatible with the canvas renderer. How can I create a gradient using the canvas renderer as a fallback option ...

Guide to sending checkbox data using jQuery AJAX

I am facing an issue with submitting the form below: <form action="/someurl" method="post"> <input type="hidden" name="token" value="7mLw36HxPTlt4gapxLUKWOpe1GsqA0I5"> <input type="checkbox" class="mychoice" name="name" value="appl ...

Acquire information from a Card using Oracle Apex

I have a Card Regions that showcases some of my tables. I'd like each card to redirect to a specific page based on a number (the "page_table" number corresponds to the page it will redirect to). Below is the Query for the Cards Region: SELECT table_n ...

Tips for making a dynamic active button using javascript

I'm trying to create a toggle button with eight buttons. When seven out of the toggle buttons are clicked, it should toggle between two classes and change its CSS styles. If the daily button is clicked, it should toggle the styles of the other seven b ...

Transferring information to a view using ExpressJS and Reactjs

I have created an application that requires users to log in with Twitter credentials. Once logged in successfully, I typically pass the user data to the template using the following code: app.get('/', function(req, res, next) { log("The ...

Difficulty with CasperJS multi-select functionality

I am currently attempting to utilize CasperJS for choosing both options in a multiple select within an HTML form: <select id="bldgs" name="bldgs" multiple="multiple" size="6" autocomplete="off"> <option value="249759290">Southeast Financia ...

Searching the JSON file by its value using Waterline

I am struggling with locating model instances based on the nested address attribute in one of my models. attributes: { address: { type: 'json' } } I have attempted various queries to find model instances located in the same city: Model ...

Unusual behavior observed when routing onScroll in Next.js, with rendering occurring exclusively on the server side

In my attempt to leverage Next.js imperative routing api within a scroll handler for page navigation, I encountered an almost perfect solution by attaching it to the window. However, there is a slight color 'flash' as the scroll position resets w ...