Projectile calculations in 3D space, using your own movement code

It’s been a while 🙂 I have been busy and did not have the energy to finish this 4 part series of projectile calculations. Now I am finally putting out the last bit. Calculating the projectile movement in 3D space using your own movement code.

For starters, lets refresh what I wanted to write in the first place. I was working with a project where I needed to calculate the a projectile path in 3D space using my own movement code rather than relying on the rigid body and physic engine. In my case I absolutely wanted the projectile to hit the target always so I couldn’t go with the calculate path with any given velocity and any given angle.

For a refreshment’s sake, let’s revisit this picture. Red diamond is the source and green cube is the target. Source position is x1, y1, z1 and target position is x2, y2, z2. The angle between x -axis and projectile is theta which is 66 degrees in the example. Y axis is up and Z is forward.

projectile_3d_001

So last time we used rigid body and it’s AddForce method to do all the work. Now we need to calculate the position by ourselves. So lets start with the same formula based on Wikipedia. You can solve the velocity from distance formula when both start and end y coordinates are 0. v = 1 / cos(a) * sqrt((0.5 * g * d * d) / (d * tan(a))); where v = velocity, d = distance, g = gravity and a = angle.

Since we are interested in horizontal velocity having 2 components (X and Z) and vertical component Y we need also calculate direction because we want to manipulate the X and Z correctly. Direction we can get by subtracting the start and end positions and taking the normalized of resulting vector. So: Vector3 direction = (end – start).normalized;

You are also going to need the duration the projectile will stay in the air. Well, you could also not care about this but probably you want to do some cleanup code so your scene will not get filled with projectiles that are already landed and immobile. You can use the horizontal distance as base for duration or you can use the Y component thus velocity and gravity. Since we used the horizontal distance last time let’s now use the Y component. So the duration can be calculated by: (Sin(Angle) * velocity * 2) / gravity.

So in our example: d = 21.2132, a = 66.0, g = 9.81, replacing the variables in the velocity equation give us v = 16.74. Duration is: 3.11

If you remember from the 2D example we used the Unity’s update() function to move the projectile. This is perfect fit again since we have just one more component it’s basically the same.

So we are going to utilize the Time.deltaTime so we know how long as time passed since last update and multiply that with horizontal velocity. This is going to be our fraction of the journey up to the destination in horizontal space. Then we need to multiply the (horizontal) speed with the fraction multiplied by direction. So code is:


var horizontal = Mathf.Cos(Angle * Mathf.Deg2Rad) * velocity;
float frac = (Time.deltaTime * horizontal / distance);
var direction = (target.transform.position - start).normalized;
float x = frac * distance * direction.x;
float z = frac * distance * direction.z;

I am actually doing unnecessarily the direction inside the Update() since start and end do not change during the projectile flight. Anyways. This is the increment / decrement you need to apply to X and Z components.

What about the Y component? This is exactly the same as previously. From the wikipedia article, height at arbitrary distance X: By feeding our parameters in the formula: height y = start.y + x * tan(angle) – (gravity * pow(x) / 2 * pow((velocity * cos(angle)))). Note: x here is the distance from the start. Well, wikipedia article is 2D so X is the distance from the start but we need to use both X and Z components. Well we actually have all we need, we did the fraction right?


Vector2 position = new Vector2(transform.position.x + x, transform.position.z + z);

This is the current projectile position and since I am using the code in the projectile, transform refers to this GameObject’s transform. If we take the position.magnitude we have the distance.

Ultimately we want to do this:


this.transform.position = new Vector3(position.x, y, position.y);

Note: We projected the X,Z movement to Vector2 so it do not have Z we need to use Y. You can do this also without the Vector2 by calculating the distance by:
sqrt(pow(start.x – end.x) + pow(start.z – end.z)).

So here it is, now you can do the projectile calculation in 3D by using your own code. The complete solutions is not here, but all the relevant bits are here so you should be able to complete the Update() function very easily.

