Possible Inconsistencies with the LookAt Feature in Three.js

Attempting to use the lookAt function to make zombies move towards the character has been a challenge. The problem lies in the fact that they are not turning correctly but at odd angles. Here is the code snippet I tried:

var pos = new THREE.Vector3(self.position.x - player.x, self.position.y, self.position.z - player.z) self.lookAt(pos)

I suspect the issue may be related to obtaining the relative position of the player, but I am unsure how to achieve this.

Another attempt was made with the code:

lookAt(Player)

Unfortunately, this approach also failed to produce the desired result: view error screenshot

Answer №1

If both the zombies and the player are not parented to anything, you can utilize this code:

zombieMesh.lookAt(playerMesh.position);

It's important to note that the lookAt function aligns the positive Z axis of the model towards the target.

'use strict';  // eslint-disable-line

/* global THREE, document, requestAnimationFrame  */

function main() {
  const canvas = document.querySelector('#c');
  const renderer = new THREE.WebGLRenderer({canvas: canvas});

  const fov = 60;
  const aspect = 2;  // the canvas default
  const zNear = 0.1;
  const zFar = 1000;
  const camera = new THREE.PerspectiveCamera(fov, aspect, zNear, zFar);
  camera.position.set(14, 8, 6);
  camera.lookAt(-2, -2, 0);

  const scene = new THREE.Scene();

  {
    const light = new THREE.DirectionalLight(0xffffff, 1);
    light.position.set(0, 20, 0);
    scene.add(light);
  }

  {
    const light = new THREE.DirectionalLight(0xffffff, 1);
    light.position.set(1, 2, 4);
    scene.add(light);
  }

  const groundGeometry = new THREE.PlaneBufferGeometry(50, 50);
  const groundMaterial = new THREE.MeshPhongMaterial({color: 0xCC8866});
  const groundMesh = new THREE.Mesh(groundGeometry, groundMaterial);
  groundMesh.rotation.x = Math.PI * -.5;
  groundMesh.receiveShadow = true;
  scene.add(groundMesh);
  
  const zombieGeo = new THREE.ConeBufferGeometry(1, 1, 6);
  zombieGeo.applyMatrix(new THREE.Matrix4().makeRotationX(Math.PI * 0.5));
  const zombieMat = new THREE.MeshPhongMaterial({color: 'green', flatShading: true});
  const zombieMeshes = [];
  function makeZombie(x, z) {
    const zombieMesh = new THREE.Mesh(zombieGeo, zombieMat);
    scene.add(zombieMesh);
    zombieMesh.position.set(x, 1, z);
    zombieMeshes.push(zombieMesh);
  }
    
  for (let v = -5; v <= 5; v += 5) {
    makeZombie(v, -10);
    makeZombie(v,  10);
    makeZombie(-5, v);
    makeZombie( 5, v);
  }
  
  const playerGeo = new THREE.SphereBufferGeometry(1, 6, 4);
  const playerMat = new THREE.MeshPhongMaterial({color: 'red', flatShading: true});
  const playerMesh = new THREE.Mesh(playerGeo, playerMat);
  scene.add(playerMesh);
    
  function resizeRendererToDisplaySize(renderer) {
    const canvas = renderer.domElement;
    const width = canvas.clientWidth;
    const height = canvas.clientHeight;
    const needResize = canvas.width !== width || canvas.height !== height;
    if (needResize) {
      renderer.setSize(width, height, false);
    }
    return needResize;
  }

  function render(time) {
    time *= 0.001;

    if (resizeRendererToDisplaySize(renderer)) {
      const canvas = renderer.domElement;
      camera.aspect = canvas.clientWidth / canvas.clientHeight;
      camera.updateProjectionMatrix();
    }
    
    playerMesh.position.set(Math.sin(time) * 6, 1, Math.cos(time) * 6);

    for (const zombieMesh of zombieMeshes) {
      zombieMesh.lookAt(playerMesh.position);
    }

    renderer.render(scene, camera);

    requestAnimationFrame(render);
  }

  requestAnimationFrame(render);
}

