Improving basic collision detection using velocity-based 2D motion

Check out this CodePen demo where you can control the movement of the "player" square using arrow keys. You can also place a light by pressing the spacebar and the player is supposed to be prevented from crossing over the blue lines by getting pushed in the opposite direction. The movement of the "player" is controlled by x and y velocity variables, which are multiplied by -1 (plus some value) if a collision is detected. However, there seems to be an issue where the player gets stuck in a position where they can only move backward from the wall, appearing to be stuck on a perpendicular axis. For instance, if the wall is above the player, they can only move downwards and not left or right after hitting the wall. I am looking to implement a smooth sliding collision detection mechanism where the player, when stuck at the wall, would slowly slide down the left or right side depending on whether the left or right arrow key is pressed. While I have been able to achieve this to some extent, there is always one direction that flows more smoothly, resulting in the player sliding down in a particular direction. I have considered using rays or other methods to detect hits, but they seem to require more computational time compared to a simple approach. I would appreciate any suggestions or recommendations on how to build a scalable collision detection system.

let xVelocity = 0;
let yVelocity = 0;
var blockedMapGrid = [[0,30],[0,50],[0,100],[0,150],[0,200],[0,250],
                     [50,0],[100,0],[150,0],[200,0],[250,0],[300,0]];


var animate = function() {

if (keyState[37]) {
    xVelocity -= 1;
}
if (keyState[38]) {
    yVelocity += 1;
}
if (keyState[39]) {
    xVelocity += 1;
}
if (keyState[40]) {
    yVelocity -= 1;
}

 for (var i = 0; i < blockedMapGrid.length; i++) {
     if (Math.abs(player.position.x - blockedMapGrid[i][0]) + 
     Math.abs(player.position.y - blockedMapGrid[i][1]) < 36) {
        xVelocity = -xVelocity * 1.2;
        yVelocity = -yVelocity * 1.2;
        console.log("Blocked by " + blockedMapGrid[i][0])
    };
}

player.position.x = player.position.x + xVelocity;
player.position.y = player.position.y + yVelocity;
yVelocity *= 0.80;
xVelocity *= 0.80;
camera.position.x = player.position.x;
camera.position.y = player.position.y;

requestAnimationFrame(animate);
renderer.render(scene, camera);
};

Answer №1

This is not quite right in your detector:

Math.abs(player.position.x - blockedMapGrid[i][0]) + 
   Math.abs(player.position.y - blockedMapGrid[i][1]) < 36

Basically, instead of calculating the distance from the player to a point on the grid using the square root of the sum of squares, you are using absolute values added together here. In reality, you don't need such a complicated grid setup or distance calculation.

It seems like you are implementing Axis-Aligned Bounding Box (AABB) detection. There are many tutorials and guides on the internet on how to optimize this.

A general approach would look something like this. Your grid array should contain boxes with measurements of (x,y,w,h). These boxes can be various shapes such as thin, long, square, etc. Let's assume your player also has a bounding box

(player.x, player.y, player.w, player.h)
, then

for (var i = 0; i < grid.length; i++) {
   if (player.x            < grid[i].x + grid[i].w && 
       player.x + player.w > grid[i].x             &&
       player.y            < grid[i].y + grid[i].h && 
       player.y + player.h > grid[i].y) {
   //collision detected! move player back to previous position
    break;
  }
}

There are different actions you can take when a collision is detected, but the key is to check for overlap between two boxes using the 4 conditions above.

Update

Another issue that can arise from the code in question is "bouncing" or "getting stuck" after a collision is detected.

It is important not to simply reverse the velocity with velocity = -velocity after a collision without ensuring that the character moves back to a clear space where there is no overlap with obstacles. Otherwise, you may end up in an infinite loop where the velocity bounces back and forth without the character being able to move away from the obstacle.

To remedy this, calculate the player's new position in temporary variables first, check if the new position does not collide, and only then update the position and call render(). If the new position results in a collision, ignore the movement and render the player without changing position.

Another approach is to store the last known "safe" position and only allow the character to move back to that position after resolving the collision, possibly through an animation or series of uncontrollable movements.

There are more advanced techniques that involve physics simulation to allow the character to bounce off multiple obstacles, assuming that the control inputs do not override inertia – think of a car on a slippery road or a boat hitting multiple trees. Regardless, after detecting a collision and before calling "render()", ensure that the character is placed in a physically feasible position to avoid getting "stuck in textures".

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

Using Angular's ng-switch directive within a select dropdown option

Can we implement the [Data Presentation Format] to be utilized in the [Dropdown Box]? Specifically, I would like the "parent" items to appear as is within the dropdown, while the "child" items should have a [tab] indentation to denote their relationship wi ...

Utilizing AJAX to dynamically update a div's content by extracting a specific div from the retrieved data

Although I believe my code is correct, I am not very familiar with AJAX and have been struggling for hours to get it right. I've tried various approaches, including using filters, but nothing seems to work. The issue I'm facing is that the chat m ...

Passing PHP Variables Between Pages