What do you think of all this? Do you have any suggestions or feedback. Please leave a comment and happy coding!

Projectile calculations in 3D space, using rigid bodies

If you have been following what I wanted to write regarding projectile calculations you know now how to do the calculations in 2D with using both rigid bodies and by calculating the movement code yourself. Now we add one dimension and see how it effects things.

Let’s take a look at this picture. This is pretty similar than the previous one but with one more axis involved. This is your game where you have source (red diamond) and target (green cube). Source position is x1, y1, z1 and target position is x2, y2, z2. The angle between x -axis and projectile is theta which is 66 degrees in the example. Notice how now Y axis is up and Z is forward.

projectile_3d_001

We are still going to need the velocity vector like previously which then can be applied to rigid body. You have now three components X, Y and Z that you need to solve because you want the projectile to move to all directions.

With the same formula based on Wikipedia you can solve the velocity from distance formula when both start and end y coordinates are 0. v = 1 / cos(a) * sqrt((0.5 * g * d * d) / (d * tan(a))); where v = velocity, d = distance, g = gravity and a = angle.

Since we are now interested in horizontal velocity having 2 components (X and Z) and vertical component Y we need also calculate direction because that is going to dictate how much force we need per component. Direction we can get by subtracting the start and end positions and taking the normalized of resulting vector. So: Vector3 direction = (end – start).normalized;

Distance you get by d = sqrt(pow((x2 – x1)) + pow(y2 – y1)), or Vector3.Distance(start, end) or (start,end).magnitude (where start and end are Vector3 objects)

So in our example: d = 21.2132, a = 66.0, g = 9.81, replacing the variables in the equation give us v = 15.0929.

Remember how we used the rigid body’s AddForce -method to apply the velocity vector? We can use the same function but now we are going to need the Z -component too. Last time we did this:


var distance = Vector3.Distance(target.transform.position, position);
var velocity = (float)(1 / Mathf.Cos(angle * Mathf.Deg2Rad)) * Mathf.Sqrt((float)(0.5f * 9.81 * distance * distance) / (distance * Mathf.Tan(angle * Mathf.Deg2Rad)));
float horizontal = Mathf.Cos(angle * Mathf.Deg2Rad) * velocity;
var direction = (target.transform.position - position).normalized;
var rbVelocity = new Vector2(direction.x * horizontal, Mathf.Sin(angle * Mathf.Deg2Rad) * velocity);
rigidBody.AddForce(rbVelocity, ForceMode.Impulse);

Now we just use Vector3 like this:


var rbVelocity = new Vector3(direction.x * horizontal, Mathf.Sin(angle * Mathf.Deg2Rad) * velocity, direction.z * horizontal);

That is basically all we need. Adding the third dimension was very easy since the direction already contains both X and Z components that we need. Now you can fire a projectile that will always land on it target so matter what is used angle (with the exception of 90 and 0 of course). What do you think, any ideas or suggestions? Please, leave a comment.

Simple projectile calculations in 2D with your own movement code

So last time we did a simple projectile calculation by using Unity’s rigid bodies by calculating velocity vector and applying a force to the projectile rigid body. Now we do the same without rigid body but doing a calculation based on updating the position manually.

Remember this was the sketch of what we have:

projectile_2d_001

For updating the position we need to know the angle, distance, amount of gravity and time of flight. We also need to calculate the velocity which we need to do other calculations. The distance as you remember from the last time we get by: d = sqrt(pow((x2 – x1)) + pow(y2 – y1)), or Vector3.Distance(start, end) or (start,end).magnitude (where start and end are Vector3 objects).

So in our example: d = 15.0, a = 66.0, g = 9.81, replacing the variables in the equation give us v = 14.0716. Now we are interested how long the projectile will stay in the air. This is because we need to interpolate the position between the start and end positions. We could use some a fixed value for time but this will create unrealistic result since the actual time spent in the air depends on the angle and distance (and gravity).

