Wednesday 26 August 2015

Ludum Dare: Follow up covering nights 2 and 3 and how to succeed in a game jam.

Hello again interwebs!

So Ludum Dare wrapped up last yesterday, and I've been recuperating. Yeah recuperating sounds good. Sounds way more reasonable than failing to write promised blog entries out of laziness.

In all seriousness though, the Ludum Dare Jam was a blast and I'd like to the UVic Gamedev, Techtoria and the game developers of Victoria for hosting the event. And of course, Ludum Dare themselves for giving indies around the world an excuse to get ourselves of our butts and really crank it for a couple days. Events like this are a really great reminder of just how much you can get done in a very short time with a lot of effort and a good team.

Speaking of good teams, I have to especially thank Shane Gordon who provided all the art for this game. (Except the sky, that's Unity's default skybox.) I met Shane when we wound up sitting together in the main presentation room just before the jam started, then we broke off to brainstorm some, by which I mean one, concepts and before you knew it, we were working on a game. Shane provided fantastic pixel art and the right balance of detailed vision and quick stand in work that makes a jam game really work. So yeah, thank you Shane.

Now on to the game itself. I am happy to say this is probably the best game I've produced at a jam so far. I don't think I've been this satisfied since Jubble. The secret to a good jam game is good scoping, and this feels like the best scoped game I've done since Coffee Island Madness. I guess Soup Bubble was scoped well too, but it always felt like it was missing some of the more finishing touches. Coffee Island Madness had multiple end states with proper end screens and exactly as much content as content as I envisioned, where Soup Bubble just reset, including the music, which is a little jarring. Anyway, the new game was definitely better scoped than my previous jam game, What Do We Do Now IN SPACE, which never really had any joy to it. It played in a very static way that randomly changed, but I had so much more that I wanted it to do that the game felt lacking. Not so with this one.

So as I was saying, to succeed in a game jam, you need to figure out a project within the scope of what you can accomplish in a weekend. My game this time around has also solidified, for me at least, the archetypical process by which a successful jam game is created. Let's walk through it shall we?

Night one is the busiest having the biggest set of things that need be done, and the shortest amount of time to do them in. First you need your team. Game jams are experimental, so theres no need to be super discriminate about who you work with. Find someone else who wants to make a game and has a complimentary skill set and get to work. You can decide at the end of the jam if your teammates were helpful or good at their jobs. Nothing is really riding on a game jam, so take a chance and meet some people.

Of course, there are two easy ways to avoid this. Form a team before the jam, or work solo. Both have their drawbacks. As a person who has done the majority of my games solo, I can say with certainty that it's hard. You only have so much time, energy, and useful consciousness, and on top of art, programming, sound, and level design, you also have to add time management to your workload. Most jam teams are small and have instant communication between members that occurs within earshot of the rest of the team, so they effectively manage themselves autonomously. The solo jammer must estimate the time they will need to program every element of the game and still reserve enough time to create the art assets and enough sounds to not feel empty. And there's no winning here. Some part of the game will inevitably lose out to more important tasks.

As for pre-formed teams, this is a bit more of a personal experience thing, but I've found that I learn more and generally get a better project when I work with strangers. For one thing, you are forced to communicate from the get go. People working in a team of friends or co-workers can often have a lot of information that they assume their associates already know leading to misunderstandings later in the process. In a team of strangers, everyone needs to clarify the jobs, goals, responsibilities etc before they break off, because no one can assume anything. Besides that, you can work with your friends any time. Jams offer a kind of combination networking team building exercise that is directly relevant to your work.

The next thing you need on night one is an idea. Best tip here is to be discerning, but not picky. There aren't any hard and fast rules about aesthetics or how well a game matches the theme, so feel free to stretch, what's important is feasibility. You want an idea that will be fun, even if there is only one level, or only one screen. Avoid concepts that are too sophisticated and don't take anything that wouldn't still be fun even if it were only half completed, because, it will only be partially completed. But beyond that, take the first idea that seems doable and run with it. It will almost certainly be more than you can actually deliver, but we will deal with that later.