I'm currently working on building a game using html5(phaser js) and I need to create a leaderboard. Here's the code snippet I have: restart_game: function() { // Start the 'main' state, which restarts the game //this.game.time.events ...

Set the cookie to expire in 5 minutes using PHP, JavaScript, or jQuery

Is there a way to set a cookie in PHP that expires in 5 minutes? I am comfortable with the setcookie() function, but unsure about how to set the expiration time. Any explanation would be greatly appreciated. Could someone please guide me on how to achieve ...

Arrange the HTML DOM elements in the order of their appearance in a list

Is it possible to rearrange the order of <div> and its elements based on database information? For example, consider the following HTML structure: <div id="container"> <div id="A"> Form elements for A</div> <div id="B"& ...

I am having trouble getting the color, metalness, lights, and shaders to work properly in Three JS on my

I attempted to create a simple code using Three.js for a red colored torus with a point light and a textured surface, but unfortunately, all I achieved was a black torus that rotates. It seems like the elements in this code are not functioning as expecte ...

Eliminate unnecessary transparency in React Material UI Tooltip / Popper by adjusting opacity restrictions

Looking to integrate the Tooltip component from the React Material UI Library into my project. The code snippet I am using is as follows: <WhiteOnDarkGreyTooltipWithControls disableTouchListener disableFocusListener title={ <Text selectable ...

The Javascript Date constructor struggles to interpret date strings in certain timezones that are not enclosed in brackets

Take a look at the examples below: new Date("Wed, 28 May 2014 09:50:06 EEST"); // Invalid Date new Date("Thu, 26 Jun 2014 09:09:27 EDT"); // OK, is parsed new Date("Wed, 28 May 2014 09:50:06 (EEST)"); // OK, is parsed new Date("Thu, 26 Jun 2014 09:09:27 ( ...

Is there a problem with the way divs are being displayed when using jQuery to show the first 12 elements with the class "hide-show"?

I am encountering a problem with displaying data using the jQuery slice() and show() methods to reveal dynamically generated divs from a PHP function. The code is as follows: <style> .hide-show { display :none; } </style> <div class="c ...

Testing Angular services by injecting dependencies

I'm currently working on test driven development for an angular service using Jasmine. However, I've encountered an issue with resolving the $resource dependency, which is causing a stumbling block at the beginning of my process. The specific er ...

Failure to display masonry arrangement

I am working on creating a stunning masonry layout for my webpage using some beautiful images. Take a look at the code snippet below: CSS <style> .masonryImage{float:left;} </style> JavaScript <script src="ht ...

What are the steps to utilize the .find() method to search for documents in a database that belong to the current user

My back-end code for the 'get' request to my '/logs' collection returns data in an array labeled "times": router.get('/', (req, res) => { time .find({'userName': req.params.userName}) .exec() .then(times => ...

Modifying an @Input element within a component does not result in any changes being reflected in the parent component

Here is the scenario with my component: @Component({ selector: 'child' }) export class ChildComponent { @Input() childObject: ChildObject; changeObject(newObject: ChildObject){ childObject = newObject; } } After calling ...

Can Angular components be used to replace a segment of a string?

Looking to integrate a tag system in Angular similar to Instagram or Twitter. Unsure of the correct approach for this task. Consider a string like: Hello #xyz how are you doing?. I aim to replace #xyz with <tag-component [input]="xyz">&l ...

Tips for making a bookmark for your iframe content

Within this HTML code, there is a list element with the ID "about_ma" and an iframe named "page" that is initially hidden. <div id="navigation"> <ul id="nav"> <li id="about_ma"><a href="index1.php?name=about.php">Ab ...

Which specific event in NextJS is triggered only during the initial load?

I am working on a NextJS app and I want to implement an initial loading screen that only appears during the first load. Currently, the loading screen pops up not only on the initial load but also whenever a link is clicked that directs the user back to the ...

Experiencing inconsistent click-detection with raycasting on 3D objects within Mapbox

Using raycaster in mapbox with 3d-objects, I am trying to detect clicks on the objects. However, I am experiencing inconsistent results - sometimes receiving an empty raycaster.intersectObject array and other times a filled array. Ideally, I should always ...

Accessing the parent div in an Ajax success function

I am looking for a solution to hide a parent div when a link is clicked and an ajax call is successfully made. I have tried placing the hide() function within the success part of the ajax call, but it seems to not work: $('.mylink').click(functi ...

Is it possible to apply styles to javascript elements without relying on img class? Additionally, how can I incorporate an onclick button while maintaining a fully functional navigation bar?

My current project involves creating an interactive collage where users can click around and have pictures pop up at the clicked location. The functionality works as intended, but now I'm facing issues with the navigation bar not being clickable. Addi ...

"Implementing an AngularJS factory that returns a State object instead of typical JSON data fetched from

I have created two factories and I am calling the first one from the second one in my controller. However, instead of receiving JSON data, I am getting data as $$State. I am new to AngularJS and have tried multiple solutions but have not been able to resol ...