kittykatattack / ga

The world's tiniest, cutest and funnest game engine
451 stars 85 forks source link

Collision deduction with changing scale. #20

Open qsrahman opened 9 years ago

qsrahman commented 9 years ago

If we change the scale of an object or rotate the object during game play the collision deduction become incorrect. I noticed that the scale is not used in hit tests, centerX, halfwidth etc. why?

kittykatattack commented 9 years ago

Those are great feature to add.

Regarding scale:

I'll do some testing, but it's mostly just a matter of multiplying the sprite's x and y positions with their scaleX and scaleY properties in the collision functions (which are in plugins.js)

Something like this should work:

if (global) {
  vx = ((r1.gx + r1.halfWidth) * r1.scaleX) - ((r2.gx + r2.halfWidth) * r2.scaleY);
  vy = ((r1.gy + r1.halfHeight) * r1.scaleY) - ((r2.gy + r2.halfHeight) * r2.scaleY);
} else {
   vx = (r1.centerX * r1.scaleX) - (r2.centerX * r2.scaleX);
   vy = (r1.centerY * r1.scaleY) - (r2.centerY * r2.scaleY);
 }

I haven't tested this code above, but that's the general idea. (Those scale values might actually have to be divided by two... I'll check!) All the collision functions have this initial if statement that figures out the collision vy and vx vectors, so this would be a convenient place to compensate for scale. This might have some secondary effects that I haven't considered, so I'll need to do a lot of testing - but I'll add this to the feature list.

Regarding rotation:

If the rectangular bounding boxes used for the collision tests aren't rotated you have a quick, cheap way to test for collisions. That's because you just need to check for a collision on two axes: x and y. Most 2D video games use this standard, non-rotated collision check, even for rotated objects. (If your graphics are square-shaped and moving quickly the inaccuracy isn't noticeable.). Or, they use an even simpler circle based collision test (hitTestCircle) and don't worry about the slight overlap around the corners. In fact, the slight inaccuracy gives the collision test a little leniency which tends to seem natural in a fast-moving game. A Circle vs circle collision test is also the most high-performance check you can run because it just does one essential calculation: the distance between the colliding circles' center points, and compares this against their radii.

It gets a lot more complicated (and computationally expensive) if you introduce accurate collision with rotation because you need to calculate the angle of 4 vectors (one for each side of the rectangular bounding box) and compare each of them against the 4 angled vectors of the the other rotated box in the collision. (16 checks in total - instead of just 2 (x and y) in the non-rotated collision check.) This is fully described in Christer Ericson's classic book "Real Time Collision Detection".

But it's definitely possible to implement this. Maybe with four new collision functions:

hitTestRotatedRectangle : returns true or false if two rotated rectangles overlap. rotatedRectangleCollision : keeps rotated rectangles separated or bounces them apart. hitTestRotatedRectangleCircle : returns true or false if a circle hits a rotated rectangle. rotatedRectangleCircleCollision : bounces a circle off a rotated rectangle.

I think these are worth working on.

But, if you're starting to go much further down this path, you need consider whether you should really just be using a full-blown physics engine like Box2D or PhysicsJS. There are some complex interdependencies you need to sort out that only a closed physics system can manage reliably and efficiently. It should be pretty easy to build a high-level API for either of these libraries that will work with any standard sprites in Ga's current library. Just get the positions and rotations from Box2D or PhysicsJS, and map them to Ga's sprite positions/rotations.

qsrahman commented 9 years ago

Your suggested solution requires the user of GA to remember to apply scaleX etc what I want is that the engine should do all calculations. I was porting a simple game designed with 'Phaser' but the existing collision deduction was not giving accurate results. The solution is to use pivotX, pivotY, scaleX etc while calculating centerX, Y and drawing the sprites. I will post a patch for reviving and further testing. However I am satisfied with the results so far.