So how we get the time? You can calculate the time the projectile is airborn in two ways. Either you can use the Y component (eventually gravity pulls the projectile back to ground) or X component. If you want to use Y, the formula is time t = (velocityY * 2) / gravity. So y velocity times 2 over gravity. If you remember from the last time we used the velocity and direction to get the horizontal velocity and sin(angle) * velocity to get Y vertical velocity? We use the same method like this:


var direction = (target.transform.position - start).normalized;
var horizontal = Mathf.Cos(angle * Mathf.Deg2Rad) * velocity;
var vertical = Mathf.Sin(angle * Mathf.Deg2Rad) * velocity;

Finally we can calculate time: t = (vertical * 2) / g. So in our example it is: 2.62s This means that the projectile will stay in the air 2.62 seconds without hitting the target. So bigger the angle more velocity we need to hit the target thus longer the projectile will stay in the air. You could also use t = distance / horizontal, which by the way also gives the same 2.62. (which is a good thing!)

Ok, we have now all the components needed for our calculation. We are using Update() function which Unity will call every frame. This makes the function frame rate dependent, e.g. with 30 fps Update will get called on average by every 33.33 ms. So we know that we should get from start to the end in 2.62s. I said we need to interpolate the position based on the time. This can be done in several ways.

Unity has a Vector3.Lerp -function what is very handy what we can use e.q. Vector3 currentPos = Vector3.Lerp(start, end, time / duration); If the use this helper inside Update() -function we need to increment time variable by the difference of the previous call and Time.deltaTime is exactly for this. This way you make sure your stuff is not frame rate dependent. So a small example:

private float time = 0.0f;

private void Update()
{
time+=Time.deltaTime;
var currenPos = Vector3.Lerp(start, end, time/duration);
}

Duration you need to be calculate somewhere outside Update and start and end are positions as Vector3 type.

If you update your projectile currentPos, it will fly from start to end in given duration, but since it’s a linear interpolation between the values it do not have the projectile trajectory yet. We actually use only the x component to update the x position but we also use it to calculate y position. So how it’s calculated? We go back to the original Wikipedia page and see that height at arbitrary distance x has a formula:

height y = start.y + x * tan(angle) – (gravity * pow(x) / 2 * pow((velocity * cos(angle))))

so when in our Update() function we apply the x from current position to the formula, we have the height at distance x. The update function is going to need something more than that, for example you don’t want to update the position unless the projectile has been launched and you don’t want to update the position after time > duration. But that’s easy stuff after all this.

Neat, now you can hit the target by any angle and distance and you are doing it all by yourself! What do you think? Do you have any suggestions or improvements? Leave comments!

Simple projectile calculations, first in 2D by using rigid bodies

It’s been a very long time since I posted anything programming related here. The reason being I have been busy at work working with two different games and I have felt I didn’t have the energy to do anything extra at home.

But just recently I was working with a new game play feature where I needed to calculate a projectile movement. This was not something I have done before and I had to dig up some stuff to make it work and I wanted to share some of the ways how to do this. It’s basically not rocket science but there are some considerations how you want to do it. This is the first part of the series where I cover some techniques how to do the calculations. First we concentrate on 2D space and later how to do that same in 3D. The reason is it’s easier to understand what’s needed with just 2 axis rather than with 3 axis. I have done the code by using Unity3d but the principles applied are universal.

So in my task I needed to calculate projectile trajectory in 3D space where I know the start and end coordinates, possible throw angle but not the velocity needed to hit the target. In the game I absolutely want the projectile to hit the target so this is directly not applicable to calculation in a game mechanic where you can freely select the angle and possible velocity (thrust / power), and calculate how far the projectile will go. The formula is still the same but you would need to solve different factors from the formula.

So firstly, if you use Unity3d you can choose at least two different ways to do the projectile. 1) Using rigid bodies and applying a force to the rigid body and let Unity take care of the projectile movement. This is the easy way. You don’t need to calculate a whole lot of stuff just apply a certain force and boom, off you go. 2) You do it manually. You calculate the projectile movement by yourself.

