# Angle Shooting

This topic is 3582 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

## Recommended Posts

I'm trying to figure out how to shoot based on the character's angle. Every time a player or enemy shoots, a bullet is created right in front of them and then moves off on its own. Right now, I'm only checking for 0 and 180 (up and down). And the code on that is pretty long (one for X and Y). Is there a mathematical function to do this easily?

##### Share on other sites
look into using sin and cos

##### Share on other sites
Trig isn't my specialty, but I'll take a shot.

I got this (the Bullet class takes care of positioning):
offset.x = ( character->get_x_pos() ) - static_cast<Sint16>( ( offset.w / 2 ) * sin( angle ) );offset.y = ( character->get_y_pos() ) - static_cast<Sint16>( ( offset.h / 2 ) * cos( angle ) );
It's a bit off (at 315 degrees, it shows up lower than the firing point). I have to incorporate this into the shooting function.

##### Share on other sites
Now I have to calculate the bullet's trajectory based on angle. I plan to go by 45 degree increments.

Here's the code. Correct me if anything is wrong.
// Sets the X and Y velocity based on angle.void set_velocity( int newVel ){	// If the angle is a multiple of 180, the Y velocity is zeroed.	if ( angle % 180 == 0 ) {		yVel = 0;		xVel = newVel;	}	// If the angle is only a multiple of 90, the X velocity is zeroed.	else if ( angle % 90 == 0 ) {		xVel = 0;		yVel = newVel;	}	// If it's any other angle, set both velocities.	else {		xVel = newVel;		yVel = newVel;	}}

##### Share on other sites
Look into vector math. What you're doing can be simplified a lot. Besides, your code is only correct for 0/90/180/270-degree angles. You really should investigate vector math as it can save you a lot of time and hassle later on.

Anyway:
void set_velocity(int newVel){	float factor = newVel / sqrt(xVel * xVel + yVel * yVel);	xVel *= factor;	yVel *= factor;}
What happens here is that you divide your x and y components by the current velocity (the length of this vector) and you then multiply it by the new velocity. In other words, you first set the length of your velocity to one - it keeps it's angle but not it's length - and then it's as easy as multiplying both by the new velocity - so the length will be newVel, because 1 * newVel is newVel.

##### Share on other sites
Ah, vector math. Unfortunately, my velocity has to be in whole number integers (because a velocity of one means one pixel per frame).

So if I had xVel = 2 and yVel = 3, using your formula would yield a factor of 6. Thus, the newVel parameter has to be bigger than or equal 12 to make any real difference.

Is there a way to move every few or so frames so I can get a more accurate velocity calculation?

##### Share on other sites
why does it have to be an integer? If it's for rendering then you can round the floats to an integer if that's necessary.

http://en.wikipedia.org/wiki/Unit_circle

See the vector produced from an angle. (cos(angle), sin(angle)) that's a unit vector. To get velocity for a bullet you can multiply it by a scalar like:
(cos(angle) * speed, sin(angle) * speed)

Depending on how you set things up if the y is reversed then:
(cos(angle), -sin(angle))
and
(cos(angle) * speed, -sin(angle) * speed)

##### Share on other sites
Quote:
 Unfortunately, my velocity has to be in whole number integers (because a velocity of one means one pixel per frame).

No it doesn't. The screen is not the game world, the screen is a view of the game world; there's nothing wrong with your object being at (0.6, 1.4) and your display showing it at (1, 1) ... although with most graphics libraries you could draw it at (0.6, 1.4) anyway.

I can only second the 'look at vector maths'. Object motion, particularly if you start modifying velocities in flight (gravity, homing missiles, air resistance, force fields etc etc), is extremely well described by simple vector operations.

##### Share on other sites
And of course I can use vector math to determine the distance of the player through the enemy and shoot a bullet there.

It's a shame that SDL_Rect doesn't take decimals.

##### Share on other sites
Okay, I've encountered another problem. Using my new velocity function, the objects jerk around or don't move at all. Nothing else has changed except the velocity functions.

Here's the code that changes the velocity:
// Sets the X and Y velocity based on angle. //void Character::set_x_vel( float newVel ){	// Calculates the unit vector. //	// Checks if lower denominator is zero.	float normal = sqrt( pow( xVel, 2 ) + pow( yVel, 2 ) );		if ( normal == 0 ) {		xVel = static_cast<float>( newVel * cos( to_radians( angle ) ) );	}	else {		float factor = newVel / normal;		xVel *= static_cast<float>( factor * cos( to_radians( angle ) ) );	}}void Character::set_y_vel( float newVel ){	// Calculates the unit vector. //	// Checks if lower denominator is zero.	float normal = sqrt( pow( xVel, 2 ) + pow( yVel, 2 ) );		if ( normal == 0 ) {		yVel = static_cast<float>( newVel * sin( to_radians( angle ) ) );	}	else {		float factor = newVel / normal;		yVel *= static_cast<float>( factor * sin( to_radians( angle ) ) );	}}
Is there anything wrong with my calculation of the unit vector?

##### Share on other sites
Don't set the x and y components separately, because the vectors length changes after changing a component, so whatever component you change last will use a wrong length.

Also, 'normal' isn't the correct term here. You're calculating the 'length' of your velocity vector. And 'unit vector' refers to a vector with length 1, which you aren't using here.

##### Share on other sites
I have a few suggestions.

First, why not set the velocity according to the speed and direction, like this:

// Sets the velocity based on angle and speed. //void Character::set_radial_vel( float speed, float angle ){	xVel = speed * cosf( to_radians( angle ) );	yVel = speed * sinf( to_radians( angle ) );}

If you want to change the speed, but preserve the direction, you could do this:

// Changes the speed. //void Character::set_speed( float speed ){	const float threshhold = 0.0001f;	float norm = sqrt( pow( xVel, 2 ) + pow( yVel, 2 ) );	if (norm < threshhold)		xVel = yVel = 0;	else	{		xVel *= speed / norm;		yVel *= speed / norm;	}}

Also, I recommend dropping the pixels per frame idea. Instead, express speed in pixels per second, or pixels per millisecond. You tend to get problems when you use frames for timing.

##### Share on other sites
Slight trouble with those two functions above. The bullet still doesn't fire at an angle (although the character does move at an angle). I initialized the bullet using set_velocity( -1, character->get_angle() ).

I change the velocity just before it shoots. I have a slight inkling on what might be going on. These two lines of code (in the Bullet class) adjust the bullet's initial position (to match with the player's "cannon").
offset.x = ( character->get_x_pos() ) + static_cast<Sint16>( ( offset.w ) * sin( to_radians( angle ) ) );offset.y = ( character->get_y_pos() ) + static_cast<Sint16>( ( offset.h * 2.3 ) * cos( to_radians( angle ) ) );
Is it that or there's something else wrong with the code?

[Edited by - os3330 on April 4, 2008 12:56:39 AM]