Monday, March 18, 2013

Level Building : Level 1

We've had a change in game design.  We're shifting our focus to obstacle course design for our game.  The ninja theme is still intact as the player will still use ninja-esque acrobatics and abilities to complete the courses; however, we have decided to remove the combat elements from our game (i.e. attack abilities and enemy AI).  We made this decision because our deadline is starting to creep up on us, and we need to focus on the elements of our game that we have implemented solidly.  Our platforming elements have been constantly updated and maintained since the beginning of the project, so we decided to polish that mechanic.

That said, we needed to start building levels that suited this change in direction.  Since we have little time left before the project needs to be completed, we decided to assign more people to level design.  I was one such person enlisted for this task which I was agreeable with.  I was excited to roll up my sleeves, and see what I could build given my extensive experience with 3D platforming games.

Fortunately, one of our programmers cooked up a level builder in Unity 3D, so I could place the assets created by our artists with relative ease.  This proved invaluable as I could devote the entirety of my effort towards building levels with good flow, challenging obstacles, and general badassery (oh and secrets too).

After a good day of work, I finished my first level layout.  It was meant to introduce players to the basic abilities they have at their disposal.  Thus, each obstacle is fairly easy, and is made in a way that won't harm the player if he makes a mistake.  I recorded a run through on the windows version (yeah that means you'll have to stare at a block doing these obstacles instead of an avatar).  Here's a preview of my first level (music in the video was also composed by me).




Level Theme

Time for another composition.  I composed this theme to be used in a level. It starts right out at a good pace, and helps the player feel the energy of being a ninja (complete with japanese instrumentation just for that extra ninja touch).

It maintains near constant energy throughout, but modulates slightly during some movements to be either a little slower or a little faster.  This helps give some variety to the piece, but doesn't lose the drive behind it.  I had fun composing this one, so have a listen and enjoy!

Crumbling Platforms

Recently, we've been developing more hazards for our levels.  Thus, I volunteered to create platforms that would crumble after a player steps on them (after a set amount of time after the player touched it).

First, we knew this would be a trigger-able event, so using our trigger system seemed obvious.  There were three important variables to keep track of for this event.  First, the time it takes for the object to crumble after the player lands on it.  Second, the time it takes for the object to fully crumble (i.e. the player can't stand on it any more).  Third, the time it takes for the object to be restored (so the player can try again if he failed).

I handled most of the logic in the update function.  When a crumble trigger event is activated, it sets a crumbling flag.  The update function checks for this flag, and if it is true, it will count down the time it takes for the object to start  crumbling.  Once that timer has elapsed, it will trigger the flag for the object to crumble while disabling the crumbling flag.  The update function works similarly to update the timer until it has elapsed (which will mean the object is no longer valid as a platform).  Finally, the current flag is disabled, and the restore flag is enabled.  Again, the update function will count down; once the restore timer has elapsed, the platform will reform (and, of course, the restore flag is disabled).  The crumbling platform can then be triggered again.

There were a few problems with actually restoring the object again.  I couldn't simply just delete the object when it crumbled, as I had to be able to restore it to its previous position.  Thus, I had to be able to disable and re-enable three aspects of an object.  The actual physics body has to be disabled, so the player wouldn't collide with it.  The display model had to be disabled (or in essence invisible), so the player wouldn't see it.  Finally, the trigger had to be disabled, so it couldn't be tripped pre-maturely.  The display model was easy enough since there was an invisible toggle already implemented, but the other two were a bit more tricky.

In short, I collaborated with a few teammates to write enable/disable booleans for the physics body and trigger.  When enabled, the physics body boolean would add the physics body to the physics engine, and the trigger boolean would simply ignore colliding information.  The reverse is true when the variables are disabled.

With that obstacle out of the way, I had a working crumbling trigger that would destroy a platform after the player stepped on it, and then be restored after a set amount of time.  It works rather well, and am looking forward to seeing it in action in our upcoming levels.

Friday, March 15, 2013

Checkpoints

We have recently been messing with triggers in our levels.  These, aptly named triggers, trigger certain events when a player collides with it.  The types of triggers we currently have are Quest Triggers, Ability Triggers, Killzone Triggers, and Load Model Triggers.  These are all quite important, but we all decided that we also needed a Checkpoint Trigger, so the player wouldn't have to attempt the entire level again if he/she happened to fail.

Thus, I was put on the task.  First, I had to learn about how our trigger system works (since I hadn't designed it).  After some research, I found out how we were handling triggers.  The actual trigger object is what the player collides into.  However, we add, or subscribe, these component-like trigger events to the trigger object.  When the trigger is tripped, all subscribed trigger events will activate.

With that in mind, all I had to create was the checkpoint trigger event. The checkpoint in this game needs to only store the position of the trigger that contains it.  However, the player needs to store the current valid checkpoint, so he/she can reference it when respawning.

Thus, I created a CheckpointTracker component for the player.  It kept track of the current checkpoint, and gave the checkpoint's position coordinates when ReturnToCheckpoint() was called.  I also added a function that kept track of the id number a checkpoint had.  This was implemented to prevent accidental checkpoint regressing; i.e. somehow a player skips a checkpoint, and then hits a further one.  We don't want the player to return to a skipped checkpoint, and suddenly lose progress for it. It's more of a safety precaution, but one that should help minimize such odd circumstances.

With that completed, all I had to do for the checkpoint trigger event was to subscribe it to the owning trigger,  and then supply the position/id number to the CheckpointTracker.  If the id number was greater than the current checkpoint, the supplied position would be registered as the new checkpoint (and the id number will be set to the supplied one).

I've tested out this trigger, and it works fantastically.  I even tested out a circumstance where I skipped a checkpoint and activated one farther away.  I then walked back to the previous one, and killed the avatar.  It spawned correctly at the checkpoint farther in the level, so I'm satisfied with this trigger event.

Inhibitor Component

During my ability creation, several of my ninja abilities affected the enemies' movement.  Thus, I thought it prudent to make a component that controls the owning character's movement speed.

After some discussion, we decided to expand this into a more broad component that affects all aspects of a character's control (movement speed, stunned, frozen, etc).  Thus, we called it the Inhibitor class.

Simply put, this class created flags for each type of inhibitor effect (like movement speed).  When this flag is triggered, the update function will handle the execution of the inhibitor effect for as long as the flag is triggered.  However, each inhibitor effect has a timer that is set when the flag is triggered (which ticks down every time the update function is called).  Once that timer finished, it sets the flag to false.

It's very simple to maintain and call, so I'm quite happy with it.