Search code examples
androidgame-physics

How to bounce two moving objects


I'm making a ConSumo game from the arcade machine in Bully. Basically there's an enemy wrestler that move in a straight line and will bounce the player back if collided. I can't seem to figure out the logic in the angle to bounce the player when collided with an enemy wrestler.

I tried calculating the collision angle using the arctan of (player.centerY - enemy.centerY)/(player.centerX - player.centerY) and then adding 180 degree to mirror the angle.

double angle = Math.atan(((player.getCenterY() - enemies[i].getCenterY())/ (player.getCenterX() - enemies[i].getCenterX())));
angle = Math.toDegrees(angle);
angle += 180;
angle = Math.toRadians(angle);

player.addX(Math.cos(Angle) * strength);
plyaer.addY(-(Math.sin(angle) * strength));

I tried to just make the player bounce back on the same angle(i know this is not the ideal result, but i want to at least get the hang of it first, if you can suggest the better ways, i will appreciate it) but it only works on one or two side of the collision, and the other sides seem to pull the player through the enemy instead of bouncing it back.


Solution

  • Maybe you can try the physics approach which is taking into account conservation of impulse and conservation of energy.

    Basically, the player, with mass mp, has velocity [vp; 0] and enemy, with mass me, player has velocity [ve; 0]. So no y components because they move horizontally only. Now at the time of collision t = t_col assume the center of mass of the player has coordinates [xp, yp] and the enemy's center of mass has coordinates [xe, ye] (you can always tweak them to make sure there is a greater bouncing-off effect, by making the y coordinates much more different if you wish).

    Conservation of momentum tells us that the velocities of the two objects, call them [Vp, Wp] and [Ve, We] right after the collision are calculated as follows

    [Vp; Wp] = [vp; 0] + (1/mp)*[I1; I2];
    
    [Ve; We] = [ve; 0] - (1/me)*[I1; I2]; 
    

    where, as is typically assumed that the impact is normal to the surface of the objects, the vector [I1; I2] can be taken to be aligned with the vector connecting the two centers: [xp - xe; yp - ye]. Combining this information with the conservation of energy, one can calculate the magnitude of the said vector and find that

    k = (mp*me/(mp+me)) * (vp - ve)*(xp - xe) / ((xp - xe)^2 + (yp - ye)^2);
    
    I1 = k*(xp - xe);
    
    I2 = k*(yp - ye);
    
    

    So basically, at time of collision you have as input:

    • the position and velocity of the player: [xp; yp], [vp; 0]
    • the position and velocity of the enemy: [xe; ye], [ve; 0]
    • the mass of the player mp and the mass of the enemy me

    Then calculate

    k = (mp*me/(mp+me)) * (vp - ve)*(xp - xe) / ((xp - xe)^2 + (yp - ye)^2);
    
    I1 = k*(xp - xe);
    
    I2 = k*(yp - ye);
    
    Vp = vp + (1/mp)*I1;
    
    Wp = (1/mp)*abs(I2);
    
    Ve = ve - (1/me)*I1; 
    
    We = (1/me)*abs(I2); 
    

    Observe that I used abs(I2) which is the absolute value of I2. This is because for one of the two objects the y-component of the velocity after collision is going to be positive (so no difference there), but for the other one will be negative. For the negative one, we can also add the fact that the object may bounce off the ground immediately after collision (so collision with object and then collision with the ground). So we use the reflection law, kind of like the way light is reflected by a mirror.

    After collision, at time t = t_col the parabolic trajectories of the two players (before they land back on the ground) will be

    xp(t) = xp + Vp * (t - t_col);
    
    yp(t) = yp + Wp * (t - t_col) - (g/2) * (t - t_col)^2; 
    
    xe(t) = xe + Ve * (t - t_col);
    
    ye(t) = ye + We * (t - t_col) - (g/2) * (t - t_col)^2;
    

    If you want angles:

    cos(angle_p) = Vp / (Vp^2 + Wp^2);
    
    sin(angle_p) = Wp / (Vp^2 + Wp^2);
    
    cos(angle_e) = Ve / (Ve^2 + We^2);
    
    sin(angle_e) = We / (Ve^2 + We^2);
    

    where angle_p is the angle of the player and angle_e is the angle of the enemy.