Half-Bit Software

LZRS Postmortem

I’ve been pretty sloppy in the past about recapping when I’ve actually managed to finish something. This is an attempt to be a bit more proactive and a bit less “oh right, I should’ve done that weeks ago” about a project. This time around: LZRS for #lowrezjam2016!

What Is It

LZRS started out due to an interest in the laser section from Mega Man 2. Yes, this whole game is basically just poking and prodding at a single mechanic. Lasers flying across the screen that the player needs to avoid to navigate an environment felt like a decent hook - I mean, clearly, given that a MM game used it!

Because I’m lazy, I tend to throw procedural generation at just about anything I come up with, so in this case, my initial idea from long ago was to make a generator for screens, or levels, or courses, or whatever. This makes total sense, because content takes time to make, but it also creates another problem: now you’ve got to make the thing that actually makes the thing, which can be more work. “Fun” is tricky to algorithmically generate.

And that, sadly, is where the idea sat until a few weeks ago.

What Went Right

  • It finished!

Bear with me, here - for someone chronically late on side projects, actually getting something semi-satisfactory done is a big deal (to me). Having two weeks instead of two days contributed heavily, as did having a general idea before I even knew about the jam. Most of the time, I try to start from the theme, but here the theme is more about a technical limitation, rather than creative. That’s an interesting distinction to me.

  • Platformer

It’s a platformer! Usually people tend to start with these, but not me! I’m not really very good at real-time, actiony games, likely due to lack of experience. It’s pretty exciting to have something finished that plays reasonably well. Collision happens, there’s triggers, stuff goes fwhoosh, and it all seems to behave as I’d expect. (Whether things behave as players expect is another matter entirely.)

  • Reception

People seem to like it! I haven’t woken up to any severed heads in my bed, which I consider a good sign. It’s short enough that most people should be able to finish it, and nobody’s complained about getting bored, either.

What Maybe Kinda Didn’t Go Great

Usually you go with five specifics, but to heck with that. I do what I like

I think most of what I’m unhappy with boils down to one word: incomplete. It’s a jam game, and I was pushing back and forth against what seemed like a good idea to add, and what seemed possible within the remaining time. A few hours a night is an awful lot if you’re driven with a plan, but for exploration, it ends up being a bit trickier. Experimentation is fine but it really helps if you think your new idea is going to bear fruit.

(And before I go too much farther, incomplete is from my perspective as the dude who saw everything it could have been, rather than the players going through the whole thing. Very different perspectives.)

First off, the big mechanic: lasers. Sure, they slide around, or turn themselves on and off, but from a mechanical perspective, they’re kind of lame, aren’t they? There’s no telegraphing, there aren’t any hints about whether they’re going to turn off soon, or even which kind of laser is which! It’s a little lame. They don’t move at different speeds, and they’re not even textured. Tons of work could be done here polishing and improving.

Audio’s one big area that I’m a little disappointed with, and would probably get tackled pretty soon. Just looking at the main spaceman character is a great start: sounds for footsteps, jumps, hard landings, skids - there’s plenty here that I could add to push a bit more depth and feel into things. Heck, just having multiple different sounds for the same type of event would be great for adding feel and juiciness.

This next one’s a bit tricky to explain, but the unfinished-specific umbrella is probably just ‘polish’. I’ve usually got a pretty discerning, ruthless eye about what works, what doesn’t, and what to change. Some of the tiles don’t work quite right, but more importantly, my tiles are all black with alpha. Why care? Well, I can’t really tint them, which makes me kind of bummed out. I like being able to just tweak colors a bit, and if they’re white instead of black, I can muddle with the levels as much as I’d like.

The backgrounds change as you progress through the level, after all, so why not the walls and the environment, too? This was another issue of “things work, so don’t break anything” that kept me from making too many daring changes. The hard deadline both helped and hurt me, bless its heart. Twiddling with the precise color progression for the background would likely be on my list, too, just to make sure it’s exactly what I want.

