I have a ball that can move along any angle, and I want to squash and stretch it based on this angle.
To be clear, if you dropped the ball down at a -90 angle, the squash would be all along the y, and the stretch on the x.
This wouldn't work however for a 0 degree angle, where the squash is on the x, and the stretch on the right.

3 Answers
3

It is not possible to deduce X and Y stretch factors to reach your goal, they simply do not exist.

One solution is to first rotate your object so that its main axes coincide with the main X and Y axes, then apply the squash/stretch transformation, then rotate the object back to its original orientation.

In terms of matrices, this would be the matrices involved, where SQ ≤ 1 is the squash factor, ST ≥ 1 is the stretch factor, and vx and vy are the normalised directions of motion (ie. you can get vx and vy by normalising your direction vector):

| vx -vy | | SQ 0 | | vx vy |
| vy vx | | 0 ST | | -vy vx |

The product of these matrices is:

| SQ*vx²+ST*vy² (SQ-ST)*vx*vy |
| (SQ-ST)*vx*vy SQ*vy²+ST*vx² |

It is not a trivial matrix but you can probably inject it into your framework. Otherwise, you can still apply the three transformations (inverse rotation - scale - rotation) separately.

Although using vx and vy instead of (co)sines for the rotation matrices is a nice optimisation, make sure they are normalised, either before or after, or this transformation will scale the ball by a factor v².
–
Marcks ThomasJan 29 '13 at 14:49

If your ball is actually a circle, you can just draw it as an ellipse, rather than a circle, with one axis aligned along the direction of travel. When the ball hits a surface, transition from being stretched along the direction of travel to being squashed perpendicular to the surface, and stretched parallel. Then as the ball leaves the surface, do the opposite, ending up stretched in the new direction of travel. This means that the directional axis will essentially rotate around the point of impact, which is what I think you want.

If you're transforming a bitmap, then some combination of rotation in the direction of travel and/or shear & scale transforms should do it. Draw out a few "keyframes" of the squash effect to see what works.

If you want to generalize it to an equation you'll need to be able to stretch and squish the image on things other than the x and y axis (A diagonal drop requires squishing the corners together and apart) An easier solution could be as simple as making your sprite sheet have a nicely animated squish in one direction then rotate the ball such that "down" on the sprite is the direction of the collision.

If you are not able to do so for whatever reason, and do have the ability to squish/stretch in any direction, there are math solutions available to you. You can get some simple directions of the stretch/squish by finding the perpendicular/parallel lines to the collision vector (center of ball to point of impact).

You can also tell how much something should squish along a specific axis (say if you only have x and y to deal with and you're fine with it) by checking the dot product of the collision vector normal against the stretch direction. 1 means that you should be doing maximum squish and 0 means you should be doing maximum stretch along whatever direction you specify.