Now it's time to delegate responsibilities. First figure out your programmer. Every video game needs one. No programming = no interaction = no gameplay = no game. For the first night your, programmer needs to know what they are building, then get to work while the rest is figured out. The next must fill position is the artist. Video games are a visual medium, and you player's main source of information about your game will be sight. Find an artist, give them a rough idea of how the game needs to look, and get them grinding out early stand in assets ASAP, nothing super detailed, just enough to be identifiable.

Every position after that is optional or situational. A sound developer is highly recommended, but not essential. Sound rarely gives the player critical information that isn't also communicated visually, but it greatly enhances the feel of a game. Most games can be played on mute, but the experience is lessened. Sound can also be delayed. I almost always get the sound integrated on the last day of the jam unless I have a dedicated sound person on the team. It's often easier to time share someone who is doing sound for several teams, or to have one of your team members switch to finding or creating sounds after most of their work is done.

Also recommended is a dedicated overall game designer. I usually wind up doing the design as well as the programming on my own games, and consequently have to split my time between developing features, and a combination of testing myself, play testing with others, and parameter tweaking. That's a lot. Ideally, a designer could get a kind of break off build of the game that they could take around for play testing and modify the parameters of, freeing the programmer to create the next feature.

Lastly, level designers and writers. Both of these roles are incredibly optional. Writing and level design are mainstays of a content driven game, which is usually a risky prospect for a jam game. Content is only good if there is enough of it and it often winds up being a black hole that sucks the time and energy away from development. Generally a game that relies on content is a bad idea for a jam. But if you must have content, then it is extremely helpful to have a person dedicated to developing that content and thus freeing up everyone else. Beyond that, minimize the content as much as possible. If your levels need space, then only make one. If your levels are very short, maybe make a handful, but keep it under 5 or so. Everything you add will increase the need for play testing and iteration and those take a while.

So now that you have your team organized, it's time to get a working minimal prototype. The main thing to build is the player's main interaction with the game. If they have a character on screen, build working controls and figure out how the camera moves in relation to them. If there ore objects you need to be able to interact with, put one on the screen and make sure you can interact with it. Nothing has to look good but you should be getting an idea of what your game feels like and wether or not your main interaction is engaging.

Then go to bed. Many people will tell you that the most important resource in a game jam is time. It is not. The most critical resource is useful consciousness, time in which you are rested, focused, driven and capable of doing your task. The key to getting useful consciousness is to sleep. So everything on night one needs to be dome as fast as possible so you can go home and sleep. Generally a game jam starts around 6 with a keynote that takes anywhere from 30 minutes to an hour. this leaves you with about 3-4 hours in which to get an idea, get organized and get a basic prototype before you crash. And that's why night one is the busiest.

So how did my game this jam match with this schedule. Well, the keynote was quick, which is always helpful. As I said earlier, I met my partner for this jam during the keynote and we got to work almost immediately. We had a concept for the game, Jaws from the perspective of the shark, after maybe 5 minutes and a fleshed out idea of the gameplay after about 15 more. And before we headed home at around 10pm we had a prototype that answered the main design questions of the game.

How do you interact with the game? You rotate the shark clockwise or counter clockwise and press space to give yourself some forward momentum.

How does the camera interact with you? It doesn't. The camera is fixed and you cannot escape the screen.

What else is there? Stuff you can eat. That stuff gets destroyed when you collide with it. also stuff you shouldn't eat that hurts you when you collide with it.

Is it fun? Hell yeah! This is the first jam i've had where I actually lost a substantial amount of time because I was too busy playing my own game.