Solution 1) is just fine if you can do that. With ridig body you lose the control how the physics simulation takes place (it’s carried out by Unity3d). This might be ok for certain game play mechanics, but was not for me. For example I needed to be absolutely sure that the projectile will end up in the target. Also if you want to have automatic collision detection with colliders you might have a situation where you have something in front of the actual target and colliding that instead of intended target. This is of course not realistic but if you are reading this you are probably not making a realistic FPS anyway.

Solution 2) is where you do calculations manually. This gives you absolute control of the position of the projectile and still allows you to do collision detection with colliders.

Ok, let’s draw some stuff. This is your game where you have source (red diamond) and target (green cube) in 2D. Source position is x1, y1 and target position is x2, y2. The angle between x -axis and projectile is theta which is 66 degrees in the example.

projectile_2d_001

With solution 1) you need to calculate the velocity vector which is applied to the rigid body of the projectile. You have two components X and Y that you need to solve because you want the projectile to move both to X and Y directions, right?

With the formula based on Wikipedia you can solve the velocity from distance formula when both start and end y coordinates are 0. v = 1 / cos(a) * sqrt((0.5 * g * d * d) / (d * tan(a))); where v = velocity, d = distance, g = gravity and a = angle.

Distance you get by d = sqrt(pow((x2 – x1)) + pow(y2 – y1)), or Vector3.Distance(start, end) or (start,end).magnitude (where start and end are Vector3 objects)

So in our example: d = 15.0, a = 66.0, g = 9.81, replacing the variables in the equation give us v = 14.0716. This is our total velocity which needs to be used in 66 angle to hit the target. So how you apply this force to a rigid body?

Rigid body has a function AddForce() which have multiple overrides but basically it accepts velocity vector to be used as force. You can also choose what type of force you are interested applying to. Since it requires a vector or 2 to 3 components (x,y) or (x,y,z) we need to calculate how this 66 degrees and velocity are in terms of a vector.

First we get the horizontal component from the velocity. This is done by multiplying cos(angle) with total velocity. And vertical component you multiply with sin(angle). We also need to know what is the direction we want the force to be applied to. This you get by target position – source position normalized. Vector3 direction = (target.transform.position – source.transform.position).normalized; What this does it gives the direction without the length.

For Y component it’s always a positive so we don’t need to do anything. (We are firing upwards, right?) For X component we need to multiply the direction.x with horizontal velocity. Like this: float xDir = direction.x * horizontal; These are the values for your velocity vector which you can apply to the rigid body.

So this is the code:

var distance = Vector3.Distance(target.transform.position, position);
var velocity = (float)(1 / Mathf.Cos(angle * Mathf.Deg2Rad)) * Mathf.Sqrt((float)(0.5f * 9.81 * distance * distance) / (distance * Mathf.Tan(angle * Mathf.Deg2Rad)));
float horizontal = Mathf.Cos(angle * Mathf.Deg2Rad) * velocity;
var direction = (target.transform.position - position).normalized;
var rbVelocity = new Vector2(direction.x * horizontal, Mathf.Sin(angle * Mathf.Deg2Rad) * velocity);
rigidBody.AddForce(rbVelocity, ForceMode.Impulse);

Some stuff outside the code: I have local reference to rigidBody of the projectile which I have instantiated at source position and I am applying this force once when I instantiate the projectile. This can be done several ways but I did mine on left mouse click so I would be able to see multiple projectiles flying from source to target.

Now you have code for a projectile using rigid body flying constantly to the target position with a certain angle and range. Nice. What do you think of this? Do you have any comments, ideas or improvements? Next time we do this same exercise by calculating things manually.

–small after post note–

If you run into problems where the projectile do not land correctly even if you think the formula and calculations are correctly, this might be caused by Unity’s physics engine with too few velocity solving iterations. My projectile hit the target always when angle was more than approx 30 degrees but would always go over the target when lower. If your calculations are correct then try to add the “solver velocity iterations” in the project settings, in physics tab.

