Monday, May 27, 2013

An Explosive Update: Melon Bombs

Okay, I added a cool new item to the game, the Melon Bomb.

The artist promises not everything will have skulls on it. But come on, it's a bomb.

BUT before I get to that and the accompanying video, I just wanted to point out that Super Obelisk is 100%  rendered in OpenGL now. I have nothing but praise for the folks behind SlimDX, but in the end I wanted to open up the potential for ports to Mac/Linux, and consoles. The game feels best with a gamepad, so the push to consoles is a pretty attractive prospect.

Anyway, I'm using OpenTK now, which is a framework that includes C# bindings to OpenGL. This, combined with Mono (cross-platform implementation of C#/.Net) should make the porting process smooth.

So, yeah, that took a bit of time, since I haven't touched OpenGL in many years, but overall it was a pleasant experience. I was pretty eager to get back into developing something concrete after getting things back to where they were, so I thought up the Melon Bomb, which is a bomb that happens to look like a melon.

You can lay the bomb down. You can toss the bomb in front of you. Or, you can charge up a throw and launch it across the screen at your enemies! But why read about it when you can watch it all in action? As always, here's this weeks video. As always, best to open it up and put it in HD with annotations on, since they explain what's actually happening.

No new infrastructure was required for the bomb update--just a new behavior and a new graphic asset. That's a good sign--that means engine development is slowing down and game implementation is speeding up!

Until next time!

Sunday, May 19, 2013

Framework conversion

Unfortunately there's nothing fun to show this week, because I'm doing a conversion of my graphics engine from SlimDX to OpenTK--under the hood, this means Super Obelisk will use OpenGL instead of DirectX. 

The reason I'm doing this now is to ease the process of potential porting. Thanks to the efforts of the folks behind Mono, I can continue to write the game in the language I love, C#, and still have the ability to port to Mac, Linux, and whatever other platforms (consoles, handheld) can run Mono. The problem is that DirectX is not supported on these platforms, and OpenGL is. I selected OpenTK based on the fact that it's what MonoGame uses.

I haven't used OpenGL in many years (since college), and even then, my experience with it was fairly trivial, so I've been spending the last couple days learning the ropes. And by the 'ropes', I mean things like this:

Super Obelisk: Now a game about a lonely cube in a strange world

I'm a bit further along than that now and I'm ready to actually convert my codebase to the new framework, so that's what I'll be doing today.

Sunday, May 12, 2013

Rain and the Blob Enemy

Welcome back! I have a lot of neat things to show off this week! Video is at the end of the post if you want to skip straight to that.

1. First up is a Rain Effect. This actually required very new little new engine infrastructure to create. I had to implement Texture Offset to actually animate the rain. Instead of using particles for the individual falling drops, it's just a big rain texture repeated over and over and shifted every frame to create the illusion of falling rain. The video at the end of this post shows the evolution of the rain effect.

It's rainy

2. The return of the Fade Transition. You might remember from previous videos that this had existed at one point, but I lost it in the infrastructure conversion (Lua --> C#). You can see the fade transition in the video about halfway through, when I enter the temple.

3. A Blob Enemy. I don't have a name for this thing yet, so let's just call it Blob. Look at it. Look at that thing chomp.

Okay, so the source material is pretty cool. But this enemy represents a key development milestone: this is a real enemy with real behaviors. 

Generally my engine development pattern is to attempt to make realistic game scenarios and use them to discover what the engine still needs to make them work. There's a popular saying in game development circles: make games, not engines. This doesn't really mean that you shouldn't make an engine, but it does mean that you shouldn't make an engine in a vacuum--that is, an engine without test cases to drive it will probably end up being useless when it comes to practical application.

So, anyway, back to the blob. The blob has a more complex state machine than the previous demo enemies (spike, ghost) I've created. This led to some issues where state management was difficult when states were interrupted and various animations hadn't completed yet. For example, when you get near a blob, it compresses before jumping at you. If you hit it during this animation, it gets sent into another state (knockback) before the animation completes. These effects are achieved with entity controllers, as shown in a previous blog post. After the compression effect of the blob, it has a command that sends it into an 'jumping' state. We don't want this to run anymore if the blob was interrupted by an attack (and sent into the knockback state). To solve this, I introduced state-local controllers. That is, they are controllers that are discarded if the state changes, since they're 'owned' by the current state. This makes for a much cleaner programming model.

This is sort of hard to explain without code examples, so look for a post later in the week which shows the blob source code with an explanation of how it works.

4. Hue Shift

In the video, you'll see the blob flash colors when it's hit. This is actually done with a pixel shader that shifts the hue of the entity, rather than attempted to just change the color of the vertices (which doesn't work--a green image with red vertices appears black).

Hue shifting the blob

Anyway, here's the video. Enjoy! Recommended HD/fullscreen/annotations on.

Saturday, May 4, 2013

Adding Player Health

Video is at the very end of the post in case you want to skip straight to it.

Two posts ago I introduced a new Screen Management architecture that I had implemented. Currently, Entity state can be easily managed and manipulated by using Behaviors. Additionally, Sections can be created and destroyed (and rendered at the same time, with different cameras). But what if two Sections need to communicate to each other? For example, Player Health is something that both the game screen (so enemies can reduce it) and the HUD screen (so it can be displayed) need to know about!

Both 'Sections' need to know about a shared variable, Health.

Entities are local to a section and shouldn't be passed around, so we don't really want to use a behavior attached to an entity to do our work.

One option is to use a Global state object of some sort. But that's no good, because globals are generally difficult to manage and lead to poor design. For example, if I wanted to load a game, I'd have to manually implement a 'reset' on the game state. With proper object management, I should be able to just toss out the existing game state and replace it with a fresh one. In addition, a global state would imply nonsensical designs where you could access the player's health from the title screen. So, no to globals.

Another option is to tie a Game Model (this can be any object you want) to a Section, but allow the model to be shared across sections. This is the design I ended up implementing. Here is an example of how the main game might be set up with a shared model:

The code that sets up a simple shared Game Model

Once this is done, Behaviors can access the Game Model. For the sake of convenience, I've decided to introduce a base class for behaviors that belong in-game (as opposed to, say, stuff on a start-up screen). Here is a sample (and simple) usage:

Highlighted is the code that makes the player lose health. Simple!

Note that I've added a 'damage amount' variable to the 'DamagePlayer' trigger. So now what? Well, I've created some Hearts that live in the HUD Section. Each Heart has an update method that polls the game model to determine how it should be displayed. For example, if the current health is 5, and the heart is the 7th heart, the heart should be invisible. If the current health is 5.5, and the heart is the 6th heart, then we'd show a partial heart (for the sake of simplicity, I just draw it at half-scale).

The player has 5.5 health remaining

As always, there is a fun little video of everything in action. Some notes:
  • As a demo of both subtracting and adding health, I've added a simple little ghost enemy that does damage proportional to its size and little heart pickups. The ghost in the first room does 1 damage, the bigger ghosts do 2.5 damage. The heart pickups restore 1 health.
  • The model caps the player's health at 8 for this demo. You can see that additional heart pickups, once full, don't give the player more health.
  • I'll be adding game music to the videos just for flavor. This is being played through the game's audio engine, which I added recently (it wasn't worth a blog post--it's pretty simple for now). Of course, once I get my own music I'll be using that!
  • The ghost enemy is just a demo whipped up in a few minutes, nothing necessarily permanent. True enemy design will come at a later phase.
  • I had to re-implement section transitions after changing from Lua to pure C#, but hadn't gotten around to actually doing it until this week. 
Anyway, the video. Enjoy!