So was it perfect? Not quite. A few things were missing from the night one version. The test fish is static and there's only one, but it's disappearance is still triggered correctly, so there was a skeleton to build the rest of the interaction around. My memory is a touch foggy on wether the walls were in the scene yet and I can't actually tell from the video, but I think they're missing. There's also no enemy, but you wouldn't be able to tell the difference because there's also no health to lose on contact with them. There's probably a bit more development of the visuals than was necessary. Normally, the shark would only need to be a box at this point, but I had never worked with the animation systems in unity to this level of integration, and I wanted to be sure I could do it. What I'm glad we did have  was the movement and the relationship with gravity. All in all though, this was about as good a night one prototype as I've ever had.

So after getting some shut eye, what's next? Day/night two is when the lion's share of your development will happen, so it's mostly just cranking out the features that your game needs. The specifics really depend on what you're making, but in general there are a couple reasonable milestones to aim for. By lunch time, try to have a play testable version. Art can still be boxes, and sounds can still be missing, but be playable and have at least one representative for each thing in your game ie 1 enemy, 1 power up, etc. Have a working version of your UI regardless of how ugly it is. And have the game completable. Be able to go from a start screen to the game play and back again.

In our case, by the middle of the day, we had invisible walls that kept the player on screen, black box fish that moved at a constant speed or in pulses like the player, red box enemies with the same movement patterns as the fish that the player would bounce off of, a random enemy spawning system, a labeled energy bar that increased when you ate a fish and decreased when you hit an enemy, and start screen that explained the controls and transitioned smoothly into the game and back when you died due to loss of energy. I think we also had an oxygen bar, but it didn't do anything yet. Shane had also created most of the assets, but almost nothing had been integrated into the game yet.

By dinner, you should have a clear plan for the rest of your game. You should have enough work to put in now to estimate what you can still develop and what will be too much work. With that in mind, cut a bunch of stuff from your concept and narrow down a few remaining features that are important enough to cram into the game. Here's a quick list of a bunch of things we opted to remove from our game:

- animations of creatures other than the player
- falling nets that slowed the player down, impairing their ability to get oxygen
- a player sprite that changes to match the direction the player is facing so that the shark is never swimming upside down
- depth charges
- edible humans on boats
- complex harpoon spawning patterns

So once you've cut a bunch of stuff, make a short list of things you want in the game by the end of the night. This should include all the features you plan to have in the final version as day 3 should be all about tying up loose ends and polish. Our list was as follows:

- Add the oxygen mechanic (the player loses oxygen while still and regains it when moving)
- Add a third movement pattern which included vertical pulsing or bouncing
- Add boats and divers which spawn harpoon enemies
- Add blood effects and smashed effect for boats
- Add make it so boats have a solid collision area on the bottom and a squishy area up top so they have to be attacked from above
- Add a squid enemy that rotates between forward pulses so that it moves in a way identical to the player
- Start integrating sprites
- Add a score system so players have something to accomplish

And once you have them, blitz them. As with night one, you want to get as much done as you can and then go home and sleep. And note that by this point on day 2, useful consciousness will be running out, so you will almost certainly fall short on your plans. Anything you can't get done, drop or push it till morning 3, but don't leave yourself more than about an hour's work for the last part. You will be very tired and very stressed by that point. Of the items listed, I only got the oxygen system, the bouncing enemies and the divers spawning harpoons to work. I kicked the boats spawning harpoons to the morning because they were just a variant on the divers that I knew could be made easily. I also knew that there would be some programming to add the background tiles, but since that would be accomplished through textbook nested for loops, it was safe to leave until integration time.

At the start of day 3 look over whet you wanted to get done, and what you've accomplished so far. Pick out the easy stuff to do and drop everything else. The time for feature development is pretty much over. Quickly knock off what you keep and move on to debugging, integration and polish.

