Trigonometry – the Flame of the Rudiment Rock-it

June 25th, 2014

trigonometry needed

This week I have been thankful that I paid attention and did well in my high school trigonometry class. Sine, Cosine, and Tangent really came in handy when the flames of my rocket in Rudiment Rock-it wanted to do detach themselves and do their own thing.

A Trigonometry Story Problem

It had been a very long time since I used trigonometry for anything. This problem presented itself whilst I was innocently developing a game for drummers who are looking for a fun way to learn some of their basic rudiments. In the game, the player taps each side of their mobile device in the pattern specified. The goal is to perform the pattern correctly and evenly as quickly as possible. If its not even, the rocket will tip and the flames on the side of the inaccurate hand will get smaller. Or if the player is going too slowly the flames will go out altogether and the rocket will not go higher. This gives the player feedback on what they need to fix in order to do better. The problem happened when the rocket rotated and the flames would not come with it.

The flames needed to be programmed separately from the rocket. They needed to act independently of each other to give correct and good looking feedback. Yes, I could have asked my animator to graciously draw 50 versions of a rocket with flames. But that would have been a waste of memory (mobile app) and not an efficient use of his time either. The better solution was to tie the separate flames to the rocket and get better results with less strain on the device. I hesitated when I realized that the answer to tying a rotating image to a part of another rotating image required some very difficult trigonometry. “I know some people who could do this faster,” I thought. But no, I wanted the challenge all to myself.

The Solution

superhuman-trigonometryIf you’re not into actually doing trigonometry with me, now would be the time to check out and go play Rudiment Rock-it. Have fun, we’ll join you in a minute!

The rotation of the flame was easy: flame.rotation = rocket.rotation. If the rocket always stood up straight, the rest would be easy too:

flame.x = rocket.x and flame.y = rocket.y

Oh, but the flame changes length so we need to make an adjustment: flame.y = rocket.y – (flame.length/2)

This ties the top of the flame instead of the middle. But now we need to actually tie the flame to the engine of the rocket (we’ll just do the left one for now):

flame.y = (rocket.y – 26) – (flame.height/2)

flame.x = rocket.x – 7

But what about when the rocket tips? The flame will detach and look silly. And that’s where the trigonometry comes in. First we need to figure out how far away the flame is (the hypotenuse) because this number will not change. x and y will be changing every frame! So x and y need to be based upon the total distance:

7^2 + 26^2 = 26.93

So now we can use a combination of the hypotenuse and the angle of the rocket’s rotation to determine either x or y first. I think it’s easier to think horizontally, so we’ll do x first. We want “flame.x” to equal “-7” when the rocket is straight since the flame should be directly left of the rocket (we’re ignoring y for now). We have to use cosine because x will the adjacent side once the rocket rotates. So since “cos(-90) = 0” and “cosine = adjacent/hypotenuse” we can do this (assuming that flame.x is -7 and rotation is 0):

flame.x/26.93 + 7 = cos(rocket.rotation-90)

flame.x = (cos(rocket.rotation-90) * 26.93) – 7

But we also need flame.x to be “+7” when the rocket is up-side-down. To fix that we need to modify that “-7” in our equation by finding a way to switch it to a positive number when the angle is 180 degrees.  I found this easier to do while thinking of the rotation in 90 degree increments:

flame.x = (cos(rocket.rotation-90) *26.93) + (cos(rocket.rotation)*7)

This way, when the rotation is at 180 degrees, the 7 becomes positive and it’s still negative when the rocket is right-side-up! But now when it on its sides, x should be +/-26 and not the length of the hypotenuse like it is right now. But I really don’t care because it’s not even a whole pixel of difference. Moving on!

We have one more major problem to solve: we still have to compensate for the changing height of the flame. So we modify our hypotenuse because that is the flame’s distance from the rocket. Currently, the middle of the flame is touching the engine. To change that to be the end of the flame, all we do it add half of the length of the flame to the distance from the center of the rocket.

flame.x = ((cos( rocket.rotation -90)*(26.93+( flame.height /2))) – (cos( rocket.rotation )*7))

And of course we should probably add in rocket.x

flame.x = ((cos( rocket.rotation -90)*(26.93+( flame.height /2))) – (cos( rocket.rotation )*7)) + rocket.x

Now for flame.y. Just use sine instead of cosine to find the other axis. Simple as that:

flame.y = ((sin( rocket.rotation -90)*(26.93+( flame.height /2))) – (sin(rocket.rotation)*7)) + rocket.y

Now for the right engine. Just add instead of subtract:trigonometry-flame

flame.x = ((cos( rocket.rotation -90)*(26.93+( flame.height /2))) + (cos( rocket.rotation )*7)) + rocket.x

flame.y = ((sin( rocket.rotation -90)*(26.93+( flame.height /2))) + (sin(rocket.rotation)*7)) + rocket.y

Simple trigonometry, right?


Pick-A-Mode – Bonus Features in Upbeat Bird

June 14th, 2014

I wanted to avoid redundancy in the music produced by Upbeat Bird. On the other hand, I also wanted the music to repeat itself to an extent. When first being introduced to new sounds, the listener needs some time to adjust the idea. But it has to do something eventually. The solution was to change the mode in which the music was being played. But not until the player starts to get the idea of how to play the game well. Since there are seven primary modes to work with, that also leaves plenty of opportunity to give the player goals to aim for as their timing becomes more accurate. Rewards and checkpoints are important parts of good games! Here’s the breakdown of the rewards in Upbeat Bird:

pick-a-mode

Yeah, I rock at this.

  • A high score from 0 to 199 = Ionian (major)
  • 200 to 599 = Mixolydian
  • 600 to 1199 = Lydian
  • 1200 to 1999 = Dorian
  • 2000 to 2999 = Aeolian
  • 3000 to 4199 = Phrygian
  • 4200 to 5599 = Locrian

So what happens when the player exceeds 5599? This opened up another opportunity. After the player has earned every mode, why not let them pick the mode their next game is in? So, at 5,600 points the player gets to have a say in what they’re hearing! Or if the player doesn’t care, the can just pick random.

Programming mode selection

Many people understand modes as scales and stop there. But it’s both simpler and much more complicated at the same time. In short, all I had to do was transpose the base line without changing the bird sounds. Change the lowest note in a song, and you change the mode. And just like that, we magically have seven times the music which develops slowly over time! In reality, it’s much more complicated than that, but you get the idea.

Just like a good piece of music, Upbeat Bird always has something new to offer the listener.

Send Caleb a message!

Blog Subscription

Loading