I’ve been thrilled by people posting their times and death counts and would love to have some kind of global leaderboard for scores. I don’t know that I want to do anything platform-specific, which means either picking something cross-platform or finding an acceptable third-party solution. I haven’t really gotten that far or done any thinking about it yet, but it’d be a great thing to have.

Lastly on this hate train: levels and courses. Courses feels like the right word for the sequence of, uh, ten or eleven laser-filled screens of death. I didn’t even consider it for the scope of the jam because, well, there’s no way to pick a different course on the menu. Duh! Having a bunch of courses with different themes or different mechanics would be really pretty great. Designing the levels wasn’t quite as rough as I was afraid it’d be, and making more of them might be fun.

Final Thoughts ~Brainfarts~

I’m tremendously happy with how things turned out. I’ve been itching to do Ludum Dare for ages, but the 48/72 deadlines are a bit too much for someone with a dearth of time. Having two weeks and a technical restriction made all the difference in the world, and I think going in with an easily-applicable concept helped a ton.

The game even seems pretty fun, which is always a pleasant surprise. The mechanic isn’t mine, but I can claim some of the level design, at the very least. It was a good experience and something I wouldn’t at all mind putting more time into. That alone probably makes this experiment a success.

Luxe Status Bar

Another in a long series of brief tips! If you’d like to hide the status bar on iOS (unconfirmed, so far, for Android), just set fullscreen to true in project.flow. If you want this just for mobile devices, it’s likely easiest to do in config

1
2
3
4
5
override function config(config:luxe.AppConfig) {
  #if mobile
    config.window.fullscreen = true;
  #end
}

Boom! No more status bar!

Target-Action in Luxe

There’s an incredibly common, useful design paradigm called ‘target-action’, one I first encountered on iOS. Basically, you’ve got a button that calls a function when something specific happens: maybe a touch or a drag or something. This is the basis of all of iOS’ user input.

So I thought it’d be handy to recreate something similar using the entity-component model. It’s pretty braindead-simple, but it seems to work okay for my purposes. It’s not quite as powerful as it could be, but given that I’ve already put together a game with it, I figure it’s good enough.

Here’s what the component looks like:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import luxe.Component;
import luxe.Input;

class TargetActionComponent extends Component {
  public var mouse_up_action : Void->Void;

  public function new(?_up_action : Void->Void) {
    super( {name: "targetAction"} );
    mouse_up_action = _up_action;
  }

  override function onmouseup(e:MouseEvent) {
    if(mouse_up_action != null && cast(entity, Sprite).point_inside(e.pos)) {
      mouse_up_action();
    }
  }
}

And here’s what using it might look like:

1
2
var turkey = new Sprite({...});
turkey.add(new TargetActionComponent( function() { trace("I'm a turkey!"); } ));

The neat thing, and something I found pretty useful, is being able to rebind your target actions after creation. That ends up looking something like this:

1
t.get('targetAction').mouse_up_action = function() { trace("Gobble gobble gobble!"); };

The obvious next step is adding more triggers and actions for various input events. Touch events are a good thing to consider, as well as down-events, too - great for juicy, depressable buttons!

Another Luxe Tip

I didn’t expect to write more of these, but here I am! I wanted to document a bit of interesting behavior I found in the process of building/rebuilding a shmup.

I had this cool effect for making a sprite kind of flicker and glow a bit by adding a duplicate and making it expand and contract rapidly. I think the old way in SpriteKit used a parent/child relationship with an SKAction for the animation. In luxe, the way I’m doing it is by attaching a component to the base sprite.

This component is fairly simple. I build a sprite, attach it to its parent via the parent property (so moving it by hand is unnecessary), then add a few animations. I’ve already learned that onremoved() is the right place to do teardown, so I destroy the sprite in there and all’s well, right? Not quite.

The extra wrinkle here is that I’ve got a timer that fires after a few seconds to remove the component. Simple and straightforward - entity.remove('flicker'); - until I tried to run it. There’s a couple of annoying subtle bugs in here that made me sad.