So as of morning on day 3, I finished off harpoon firing boats and then started integrating Shane's art. This is where I hit the only significant bugs. As I was integrating the art, I had to also fix the collision boxes which had been sized to the early test assets with no real idea how large the final assets would be. Unity scales stuff anyway so we knew we would be able to get a size that worked, I just didn't know what it would be and the collision boxes weren't tied to the image sizes, so they had to be adjusted manually. When I came to the megalodon, the big square jawed enemy shark, I hit an unexpected snag. In Unity, there is no way I have yet found to make hard collision boxes only apply to certain other objects, so an object which would bounce the player would also bounce the walls. But the space between the screen edge and the walls had to be small enough that the player couldn't entirely escape the screen, so there wasn't enough space to fit the giant megalodon. Instead the shark would bounce off the wall and either repeatedly hit it until it stopped moving altogether, or bounced off so hard it made it to the other wall and bounced off of that in a positive feedback loop that only ended when the shark was moving so fast that it clipped through the wall and was destroyed. The only way to avoid this was to make the shark collision box a trigger region instead, meaning that it wouldn't have any solid substance. This created a new problem since the player could trigger the shark again without having left the trigger area yet and it looked sloppy to boot, so the megalodon damage was upgraded to an insta-kill. This way it was still broken, but no one would actually see it.

The other bug was a slight hick-up I created when I added the final assets for energy and oxygen bars. I stupidly entered them as sprites instead of UI images, so they didn't disappear properly with the rest of the game play assets. Because the bars themselves did disappear and the energy and oxygen bars were both mentioned in the instructions, I just opted to leave them that way and move on.

Meanwhile Shane was working on gathering/creating music and sound effects as well as giving the game it's title and creating a cleaner, art style consistent version of the instructions. My memory is a little foggy on the sound, but I think the swim sound and possible the final music were made/found on day 2, though not integrated until day 3.

The last bits of development on my end were programming the toiling of the background assets, adding the crunch effect when a fish or ship got eaten, and value tweaking to differentiate the fish and enemies from each other and make the game more challenging. Everything else got cut including the following:

- a smashed up ship version of the crunch
- boats having different collision areas
- the rotating pulse squid
- the score system

And then it was just a bit of fiddling at the end to get the game properly submitted before I had to leave the jam for another appointment. Day 3 was pretty much textbook, everything either got hastily thrown together or cut and the game that was left was polished to a satisfactory state. And that is how you game jam.

So what went well and what would I want to improve for next time. For me one of the best decisions I made this jam was programming individual behaviours rather than whole operating scripts for both the enemies and the non entity functions of the game like enemy and tile spawning. By separating things into individual behaviours and having most of the scripts driven by public parameters, the scripts could be easily re-used on different enemies with different parameters even if new enemies needed additional behaviours on top of them. For example, the clownfish, fishing boats, constant speed divers and megalodon all move using the same script. The divers and fishing boats each have an additional behaviour on them responsible for spawning harpoons. This is a pretty basic OO technique called composition, but it takes some presence of mind to see the opportunity for it and take advantage of it. Otherwise it's very easy to end up with a player that manages the entire game like I have in What Do We Do Now IN SPACE.

These behaviour scripts were also similar to each other in organization so variations could be easily made by copying and modifying the existing behaviours. The player movement was copied over and tweaked to use RNG rather than keyboard input to create the pulse swimming script, which was in turn copied and modified to create the bouncing script.

Another good decision was separating the random generation of fish and enemies from the selecting their location and direction of travel. The generator only chose which object to create and created it off screen. Each object randomly chose a position, speed and orientation in it's start routine so the parameters for these selections could be specified on each of the object prefabs.

As for improvements, my biggest mistakes were not getting enough sleep, and not looking at the submission system in advance. Almost all the stress at submission time came from figuring out where to host the game and fixing the resolution so it could would appear properly. Even though we got the game submitted on time, anyone playing through the link on the Ludum Dare web page would find that the sides of the screen got clipped off due to the resolution limit and the screen doesn't auto scroll to the centre. I had about 15 minutes to get that to work though, so as soon as what appeared was playable we called it and I was out the door.

