Monday, March 18, 2013

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.

XBLIG EVIL LIST!

Since we are submitting to the XBLIG arcade, there is a submission process we have to pass for our game to be published.  Fortunately, there exists an already compiled list of oft-checked items that your game has to pass, at the least, to be accepted.

I was assigned to keeping track of what our game has passed, and what needs to be fixed.  Thus, I compiled a list of the items in the checklist, and made a Google doc that would keep tabs on our progress.  Below is the link to this document.

Evil List

I'll also update this post to keep up with the parts I personally fixed for our game.

1. I found that our screen wasn't adapting properly for widescreen/standard size.  This was largely the GUI elements of the game, so I had to go digging into our GUI code.  Fortunately, since we only have to worry about standard and widescreen when it comes to our scaling, I only had to add a scaling factor that was set according the screen mode.  It was a relatively simple fix, and it worked flawlessly.

2. After some testing, I found that a second controller (not the profile logged in for the game) could control the menu screen, but not the actual game if they started it.  This happened to be an evil list item, so I went to work.  Again, this was a GUI issue, as the menu screen needs to keep tabs on what player's input is valid.  Thus, I modified our GUI screens to only accept input from registered controllers (which XNA was all too happy to provide for me).  This was accomplished by simply adding a check in the button input function, so that it would check the current controller's port to the registered ports provided by XNA.