The first is the parent-child relationship built from the sprite. The lifecycle of a sprite is this, during destroy. First, destroy yourself, then loop through and destroy your children. This means I’m double-destroying my flicker sprite! Dangit. The solution? Don’t add it as a child, and manually update position in update().

The second is that timer. See, there’s a problem there, too: what happens if you kill the parent before the timer fires? Everything gets cleaned up properly, but then you try to call entity.remove('flicker') and - boom, again! Dangit. The fix here was to save my scheduled timer and tell it to stop in onremoved(). Both reasonably simple fixes, but real head-scratchers as I was working through the issues. This isn’t even a particularly complicated situation, but making simple mistakes really bit me in the ass.

Little Luxe Tips

I’m not dead! A shock, I know, but between real-life obligations and a decline in my general state of gives-a-crap, my fun little hobby life has suffered in recent months. Shucks.

Doesn’t mean I can’t bounce back, though, right? Spring 2015-ish, I was on the hunt for something new to tinker with, and I found this rad stuff.

First off, a dumb, semi-obvious one. For anyone loading textures in config, using something like config.preload.textures.push({ id:'assets/playershot.png' }); who want nearest neighbor filtering on all of their textures, it’s important to call phoenix.Texture.default_filter = phoenix.Texture.FilterType.nearest; before you load anything. Promise - this’ll make you sad and confused otherwise. Obvious in hindsight and a real forehead-slapper once I figured it out.

Another important thing to note is that someday (soon?) phoenix is going to go away, replaced with embers. The API might look similar, and this might still be relevant, but just something to keep in mind.

I bumped into another forehead-slapper obvious issue with global events and ids. It’s super easy to just Luxe.events.listen('whatever', function() { doRadStuff(); }) - but the gotcha here was not holding onto what listen() returns. Whoopsie. That’s the thing you use later to unlisten to things, ala Luxe.events.unlisten(event_id). The worst part? This is even in the docs! Bad me.

The last tip is going to be a bit of a rambler. Luxe supports the pretty useful entity-component model of design: you’ve got your base entity, and you can lump additional behavior onto it via components, which are small little focused nuggets of goodness. I’m coming from an objc/iOS background, which means that I spotted new, init and destroy and thought, aha! That’s clearly the place to put stuff!

D’oh. Nope. See, the thing you’re attaching your component to isn’t quite ready in new - that’s just for building stuff up. Init, too, is a little early - sure, you’ll be ready, but if you want to add stuff your component after the fact (adding components to an entity returns that built component - handy for twiddling stuff immediately afterwards) - well, onadded is a better place. Teardown is similar, as onremoved happens earlier in the destruction lifecycle than ondestroy.

Slow Jam 1: Technical Postmortem

Yesterday, I posted up some of my recent thoughts and experiences on the last PIGSquad game jam. It went pretty well, and I’m pretty happy with it! This is going to be the big, ugly breakdown of how I actually put the whole thing together.

And just to repeat myself, here’s the page for the game!

What’s a Game?

Some people like to carefully proofread what they write and post on the Great Wide Internetâ„¢. It’s a good philosophy! It leads to quality content (for your braaaand) and, in general, it’s how things ought to be done.

This is not gonna be one of those things. Strap yourselves in, folks, I’m going completely free association, here.

Backing up a step, I’ve been playing around with luxe for the last few weeks, hence the silence. Ludum Dare went Very Poorly, but unfortunately I don’t know the Latin for that. ‘Vilissimo’, sayeth the googles. The sad part is that it’s all stupid emotional nonsense, but that’s not what I’m here to fumble with.

I’ve been building a silly little couch party game for the last few nights - since Friday, come to think of it. Or maybe last Thursday (4/23/2015). The first night, I got a whole level loaded from Tiled! I’ve never done that before, so it was kinda neat to see such quick turnaround. Slowly but surely, I’m learning. Second and third night, all physics, then input. Now I’ve got these neat little marbles that roll around the screen, more or less how I imagined my prototype, way back when. Triggers are hooked up, so I know when things bounce into bad things, and…