Regrets? Well there are a couple things I want to fix. There are a bunch of fully programmed but not tested enemies and targets that I didn't manage to squeeze into the spawning system before submission and I really wand to fox the bar background displays so that the projects don't swim between them and the bar, but my biggest regret is not getting the score system into the game in time. With out it, it feels like the game can be lost, but is can't be won, or even succeeded at on any level other than not dying for a longer time. I'll probably fix these in the coming weeks,  but in the interest of intellectual honesty, I like leaving the jam version in tact as a genuine display of exactly what was accomplished during the game jam. So I'll probably wind up with 2 versions on my website.

For now, you can play that genuine display of game jam awesomeness entitled "The Deep" right here.

That's all for this this post. I hope this has been enlightening. This blog will be going quiet for a little while as I'll be spending all weekend in Seattle for PAX Prime. But when I get back, it will be time for the second part of the Showdown retrospective analysis.

See you there!

Saturday 22 August 2015

Ludum Dare: Night 1

Good evening interwebs.

I gotta keep this one quick.

So the theme this jam is "You are the monster". And what monster is more classic than the mother of all killer sharks, Jaws. So I'm working with an artist I met at the jam on an arcade style game where you are a killer shark, eating all the peoples and trying not to get shot, netted, harpooned, dynamited, devoured, or krakened. You move by pressing forward on the spacebar and using A and D to rotate yourself. Already have the movement working, and it's pretty fun.

Here's a sample:


I'm feeling good about this one. Hopes are high. Will keep you posted.

G'nght!

Thursday 20 August 2015

Showdown Tech 1: Everything's a Square

Hello again interwebs!

So, when I started this blog, I intended it to be a dev blog for Stratagem (Showdown from here on out), but having restarted the game repeatedly and never having been sure what would definitely work and what would get thrown away, I never really shared the ins and outs of what I was creating. It's time I fixed that. So here begins a multi part series about of few of the design decisions and implementation details of Showdown. It won't cover everything, just the suff I think is worth taking the time to write about.

But first I want to summarize the design of the game so it's clear what I was trying to build. Firstly, Showdown is a twist on a turn based game. Rather than each player taking their turn on their turn the way titles like Fire Emblem or Advance Wars are played, in Showdown, both players make a single command for a subset of their units while their opponent does the same in a manner similar to an asynchronous strategy game like Diplomacy. However, the commands are still resolved sequentially, first one player, then the other. In the original specs, each turn would consist of 3 commands from each player, so when the moves were resolved, the computer would resolve player 1 move 1, then player 2 move 1, p1m2, p2m2, p1m3, and lastly p2m3. Since the player who's move is resolved first gets the benefit of knowing the exact position and stat of each unit at the time of the first move, the resolution order alternates each round, so in the second round would go p2m1, p1m1, p2m2, etc.

This alternating turn order is also the game's only uncertainty beyond the RNG in map generation. A move carried out in the same situation will always have the same result. The variable is always the other player's decision, which can be very predictable if you know your opponent well, and wildly unpredictable if you do not.

Another important component of the original design was a variety of units. There were six units in the paper prototype, 2 melee types, 2 archer types, and 2 cavalry types. Each command would only apply to a single unit. This approach evolved into one where units with similar properties could be given similar orders, ie two archers could be told to attack the same target. Since all units could move, movement orders could be given to all units simultaneously, but the set of available orders differed depending on the unit type. Archers had 3 different kinds of shooting orders while cavalry had no ready order. This was a major point of confusion and led to most players only using one unit at a time. Now for the sake of having a very minimal starting point and finishing before my deadline, I wound up only using one type of unit in the prototype, but the solution I'm about to explain works regardless of the unit type, so it doesn't really matter that all the units are the same variety of archer. The design still assumed that there would eventually be more units in the future.

