QC Dev 001: Ghost Cursor


In Quadrilateral Cowboy, the player can place items in the world.

The player moves around a “ghost cursor” of the item. When the cursor is in a desired position, left-clicking makes the item appear at that spot.

This went through some iteration, and will almost certainly be further tweaked as development continues. Let’s take a look at how it works right now.

Tracelines And You

But first, some terminology: traceline.

In the picture below, I want to figure out what the player is looking at. So, I use a traceline. The traceline would start at the player’s eyeballs, and then shoot forward a very far distance.

placer_traceline

The traceline then spits out a bunch of information. One of these pieces of information is collision: what did the traceline collide with. In this example, the traceline hit the wall, signified by the red circle.

placer_tracelinehit

I examine what the traceline collided with, and now I know what the player is looking at: the wall._ _

Tracelines can do more stuff, but we’ll leave it at that for now.

Bare Necessities

I like to start with the most stupidly easy & simple implementation and then work from there. In this case, the most SE&S implementation is to make the ghost cursor appear X units in front of the player’s eyeballs:

placer_occam

This has some issues:

On The Ground

To address those issues, the next iteration had the ghost cursor snap to ground surfaces. This was done by having two tracelines:

placer_ground

There. Now we have a nifty ghost cursor that snaps to floors, tables, shelves, vanities, curios, whatever old-timey furniture you can throw at it:

placer_ghost2

Done, right? Not quite.

Against the Wall

This is where things break down. If the ghost cursor is positioned near a wall, it’s fine. But once you push it closer to the wall, the ghost cursor ends up lodged into the world:

placer_collide

That’s no good. Halfway into a wall is a highly inappropriate place for any self-respecting ghost cursor. To illustrate, Traceline 1 is hitting the wall, then Traceline 2 is tracing down to the ground, resulting in this awkwardness:

placer_hitwall

Now, we _can_ rely on the player to not place stuff so close to the wall. They’ll learn and get used to it, right?

Yes, they will learn your quirks. But if making your game lean is a goal, then stuff like this is definitely fat. Players have a finite amount of time and energy for you. Everything that goes into the project has to answer one question: is it respecting the player’s goodwill or squandering it?

Wash Rinse Repeat

The problem: the ghost cursor is lodged into the wall. Therefore, the most straight-forward solution would be to move the ghost cursor away from the wall. Let’s start there.

We add an additional check. If the ghost cursor is stuck in geometry, we:

  1. Step 1: Modify Traceline 1 by shortening it by X units.

  2. Step 2: Do the Traceline 2 downward trace. If the ghost cursor is stuck in geometry, stop everything and return to Step 1.

Once the ghost cursor is no longer stuck in geometry, then we know it has found a suitable place. Done!

placer_pullback

That’s where the system is right now. As levels are completed, more gotchas and edge cases appear as the ghost cursor has to contend with increasingly bizarre world geometry.

Et al

There’s something exciting about creating a system and then putting it through its paces. While artistic creativity plays a large part of game development, it also tickles that pleasure center of creating a finely-tuned clockwork machine, brimming with a billion moving parts working in concert with one another.

Then one day your baby is released out into the wild and you hope those billion moving parts don’t violently implode on themselves.

It reminds me of a program I saw on PBS about an off-road racing competition. The catch was: the cars had no drivers, nor were they remote controlled. Robot cars, folks. There was something so exciting and satisfying about seeing these machines have to be ready for whatever one-in-a-million edge case might happen, and gracefully handle it when that edge case inevitably happens ten times in a row.