Specifically trig…and you thought you’d never use trig outside of school, huh?
If you just want to see some things blowing up, you can scroll down to the bottom if you really want to. But if you are a math nerd, this just might interest you.
One of the reasons I majored in Computer Science was because I saw a potential to merge both math and computers together…my two favorite subjects. So what in particular did I need math for this time? It’s a little more complicated than the last time I wrote a post about some of the math used while developing Shape Sprout, although…I’m a little embarrassed to say I still initially forgot about Mathf.Rad2Deg and Mathf.Deg2Rad.
Working on our new game, Castle Clans, we are in a 3D environment rather than just a 2D environment like Shape Sprout, so it adds another dimension (pun intended) of complexity to our calculations. If you haven’t read my previous post about Castle Clans, the overall gist of the game is you own a castle with some sort of medieval weapon(s) protecting it. Your weapon(s) shoot boulders toward the enemy castle in hopes that you will either destroy all their weapons or their castle first so you can win the round, loot their gold and buy/upgrade your stuff to take out more difficult opponents. There are a ton of physics going on here between boulders flying between both castles and the fragments of destroyed objects. Well, to get to that point in my game, I had to tell each boulder that gets launched from the weapon how much velocity it needed to reach the enemy side of things. Since each brick in your castle is independent from every other brick, and each weapon is independent as well, the weapons have to target those objects very accurately.
So what did we have and what did we need to figure this out? What we needed is the initial velocity of the boulder so it could reach its target from the angle that it was shot. Unity has a few features that make vector math a little easier. So, what we DO have is distance to the target (on the xz plane), the direction it needs to head, the initial and final height of the boulder, and the angle at which the boulder will be launched…in this case, the ballista’s launch angle is about 30°.
Now that we have determined what we know, we can figure out our initial velocity by using this equation in our code.
So lets see what that looks like:
// Makes for easier readability Vector3 target = parentEntity.GetEntityData().GetTarget().transform.position; Vector3 origin = transform.position; // Pull out our angle float radians = transform.eulerAngles.z * Mathf.Deg2Rad; // First need a direction on xz plane Vector3 direction = new Vector3(target.x, 0, target.z) - new Vector3(origin.x, 0, origin.z); // Now we need to see what the distance is on the x/z plane float distance = direction.magnitude; // Now need to calculate the height on the Y axis for the angle it shoots at direction.y = distance * Mathf.Tan(radians); // We will also need our height offset between the two objects float heightOffset = origin.y - target.y; // Now we need to normalize the direction into a single unit Vector3 normalizedDirection = direction.normalized; // Calculate what our velocity should be float firstPart = 1f / Mathf.Cos(radians); float secondPart = 0.5f * -Physics.gravity.y * Mathf.Pow(distance, 2); float thirdPart = distance * Mathf.Tan(radians) + heightOffset; float initialVelocity = firstPart * Mathf.Sqrt(secondPart / thirdPart); // And apply it to our final velocity Vector3 velocity = normalizedDirection * initialVelocity;
Our “target” variable is the position that the boulder will hit and the “origin” variable is the initial location of the boulder. Direction on the “xz” plane is done pretty easily by creating new Vectors that don’t have a “y” component, then just subtracting them. Like I said, Unity make is pretty easy to do vector math. Does anyone else think of “Dispicable Me” now anytime you hear the word “Vector”? No?
Okay, never mind then, guess it’s just me.
After getting the direction to the target on the xz plane, we can also get the distance by retrieving the magnitude of our direction vector…again, Unity makes this pretty easy. We still do need to calculate the “y” component of the vector so the boulder launches at a 30° angle. We know this because when we attached the boulder to the launch rail, it placed it at that angle. To calculate our launch angle (so it looks like the boulder is leaving the launch rail), we can use (distance * Tan(θ)) to give us the “y” component. So now the direction vector is complete up to this point. One of the last components we need is the height difference between the initial and final locations…that is pretty important considering the boulder doesn’t leave and land on the same height. Taking our origin height and subtracting the target height from it gives us this value. Before we calculate the actual velocity (we’ve only calculated direction up to this point), we need to normalize our direction vector which gives us a unit vector. From there we can use our unit vector and multiply it by the velocity we are about to calculate to give us the final vector in 3D.
I split the velocity function into three parts in my code to make things easier and I could see what the values were as I was debugging the code if needed. The first part is (1/Cos(θ)) in front of the radical, the second part is the numerator under the radical and the third part is the denominator under the radical. Once I had these three parts calculated, I put it all together according to the function and then multiplied it by our unit vector and voila, you have the correct vector needed to apply to the rigid body component of your boulder. Lets see how well it works now…
In this particular test run, the enemy’s weapons have an accuracy of about 48%, that is why some boulders miss and some don’t. It wouldn’t be as exciting if your boulders hit the target every single time!
There is something oddly satisfying about watching a structure being destroyed one brick at a time…
And yes, there WILL be flaming boulders…there WILL be.