To encourage more co-ordinated movement, I toyed with the idea of a formation orders, a set of orders used in place of individual orders whenever 2 or more units were being commanded. A vague order would be given to a whole group of units and each would unit would respond in its own way. At first it looked like even more complexity, but then I realized that the formation orders could be the only orders so that each unit was defined by the way it responded to each of the orders. This simplified the game in two ways. Firstly there was now no difference between the controlling one unit and controlling 100; the same order applies regardless of the number of units. Second, the pool of possible orders could be reduced to just a handful. In the version on my website, there are 4: move, attack, ready, and none.

With this view of units, individual unit types and capabilities are not nearly as important as a unit's location on the board. All actions have to be carried out in terms of location relative to the selected unit. Hence the design decision that this blog is focused on, everything's a Square.

What do I mean by this? Let's look at an attack order. In most turn based games, a player selects one unit and gives it an exact target. Often this can combine moving and attacking so that a unit moves into range of its target then attacks the unit directly. Attacks are an interaction between units, with location on the board as a limiting factor. Now try to imagine controlling 2 units at the same time with the same command. Movement is simple enough, both units follow the same path, assuming they have the same movement capacity. But which unit do they attack? They can only attack the same unit if they we close enough at the start that they will both be in range of the same target at the end of their movement. Both could attack the same tile relative to their final position, but this can easily cause one unit to have no target. As an interaction between units doesn't make sense.

In Showdown, actions are performed on squares. An attack order consists of a set of selected units and a direction. There is no movement to consider because movement is in a separate order. Each of the selected units sends an attack in the same direction from its current location. Since the action isn't targeted or specified in terms of one unit, it feels perfectly normal to affect an empty square. We've changed the semantics for the player from "shoot him" to "shoot that way", and made it much easier to resolve the results of an attack ord. The key is that an action is an operation on board locations rather than the units themselves.

Let's talk implementation. A Square in Showdown is a basically just a wrapper for a co-ordinate pair, specifying a single space on a 2D grid. We have horizontal and vertical co-ordinates, and the methods necessary to copy and compare them them.

public struct Square{

    public static Square getNullSquare(){
        return new Square(-1,-1);
    }

    public int x { getprivate set; }
    public int y { getprivate set; }

    public Square(int x,int y) : this(){ this.x = x;
        this.y = y;}

    public override bool Equals(object o)
    {
        return o is Square ? Equals((Square)o) : false;
    }
    
    public bool Equals(Square o)
    {
        return x == o.x &&
            y == o.y;
    }    
}


The important part on the implementation side is the relationship between Squares. This is contained in the  idea of a Direction. A Direction is a like a unit vector, containing the x difference and y difference necessary to move to an adjacent Square. A unit will only move one Square in a cycle, so a distance of several Squares is made one step in a Direction at a time. Let's have a look at Direction:

public class Direction{

    public const int NONE=0;
    public const int NORTHEAST=1;
    public const int EAST=2;
    public const int SOUTHEAST=3;
    public const int SOUTH=4;
    public const int SOUTHWEST=5;
    public const int WEST=6;
    public const int NORTHWEST=7;
    public const int NORTH=8;
    
    private int x;
    private int y;
    
    public Direction(int xint y){
        
        this.x = x;
        this.y = y;
    }

    public bool equals(Direction d){
        return x==d.x && y==d.y;
    }

    public int getX(){
        return x;
    }
    
    public int getY(){
        return y;
    }

    public static Direction getDirection(int d){
        switch(d){
        case NONE:
            return new Direction(0,0);
        case NORTHEAST:
            return new Direction(1,1);
        case EAST:
            return new Direction(1,0);
        case SOUTHEAST:
            return new Direction(1,-1);
        case SOUTH:
            return new Direction(0,-1);
        case SOUTHWEST:
            return new Direction(-1,-1);
        case WEST:
            return new Direction(-1,0);
        case NORTHWEST:
            return new Direction(-1,1);
        case NORTH:
            return new Direction(0,1);
        default:
            return null;
        }
    }