main();
body { margin: 0; }
canvas { width: 100vw; height: 100vh; display: block; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/99/three.min.js"></script>
<canvas id="c"></canvas>

Answer №2

From what I can tell, this game appears to be in first person perspective. To address this, there's a clever workaround that you might find useful...

function UpdateZombieDirection(o){
    console.log("The camera has been repositioned");
    zombie.lookAt(camera.position);
    console.log("The zombie has now been oriented towards you");
}

controls.addEventListener('change', UpdateZombieDirection);

Essentially, due to the fact that you're always seeing things through the camera, the zombies can easily follow your line of sight. This function alters the zombie's position based on the camera's movement, with the event listener keeping track of any changes.

Although there's no specific code provided, ensure that your lookAt commands are properly linked to the object. I've experienced issues with that in the past...

Answer №3

If you utilize the lookAt function in ThreeJS, it handles the calculations automatically based on the objects' positions. However, your current code is not working because you are attempting to calculate the direction around the object instead of where it should be looking.

To simplify your code, just use:

self.lookAt(player);

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

The Vue/Nuxt application displays content duplication on each page, rendering the content twice without duplicating the components

I recently delved into Vue/Nuxt programming and worked through a tutorial on adding a blog, which I then customized for my website. Everything functions perfectly except that the content is rendering twice. It goes from rendering NavPage (component) > c ...

Tips to center a circular progress bar in Material UI

Does anyone know how to properly center-align a circular progress bar in a login form using material UI? I'm having trouble with it not being positioned correctly: screenshot {isLoading && <CircularProgress />} {user?.ema ...

What is the optimal placement for promises in Angular: Factory or Controller?

In my application, I have a basic factory to manage API calls. Currently, the structure looks like this: .factory('apiFactory', function($http){ var url = 'http://192.168.22.8:8001/api/v1/'; return { getReports: function() { ...

Unable to access 'this' within a custom operator in RxJs

I developed a unique operator that utilizes the this keyword, but I am encountering an issue where it always returns undefined. Even though I used bind to pass this into the function. My special operator function shouldLoadNewOptimizationData() { retu ...

Tips for ensuring sequential execution of $.post requests without ajax alternative

Can I make synchronous requests with $.post in this code snippet? function loadTest() { var questionIDs = []; var count = 0; console.log("getting test"); $.post("db.php", function(data) { obj = jQuery.parseJSON(data); var questionCount = obj.l ...

Running npm commands from the root directory while the package.json file is located elsewhere

Although I understand that it's not ideal, I am faced with a specific directory structure that cannot be changed: [projectRootDir] [src] [tests] [otherDirs] [configuration] package.json mocha.opts other files.. ...

Resize a div within another div using overflow scroll and centering techniques

Currently, I am working on implementing a small feature but am facing difficulties with the scroll functionality. My goal is to zoom in on a specific div by scaling it using CSS: transform: scale(X,Y) The issue I am encountering lies in determining the c ...

Tips for defining a function without an arrow as a parameter

Understand that there may be individuals quick to flag this as a duplicate question, but trust me when I say that I have exhaustively searched on Google for almost an hour before turning to ask here. methods: { stylizeHeader: debounce(event => { ...

Enhancing Kendo Grid with Checkbox Columns

I am facing a situation with my kendo grid where I need to insert two checkbox columns in addition to the existing set of columns. <script id="sectionPage" type="text/kendo-tmpl"> @(Html.Kendo().Grid<SectionPageModel>() .Na ...

Retrieving data from the database into a DIV using ajax

Here is the code snippet I am using to retrieve values from my database at regular intervals: <script type="text/javascript"> $(document).ready(function(){ var j = jQuery.noConflict(); j(document).ready(function() { j(".refreshMe ...

When I receive a 404 response from the API, I aim to start my observable

How can I trigger my observable initialization when receiving a 404 response from the API? The code snippet below is not working as expected. const urlParams = { email: this.email }; this.voicesProfileObservable$ = this.service.request<any>( AVAI ...

Socket IO: Error - The call stack has exceeded the maximum size limit

Whenever a client connects to my node.js server, it crashes with a 'RangeError: Maximum call stack size exceeded' error. I suspect there's a recursive problem somewhere in my code that I can't seem to find. This is the code on my serve ...

How can I use ngx-editor to insert an HTML block at the current cursor position by clicking a button?

I am currently using ngx-editor within Angular 7. My goal is to insert HTML at the cursor's position upon clicking on parameters from a list. The current view displays how the parameter is appended when clicked, as shown in the image attached https:// ...

What is the reason for findUser.username returning as unidentified?

I am encountering an issue where the findUser.username is being printed in my console.log, but the error persists. I would appreciate some assistance with this problem. Thank you. const auth_user = [ { username: "amylussie", password: ...

The next-auth/discord callbacks do not make any changes to the data

Currently, I am utilizing the next-auth/discord and facing an issue with the session callback not setting the user id to the session property as expected. [...nextauth].js import NextAuth from "next-auth/next"; import DiscordProvider from " ...

Executing JavaScript code within an AJAX request

Having a problem with an AJAX function that I need help solving: PAGE A represents the main page. PAGE X represents the content loaded via AJAX. RES A represents the results from PAGE A. RES B represents the new results loaded via AJAX. PAGE A initially ...

Understanding how to properly handle the data sent by an ajax request in a NodeJS server

I currently have an array called passedWord = ['a', 'bbb']. I am then making an AJAX request to send this array to a Node.js server. Upon receiving the array on the server, Body Parser returns the following object: { name: 'abc&ap ...

Can different versions of Node be used simultaneously for various Node scripts?

Currently, I am utilizing nvm. Can a specific node version be used for a particular script? For instance... Using node 6 forever start -a -l $MYPATH/forever.log -e $MYPATH/err.log -c "node --max_old_space_size=20" $MYPATH/script_with_node_version_6.js U ...

Mobile Devices and Local Storage: What You Need to Know for Safe and Efficient Use. Looking for advice from experienced developers

Need help with caching user input on an Angular11 + Firebase app? Let's discuss implementing a caching feature for a dynamic form section that can contain varying fields based on the use case. The goal is to save user input in LocalStorage to ensure ...

Error: The "toString" property of an undefined variable cannot be read in uploadify

I'm having trouble with uploadify and trying to debug the issue. When attempting to use uploadify in Chrome, I encounter the following error: Uncaught TypeError: Cannot read property 'toString' of undefined Below is my html code: <li ...