Wait. Shoot. I’m forgetting something. The whole, uh, game part of gamedev. This is just fiddling and playing around - valuable, for sure, and certainly when trying to pick up something new and slippery, but I can’t really play this. Games generally have goals, some have scores. Even games with emergent fun, whatever the hell that is, tends to have some kind of structure in place. So far, this is just a toy. Which loops back to why I’m here!

What’s a game, in the kind of base, boiled-down sense? Is it just a set of rules, simple or complex? Pong’s a game, right? At its core, Pong is a game that ends when someone’s lives hit zero. Aha! That means, in my game, I need to keep track of each player, decrement some counter when a particular event happens, and call the game ‘over’ when there’s only one person left standing. Right?

Well, sure. But what if it was a little different? What if there was a flag, and each marble had to steal/knock it away from the other marbles to take it back to their little cubby? How do you structure that? I guess that’s where I’m at. Luxe (bless it) has this pretty common, rad, new-to-me Entity-Component system. I’ve got a Sprite, and I attach Input to it, and bam, it moves. I attach Physics, and shazam, it affects its world, while the world around it affects it. (I’ve combined the two for convenience, but you get the point).

Which, after a whole lot of hot air and sore fingers on my part, leads to the conclusion: are Game Modes for this Dumb Marble Game just components that I can bolt onto…what? Having them attached to the sprites themselves seems a little too low-level, truth be told. What if the game object, the thing that holds the world, and the sprites, and receives the callbacks for collision, is the one I lump this thing onto?

Well, now we’re getting somewhere, aren’t we?

Weekly Update: 4-5-2015

This week was pretty slow. Most of it was spent fiddling and playing around with luxe and trying different things out. It’s going pretty well, and - hilariously enough - my first sample projects are rebuilding old stuff. I’m starting with bullet heck.

Not really pictured, here, are a few of the things I’m still wrapping my head around. Input works pretty well with just the keyboard, but it might take a bit of effort to get playing nicely on mobile. The mothership-esque thing also rotates to face the player, which is neat.

The good news with all of this fiddling is that I think I’ll be ready in two weeks (yikes) for the next Ludum Dare. I’m getting pretty excited!

The other thing I did was play with a few more generators for wallomatic and try to re-integrate the blurring stuff. I found some information about how to do a good blur, so I can at least tell if I’m getting the ‘right’ answer. Still not sure it’ll ship with blur, but at least I’ve got one problem knocked out. Basically, computer blur is dumb, and you’ll end up with black bands, rather than the averaged color. Obviously, this is bad if you want something to look good.

Weekly Update: 3-29-2015

This week I did…stuff? Ostensibly? Mostly just playing around with the pattern wallpaper thing. So far it really doesn’t work very well at all, which is a bit disappointing. The dials and knobs are too fiddly, and I’m not getting results I like, so it’s not looking good for this stupid thing.

Same deal with blur on wallomatic, actually. It’s…good, occasionally? And other times it’s just kind of a blurry mess (obviously) that hurts my eyes. I wanted something, oddly enough, with a lot of banding, but it isn’t really working out very well. Will try twiddling a bit more before giving that feature a swift kick in the teeth.

Which is kind of a funny side-issue on its own. It works pretty well on a few of them, all the time, but a lot of them it just really doesn’t jive. Is it better to not have it at all if it mostly sucks? That’s what I’d think, but what do I know?

Work continues, slowly but surely, on Bullet Heck. I’m doing some of the Game Center nonsense right now, filling out leaderboards and achievements, because every game needs ‘cheevos! I think a lot of the features are pretty much done, until they’re, uh, not. Welcome to gamedev!

Lastly, I’m still playing around with luxe engine/snowkit/whatever the hell. Still neat, and trying to wrap my head around components and entities and how to get everything to be aware of each other and play nice. The list of “things I need to make a game” is probably shorter than I think, and it’s really only the hard things that I need to get worked out.