    public static string getDirectionString(int d){
        switch(d){
        case NONE:
            return "NONE";
        case NORTHEAST:
            return "NORTHEAST";
        case EAST:
            return "EAST";
        case SOUTHEAST:
            return "SOUTHEAST";
        case SOUTH:
            return "SOUTH";
        case SOUTHWEST:
            return "SOUTHWEST";
        case WEST:
            return "WEST";
        case NORTHWEST:
            return "NORTHWEST";
        case NORTH:
            return "NORTH";
        default:
            //Debug.Log ("undefined direction detected!");
            return "ERROR: NOT A VALID DIRECTION";
        }
    }

    public 
static int invertDirection(int direction){
        if(direction==0)
            return 0;
        else
            return (((direction - 1)+4)%8)+1;  

    }

    public Direction invertDirection(){
        return new Direction(-x, -y);
    }

}

Each Direction contains an x, y pair, but x and y must each be integers in the interval [-1,1]. This guarantees that when applied to a Square, a Direction will specify the change in x and y to reach one of the 8 Squares adjacent to it.

As a quick note, Direction is often specified as an integer that can later be translated into a full Direction when it's time to use it. These integers can be used as a constants, allowing the constant names to be used for I/O which greatly simplifies both writing and debugging. Another great thing about integers is that they can be used for modular arithmetic. This makes it easy to rotate Directions while they're in integer form. Check out the inversion functions. While we can invert a Direction object using this function:

    public Direction invertDirection(){
        return new Direction(-x, -y);
    }

We can also invert it in interval form by rotating it 4 directions ahead like this:

    public static int invertDirection(int direction){
        if(direction==0)
            return 0;
        else
            return (((direction - 1)+4)%8)+1;  

    }


We just have to make sure we ignore the 0 direction and subtract one. Going nowhere backwards is still going nowhere.

So we have a locations, and a way to find one location relative to another, but if there isn't an actual spot containing a unit, it's all for naught. So let's talk about the Board itself. The Board doesn't actually contain any Squares. Instead, it contains a 2D array of GridSlots where each position is specified by an x,y pair, stored in a Square. Early prototypes used a 2D array of GameObjects, but this was changed for two reasons. The first is tied to into how orders are resolved, which I'll be going into in greater detail in a future post. Basically, partway through order resolution, multiple units need to occupy the same space, so a GridSlot can hold multiple units until each unit has found it's final position for the round.

The second reason is a bit of Unity specific abstraction. All of the scripting functions on a unit are located inside one or more MonoBehaviours. To access a function on a unit, one needs to first retrieve the behaviour through a GetComponent<ScriptName>() call. Since every call to a unit must go through a GridSlot, GridSlot provides a home for all of these calls. If the functions of a unit are moved from one behaviour to another, only GridSlot will need to be modified.

So now we have a Board containing a a 2D array of GridSlots. The location of each GridSlot is specified by a unique Square, and you can define a path from any Square to any other Square by listing a series of Directions. Now let's see how an attack order works.

Once again, an order consists of a list of Squares being given the order, and a Direction in which to apply the attack. To get the Squares that are attacked, we look up the unit at the GridSlot and ask for its range. Then we check the GridSlot one Direction from the source Square and check if the GridSlot contains a target to attack. If it does, we apply the attack to that Square, otherwise we step one Direction from that Square and check again until we either find a target or have taken range steps. Now we just repeat this for each square listed in the order, and we're done.

And there we have it, a system for managing attacks from a set of locations in the same relative direction regardless of what units are involved. Notice that we only ask units if they exist and what their range is. For now, all attacks are a straight line, but future versions can allow the unit to return any pattern based on the Direction.

Now the Square based design wasn't perfect. Remember how the original design was going to have each player make 3 orders? Well people who've tried the prototype are probably wondering why each player only gets one order in practice. This is because Squares are also used for selection. In each order, the Square containing the unit is used as the source for the next movement or attack. When creating an order, a player is only allowed to select a Square that contains a unit because the unit is responsible for displaying selection. This also avoids the possibility of assigning orders to an empty Square and the apparent ability of the player to select opposing units or obstacles in addition to their own units.