Falling collectible bonus on Unity, part 2: The animation

In the last post we created the asset for the animated falling collectible bonus. In case you missed the post read it first here. In this post we use the images and create an animation in Unity for the collectible.

First you need to create a folder under “Assets” in which you will have the images. I have created a folder called “Sprites” and under “Sprites” I have a “Bonus” folder. The structure is up to you but creating a organized structure will help you later when you have more than just few assets (and asset types). Copy the images you created to the Bonus folder. You can import them by using Unity too but I don’t know how to import several images at one command so for me it was easier to use the file system copy.

When files are copied go to the folder and select all the images and drag them to the scene. Dragging the images to scene causes Unity to create an animation to the same folder the images are dragged from, in my case, folder named “Bonus”. You can rename the animation i.e. bonus. At the same time Unity creates a game object with:

  • Sprite Renderer, in which one of the images selected as Sprite (I don’t know is it random or how Unity decides this?)
  • Animator, in which the controller is newly created controller in the same folder. This also seems to have a random name but you can rename it to i.e. bonus. More about the Animator here.

We are going to need also some extra components. We are going to use BoxCollider2D so that we can check if player is colliding with the bonus. Add the BoxCollider2D component to the game object and check the “Is Trigger” check box. This way the bonus only causes trigger when colliding but do not actually collide (interfere with the physics). We don’t want the bonus to bounce or anything from the other game objects. Set the X and Y size so that it matches the sprite boundaries (for me X=0,7 and Y=0,33).

We are going to need also a Rigidbody2D component. You can leave the default values for this component. If the game object do not have Rigidbody2D component it will be ignored by the physics engine. If you are not having this component you need to take care of the movement of the bonus in the scene, plus I think you need to check the collision manually. In my game I wanted the bonus to “fall” so I use gravity to move the object. Your case might be different and require other type of approach.

Now you should have an animation called bonus and controller named bonus in your bonus folder along the sprites and a game object with Sprite Rendered and Animator in which the controller is the “bonus” -controller. You should also have a BoxCollider2D and Rigidbody2D components.

We are also going to add a Script. Add component and select “New Script”, type the name i.e BonusScript and select the type CSharp. This script is going to have the code which is triggered when bonus is collected. The Rigidbody2d has a method:

void OnTriggerEnter2D(Collider2D other) {

// write your bonus handling here or send message to appropriate game object

}

If you are familiar with the tag concept you can check if the object the bonus is colliding with is a player with this type of clause:

if(other.gameObject.tag == “Player”){

}

Using gravity increases the speed of the bonus so it’s more realistic, but if you want to move the bonus object same speed all the time then you can use the following script:

void Update () {
gameObject.transform.Translate (Vector3.down * Time.deltaTime);
}

When you are done with the game object in the scene, drag it from the hierarchy to the folder where you store your prefabs and delete the game object from the scene. This way you can use the prefab to instantiate the actual bonus object in your game.

Until next time, happy coding!

Falling collectible bonus on Unity, part 1: The asset

I thought writing this down already a month ago when I was playing around with Unity and I wanted to create an animated collectible bonus which is instantiated at the certain coordinates at the screen and it starts then to fall “down” (usually Y axis). Now I will create a blog post about the whole thing so I will remember how to do it and maybe help someone else too.

Bonus itself will be a simple small block, a sort of a tile with a letter so that the player can decide if he/she wants to collect the bonus or just let it drop out of the screen. So the bonus tile looks something like this:

r001

This is a simple PNG sized 77 x 38 created with GIMP. The trickier part is the letter and the animation. I want the bonus to be without the letter at the first frame and then frame by frame the letter should be revealed from top of the block so that it will look that it’s kind of rolling down. This means that the letter rendered on the tile should be transformed just a little bit “roundy” so that it would have an illusion of 3rd dimension.

