Advertisement

Aiming feature like angry bird

Started by December 12, 2023 06:12 AM
13 comments, last by JoeJ 1 year ago

Hello

Can you please give me some info on how I can add an aiming feature like Angry Bird in my game?

I will be pleased if you include the code.

regards

You have two points: finger press location and current finger location. Create a vector from those and use as your velocity.

NBA2K, Madden, Maneater, Killing Floor, Sims

Advertisement

Can you please explain more about the algorithm?

There isn't much of an algorithm: aiming requires a vector, the difference between two points (as @dpadam450 suggested) is a vector.

Just maintain a good separation between

  • user input, which can have different modes and can be replaced by automatic aiming and other mechanisms
  • the game actions that can be aimed, which should work in the same way for any input source
  • user interface feedback to show where the player is aiming

Omae Wa Mou Shindeiru

My question is just this curved line part that you can see in the image:

Cured line

Advertisement

Oh, the classical aiming the turret problem.
The curve is actually a parabola, if we ignore air resistance which we usually do.
The parabola comes from the equations of motion under a constant gravity term.
So to get something like the launch angle of the turret, or the highest pint on projectile trajectory, or the time to target, you can get all that from transforming this equation.

To find the equation, let's make an example of integrating particle motion falling under gravity:

	float start = 0.8f; // initial height of the particle
	float timestep = 0.008f;
	float a = -5.0f; // constant acceleration of gravity
	
	float p = start; // current height
	float v = 0; // current velocity
	
	for (float t = 0; t <= 2; t += timestep) // simulate time for 2 seconds
	{
		// integrating, similar to how our physics engine would do
		v += a * timestep;
		p += v * timestep;


		// alternatively, since we know no other actions like collisions will affect our particle, we can also use the analytical solution:
		float pA = start + 0.5f * a * t*t;
		float vA = a * t;
		
		// plot or print our results, and we will see p==pA and v==vA, besides the small error of the integrator

	}

Assuming i did no mistake you could see this works, and we now have the math to calculate where the projectile is at any point in time.
Extending this to 2D or 3D is trivial, because gravity affects only one dimension. The other (two) dimensions only have simple constant velocity motion, which is easy.
This also means that changing turret angle affects our equation by having a different initial velocity to be more or less upwards, which my analytical method does not handle, but we can add this and still have a closed form solution (but we could not add the handling of air resistance, which lacks an analytical solution).
We also see our equation is quadratic, so we'll often get two possible solutions.

Doing the math we get something like this:

	inline float GetLaunchAngle (float vel, float grav, float diffH, float diffV, bool takeHigherAngle = 1)
	{
		vel *= vel;
		float r = sqrt (fabs(vel*vel - grav * (grav * diffH*diffH + 2.0*diffV*vel)));
		if (takeHigherAngle) r *= -1.0;
		float s = vel - r;
		float t = s / (grav*diffH);
		return atan(-t);
	}

	inline sVec3 GetLaunchVelocity (sVec3 target, sVec3 launchPos, sVec3 gravityDir, float gravity, float launchVel)
	{
		sVec3 diff = target - launchPos;
		float diffV = gravityDir.Dot(diff);
		sVec3 plane = diff - diffV * gravityDir;
		float diffH = plane.Length(); // the height difference of turret and target
		if (diffH < FP_EPSILON) return gravityDir * -launchVel;

		// todo: handle out of reach and numerical special cases
		float angle = GetLaunchAngle (launchVel, gravity, diffH, diffV);

		// construct velocity vector to apply to projectile...
		sVec3 vv = plane; vv /= diffH;
		vv *= cos(angle);
		vv += gravityDir * sin(angle);
		vv *= launchVel;
		return vv;
	}

And i have used this using the physics engine like that:


		sVec3 projTarget; BodyGetCenterOfMass (targetBody, projTarget);
		sVec3 launchPos; BodyGetCenterOfMass (projectileBody, launchPos);
		float launchVel = 40;
		sVec3 projVel = Trajectory::GetLaunchVelocity (projTarget, launchPos, sVec3 (0,-1,0), fabs(propsPhysics::f[propsPhysics::gravity]), launchVel);
		BodySetVelocity (projectileBody, (float*)&projVel);

I did this only for fun, but it worked with good accuracy even along far distances.

There is a variable ‘takeHigherAngle’ which picks one of two potential solutions.
We can throw the stone either high or low to hit the same target. The lower path is usually preferred, hitting the target faster. Angry Birds likely always used the low path.
But the higher path is more impressive to watch, and it could help to throw over some obstacle.

I guess there is also better code to find than mine, ideally less complicated.

JoeJ said:
I guess there is also better code to find than mine, ideally less complicated.

Your code is cool and very confusing!

But now where should I place pixels?

Can you explain more concretely? And not just math?

lingo1357 said:
Can you explain more concretely? And not just math?

Not really. There is no way around the math. And because i'm self thought, it's difficult and error prone to talk in math terms.

But what's your actual problem? Sort of aim assist to the player, or make AI which can hit targets?
And how does your game work? 2D or 3D?

JoeJ said:
But what's your actual problem? Sort of aim assist to the player, or make AI which can hit targets? And how does your game work? 2D or 3D?

My game is 2d.

My purpose is to aim assist to the player.

This topic is closed to new replies.

Advertisement