4
\$\begingroup\$

How do you guys think I can improve the code for collision detection on my website asteroidfield.eu5.org? The current code is

var dx = Math.abs(c1.getcx() - c2.getcx());
var dy = Math.abs(c1.getcy() - c2.getcy());
var dist = Math.sqrt((dx * dx) + (dy * dy));
if (dist - (c1.getR() + c2.getR()) <= 0) {
  if (done === false && invinc !== true) {
    game_over = true;
    done = true;
  }
}

C1 refers to the player sprite, and C2 is the enemy sprite. Getcx is essentially collecting the X location of the edge of what is essentially a collision detection circle, and gety does the same, but collects the Y location. GetR returns the radius of the collision detection circle.

\$\endgroup\$
1
  • \$\begingroup\$ Was it running too slowly? How fast you detect a collision between two objects is not as important as being able to deal with thousands of them. In your case you do not have too many of the asteroids. By the way, there are some UI usability improvements that you can look into - the menu for selecting difficulty and a spaceship was not very intuitive (hard to find) and clunky. In professional games the implementation may be harder but the menus are slicker - you get all the info you want on screen, and you can often cycle through options with <=, => or other keys. Difficulty can be a combo box \$\endgroup\$
    – Leonid
    May 21, 2013 at 19:38

2 Answers 2

3
\$\begingroup\$

One thing you can improve on is the getting of the absolute value. In some browsers, bitwise absolute is faster than Math.abs. But it depends on the browser's implementation.

//bitwise absolute
function abs(n){
  return (n^(n>>31))-(n>>31);
}

You could also factor this part out into a variable for readability. The result of this is a boolean. The explanation will be in the next part:

//foo true if less than or equal to 0, false if greater
var foo = dist - (c1.getR() + c2.getR()) <= 0; 

Also, in this bit of code, since done and invinc are boolean, there's no point comparing them to true and false. You can use them directly in the condition.

if (done === false && invinc !== true) //when false, and not true (false)

if (!done && !invinc)                  //when not true (false) and not true (false)

In JS, assignment operations "spill left". You can do the following, assigning true to done and "spill" the same value over to game_over.

game_over = done = true;

Also, due to the structure of the code, the previous only happens when our condition assigned to foo is less than or equal to zero or true. So let's modify the condition to this:

if(foo && !done && !invinc) game_over = done = true;

So in the end, your code will look like this:

var dx = Math.abs(c1.getcx() - c2.getcx());
var dy = Math.abs(c1.getcy() - c2.getcy());
var dist = Math.sqrt((dx * dx) + (dy * dy));
var foo = dist - (c1.getR() + c2.getR()) <= 0;

if (foo && !done && !invinc) game_over = done = true;
\$\endgroup\$
6
  • \$\begingroup\$ Thank you for you help, but that didn't really improve the accuracy. I updated the original post with context. The full JS file is also available here: asteroidfield.eu5.org/_js/main.js \$\endgroup\$ May 21, 2013 at 18:26
  • \$\begingroup\$ @user2350334, what is wrong with the accuracy? This site is mainly for improving something that already works. Your problem might be with a timer or with modeling the bounding box of a spacecraft. \$\endgroup\$
    – Leonid
    May 21, 2013 at 19:40
  • \$\begingroup\$ @Leonid I am trying to improve the collision detect function-it works fine currently, but as I previously mentioned, it basically uses two collision detect circles. The problem is that since the asteroids have different sizes, it is hard to create an accurate collision detect function for all of them. Try taking a look at the JS file for more details. \$\endgroup\$ May 21, 2013 at 20:28
  • 1
    \$\begingroup\$ @user2350334, Take a look at the accepted answer for stackoverflow.com/questions/8968591/… Basically you need to hard-coded a polygon that outlines the shape of each spaceship well. You can then test whether each of the line segments intersects with a given circle. Alternatively, you may cheat and pick n equally-spaced and tightly packed points on the outside of the spaceship. Hard-code that list for each spaceship. Then check whether any of the points lies inside of a circle. That test will run quickly because you are just comparing R w distance to the center \$\endgroup\$
    – Leonid
    May 21, 2013 at 22:36
  • 1
    \$\begingroup\$ @user2350334, for speed purposes you may take a shortcut - come up with a big bounding sphere that fully encompasses all of your space ships. Then quickly check whether that bounding sphere intersects with any of the asteroids. If it does not, then the space ship is 100% safe. If the bounding sphere intersects with some asteroids, then only finely inspect the intersection with asteroids that are "suspects", e.g. their bounding spheres intersected. These are standard approaches to collision detection in gaming. So, your question did not belong at this codereview site to begin with. \$\endgroup\$
    – Leonid
    May 21, 2013 at 22:41
0
\$\begingroup\$

Rather than doing math with coordinates, you might try this:

var board = ["0x0","0x1","0x2","0x3",
             "1x0","1x1","1x2","1x3",
             "2x0","2x1","2x2","2x3",
             "3x0","3x1","3x2","3x3",
             "4x0","4x1","4x2","4x3"]; //Grid-based game board

var player = {
    "x": 0,
    "y": 0,
    "location": "0x0"
};

var enemy = {
    "x": 0,
    "y": 0,
    "location": "0x0"
};

if (player.location == enemy.location){
    //Do things
}
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.