To create the letters (by using GIMP):

  1. Create a new layer of the same size as the original layer (77 x 38 in my case). Have the background as white. This is needed because when mapping the layer we don’t want it to be transparent.
  2. By using the text tool create a letter of size 24 px (size 24 looks balanced in the tile) . I will be using letter M in this example.
  3. Rotate the layer 90 degrees clockwise (layer -> transform -> rotate). We need to do this because the GIMP map object filter cannot (at least I don’t know how) map layer to horizontally aligned cylinder aka pipe.
  4. Center the rotated layer by using the alignment tool.
  5. Merge letter layer to the white background layer of the same size as original.
  6. Take the filters -> map -> map object filter up.
  7. Options: map to cylinder, create new layer check box on, transparent background off, no light. In the orientation tab: set the Z rotation to -90 degrees. This now rotates the cylinder horizontally. Leave X and Y to 0 degrees. On the Cylinder tab: images can be what ever, we don’t use them. IMPORTANT: the radius of the cylinder should be a little bigger what your layer is, mine is 0,42 pixels I presume. Check the length so that the letter looks good. (for me 0,65)
  8. Try creating the new layer and check the result. It should look somewhat normal letter M with a little bit of “rounding”, that meaning it do not look completely flat. You can delete the layer and adjust the parameters and create new if it do not look good.
  9. When the letter looks good, you need to start creating the frames. This is done by adjusting the X rotation on the Orientation tab. Start from somewhere -100. It should rotate the letter almost hidden in the top only the bottom of the letter should be visible in the top. Most of the letter is hidden behind the camera and this is why we didn’t want the transparency.
  10. Hide the original layer of the rotated letter (this is done to prevent the export render it as part of the final image)
  11. Select the created frame with the letter just barely showing on the top and select colors -> color to alpha. And select white. If done correctly now the tile and letter should be aligned correctly and look something like this: r002
  12. Export the image in PNG format and name the image something you are comfortable with. I named all my images xxx001.png, xxx002.png and so on so that the numbering is the frame order. For me the first frame was the clear one.
  13. Now increment the X rotation by 10 degrees (this depends how many frames you want to have and how big steps the letter should be rolling). Hide the layers not needed and go to step 11.

In the end of the process you have something like 22 images / frames. The result should be something like this if exported as an animated GIF:

bonus_animated

 

When this is animated so that it moves along the Y axis it looks like it’s falling and rolling at the same time. In the next post I will explain how to use this in Unity. Until next time!

Recent progress with LibGDX version of Word Slinger

I decided to rewrite my game with LibGDX to help me focus more on the actual game and features rather than splitting my time enhancing the engine AND the game.

Word Slinger consist of several screens: Menu Screen, Play Screen, Options Screen, Help Screen, High Score Screen and few extras for handling high score user input etc. Since I am new to LibGDX I thought it would be wise to start to rewrite the game from the simplest possible screen. In my mind this could have been the Help Screen. In Help Screen there’s actually just a little bit text explaining what to do in the game plus some credits and one button.

I knew there was going to be a lot of implications if I just copy & paste the classes I used with my original engine. And there was, a lot. Luckily I used a bit similar abstraction in my own game called Screen which LibGDX has but there was a plenty of things that I have thought very differently. One thing that didn’t make the Help Screen the most easiest one was the fact that I created my own Font class with font metrics and stuff. This is all neat but unfortunately there’s no easy way to use this in LibGDX. To get forward I created a temporary font with Hiero so I can have fancy font of my own.

One nice thing about the LibGDX is the Scene2d. This is a object graph for handling different “things” on the Scene (screen). These object are Actors, objects / entities that compose the Scene (with few other things). Scene2d can use Tables and other widgets for creating UI elements and help positioning the stuff on the screen. I wont go now into detail of all that, it can be read here. Nevertheless, there’s a lot of things to read and learn.

After few (plenty!) bumps and moments of frustration I have managed to create the Help Screen and part of the initial Play Screen. Here are few screenshots which look the same like I was having already last autumn. 🙂 🙂 Hopefully when I get some of the infrastructure ready things will speed up !!

 

ws_help001ws_play001