The problem arrises when movement is considered over multiple orders. If a unit is supposed to move to a Square, but gets blocked by an opposing unit, then the subsequent orders for the unit will find a different unit, or no unit at all, in the place they expect to apply an order to, so the unit will be left sitting there with it's orders failing or being applied to the wrong unit.

There are two ways to solve this: either orders must track units, or empty squares need to be selectable. I'm not sure which one I prefer for this game, but since both required a considerable overhaul of either the board or the selection system and the UI, I opted to reduce the orders per turn to one per player and kick this problem down the road. One order each is also a better place for a minimum viable product to start from for future iteration. There was nothing magical about 3 orders each and 2 or 4 might be better choices. Anyway, this is the top priority among changes to be made in future versions, if and when I get around to making them.

So that's the first look into how I designed and implemented Showdown. Keep an eye open for more of these. I have a lot I want to talk about, but first I need to Jam. This weekend is Ludum Dare, and hopefully I can give daily updates on whatever I wind up making there.

See you there!

Saturday 8 August 2015

Snip Snip!

Oh interwebs!

Did you really think I was going to cheat you out of the big moment?

I would never. Here we go:

BEFORE:



THE BIG MOMENT
AND AFTER

AND JUST FOR REFERENCE

Here's what I looked like around the time I started this blog:


So there it is, 3 years of analysis paralysis, redesigns, reboots, platform changes and painstaking development all in follicle form.


The Long and Short of it

Greetings interwebs!

Well, we've come to it at last. I got rather shy about updating this blog, so this is probably coming completely out of left field, but it's happening all the same.

Stratagem has been released.

I'll give you a bit of background while I let this sink in. The project I was on with my most recent employer was completed a couple months ago, and my employment with it. My next goal is to get into a larger game company, there are several here in Vancouver, but the problem with larger companies is that they often have strict limits on what developers can work on in their free time while under their employ. So with my hair getting problematically long again, and not wanting to keep it for years, I figured I needed to buckle down and crank out a playable version of Stratagem before I went job hunting.

I also want to move on to working on smaller projects. Stratagem has long proven to be a development quagmire because of the sheer amount of work required to make it testable. I want to switch to faster failing projects, the sort of thin that can be testable after a week and released after a month.

With that in mind, I must confess that I've exploited a couple of loopholes in my initial specs of the game. According to the first post on this blog, the state of the game was not part of the pledge, nor the aesthetics, mode of release, or online multiplayer.  Now I didn't abandon the core of the game, but I did scope it down to just a test of the main mechanics. So instead of 6 units, there's only one, a ranged unit since that tests the most annoying cases in the engine. Instead of the original medieval look, it's now a western. Instead of having 3 alternating turns per player per round, there's only one each. There's only hot seat multiplayer and instead of a release on a major platform, it's just a web app appearing on my website. In conclusion:

Stratagem has been released... sort of.

Funny thing is, it's not even called Stratagem. This isn't really a problem since Stratagem was always a working title rather than a final one, and another low budget strategy game was released with a similar title, so I really did need to change it. The new title is Showdown, in keeping with the new western aesthetic. So...

Showdown has been released.

And that's good enough for me right now. A released playable experience is worth a hundred half finished projects, so I'm putting this one in the win column. I hope to come back to it someday and make a vastly superior version, but that will have to wait a while.

As for this blog, well, I don't want to commit to anything yet, but I hope to repurpose it again. Keep your eyes peeled for a 3.0 post. Exactly what the purpose of it will be is kind of dependent on what I'm allowed to do on my own, so I really can't say what that will be.

That's all for now,

I'm Lambwatt, this is day... the last one, and I'm going to find a hairdresser.