Wednesday, March 3, 2010

Doodle Blast! - Day 4 - Tweaks and More Flicks

Stats: 52 code files, 4588 lines of code, 2 textures, 20 sounds

Today was mostly about code clean up, bug hunting, and game play tweaks. The gist of the game was more-or-less there, but it wasn’t very playable yet and I wanted to spend some time tweaking details to make the game cuter. I was also starting to get a little tired and I needed to ease off just a touch.

One of the things I played with was flicking from the day before. You could flick the little soldiers into the air, but they looked very boring when they were falling down because I just applied a random rotation to them when they were released. So, I nixed that behavior and instead let them turn to follow the direction of their path, so that when they were falling down, they would do so head-first. And who doesn’t get a kick from seeing little stick figures falling head-first towards the ground???


I used the following method to turn a given sprite in the direction of the moving, underlying cpBody object:
cpVect direction = cpvnormalize(body->v);
float theta = -CC_RADIANS_TO_DEGREES(acosf(direction.x) * (direction.y > 0 ? 1.0f : -1.0f));
float currentAngle = sprite.rotation;
float dTheta = theta - currentAngle;
while (dTheta > 180) dTheta -= 360;
while (dTheta < -180) dTheta += 360;
sprite.rotation += fminf(DIRECTIONAL_MAX_THETA_DELTA, fmaxf(-DIRECTIONAL_MAX_THETA_DELTA, (dTheta * DIRECTIONAL_MOVE_FACTOR)));
Basically, the rotation of the sprite was attempting to conform to the velocity vector, but it did so over time with some easing-in baked in. The constants, in this case, were set to: DIRECTIONAL_MAX_THETA_DELTA = 5 (degrees) and DIRECTIONAL_MOVE_FACTOR = 0.3 (ie. 30%).

You will also notice that there are two types of runners here – the red ones, aka the suicide bombers, which don’t shoot but explode on contact and take away hit points, and the black ones that do shoot but don’t take any hit points when they crash into the tank (incidentally, I stole these pictures from Pop Fizz; that was before the final images were ready). The red peeps also had a count-down over them. Basically, they exploded when the count reached zero. In the final game, I cut that feature because it just polluted the UI and it didn’t really add that much more excitement to the game.

3 comments:

  1. Great piece of code for easing the 'rotation' of the sprite to the vector it is moving with. Forced me to re-learn my old Sin/Cos/Tan trigonemetry knowledge...

    Just in case someone else wonders what's going on in the first two calls:

    - "body->v" contains the vector along which the Chipmunk body (the soldier) is falling. It contains a 'x' and 'y' property that specify the direction, where positive 'x' is 'to the right' and a positive 'y' is 'up' (so NOT down!).

    - "cpvnormalize(body->v)" returns a 'normalized' version of the body's vector. This means, that the normalized vector's 'x' and 'y' properties indicate how much has to be 'travelled' in x and y distance, to travel an exact distance of '1' along the vector's direction.

    - "acosf()" is a function that returns an angle of a normalized(!) vector, given only the 'x' part. When thinking quickly, you could be mistaken to use "asinf()" with the normalized vector's 'y' part, but this is wrong: asin only returns degrees from 0 to 90!

    - "(direction.y > 0 ? 1.0f : -1.0f)" just inverts the result of acosf() when the original vector was travelling down (.y > 0).

    Hope this helps anyone else. If still stuck, try simulating this calculation with some spreadsheet program, I know I did...

    ReplyDelete
  2. That's a great explanation, thank you for sharing.

    I just looked through some of my development notes and about every other page includes a drawing of a right triangle, with trig equations scribbled right next to it. Good ol' geometry. You just can't do without it :)

    ReplyDelete
  3. @Tijn Thanks for the explanation!

    ReplyDelete