Friday, December 16, 2016

Chickens and cows: A tale of collisions and betrayal

 
We'll get to you in a minute, dear cows and baby cows. hang in there!

    One of the first steps of adding livestock to your farm game is to determine how they interact with the Player Character (PC) and among themselves. The difficulty with this aspect of design is the future problems and/or conflicts that will appear because of the path you took. Problems which you didn' t see coming, and for which you come up with a solution that eventually spawns even more problems. To wit:

    1) Let's design chickens in the following way: They are not considered as obstacles, so PCs can pass right through them. Additionally, one can pick them up, carry them around and drop them anywhere! Neat! Only...

    A) How will I display the character holding the chicken up like an item? Oh yes! Items! I will create a dummy item that looks exactly like a chicken! In reality, when players pick up the chicken, it vanishes, and a "chicken item" is created that players immediately get to hold in their hands. Phew! That wasn't so hard!

It's so dense, every single image has so many things going on.

    B) Shit. I pressed the "back" button while holding Chica, and she went straight into my backpack! This isn't right! I can't be running around carrying chickens in my pockets! Why is this happening?!??!?

    C) Ah. Uh. Yes. Chickens become items when you pick them up. This means that all this sophisticated code I wrote for handling items, like putting them in your babackpack, switching them in your quickslots and more, will apply to Chica now.
    While switching from a potato you were just holding to an alive and clucking chicken may land our protagonist a job at the nearest circus, it may complicate things gameplay-wise (not to mention raise a few townsfolk eyebrows). So let's add some extra code to address this issue...

    D) Alright. So players can pick up chickens, who then exist in the newly coded limbo between the Animal and Item realms, and can also put them down, aka throw them like they throw items! The item throwing code already exists. I hit F5 and proceed to begin grabbing and launching chickens around.
    Hmmm. I have coded items so that they can't be thrown "inside" objects that qualify as obstacles. And chickens seem to adhere to this...erm...code. But in some "edge" cases, when I throw them just next to an obstacle, they get stuck in place, apparently their collision mask overlapping with the obstacle. But how? I know thrown items don' t do this. Then how chickens do it?

At least they look comfortable even when half-stuck in a wall.

    E) Ugh. Normally items have a circle around them as a "collision mask". This detects when players are next to them so they can pick them up if they want to. Chickens have this sort of area around them, too.
    When I attempt to throw an item and I want to check if they can potentially end up inside an obstacle, I change this collision mask to a single pixel: I don't need to check this entire circle around them. When the item finally lands, I revert to their previous circle mask. So even if the one half of an apple lands next to a wall, there is enough room for the player to grab it by the other half.
    For chickens, collisions are also checked using this single pixel mask, and if they land right next to, say, a wall, their collision mask is naturally reset to this circle and since it's greater than a single pixel and we're next to the wall, of course they will overlap. For an otherwise immobile item we wouldn't care, but a chicken will try to move and it will fail because it's half-stuck inside a wall. So...let's add some more case checks to fix this.

    All these issues came from the initial decision to treat chickens as things you can carry around. It's not like these glitches were unfixable. It's that it becomes increasingly difficult to foresee how each new system will interact with the existing ones. The less you try to simulate these scenarios in your head, the more patched and hacked your code will end up being. And if you think that chicken handling can be messy, wait till you see our bovine friends in action.

    2) Let's think a thing or two about designing cows! In fact, what will apply to cows will also apply to other animals larger than chicken, like sheep, llamas and velociraptors. It's practically a "large animal" template brainstorming.

    So, cows should count as an obstacle to the player. Chicken are small-ish so there's no big harm if the PC goes right through one, but going through an entire cow makes things look a bit too fake. Even passing through other villagers is acceptable in my book: Walking and passing right by an average bipedal creature is a maneuver that needs no more space than roughly what you occupy while standing. Going around a 4-legged beast can need a bit more maneuvering. So, let's begin creating Obstacle Cows(TM). What can possibly go wrong?

    A) Um...is there a reason you're sitting there without moving at all, mrs. Cow? There something wrong? Would you like some tea?
    Everything seems to be in place. Animation phases, obstacle checking... Aw damn it! A cow is considered an obstacle, right? So when gets to move, it checks for obstacles first, right? Well, guess what obstacle finds first: Itself. For every possible direction. Can you really blame it for not wanting to move? Eh, I guess I'll add the cow's self as an exception to obstacle checking.

    B) Whoah cow wait! Why are you moving inside my PC? Aren't you supposed to check for obstacles??
    Oh, right. My PC doesn't count as an obstacle. So far they would check for other obstacles while moving and they didn't need to be one themselves.

I ran out of fences before completing my super secret message so now I'm holding a potato.
    C) Hmmm. The cow's collision mask is set to a sprite of a circle for all this obstacle fuss. But I need a second collision area around it to be able to interact with it. Chickens were simpler: Their collision mask was also their interaction area. But with cows, you can't "enter" their collision mask because they're considered obstacles. So now I must alter the cow's collision mask to represent this interaction area, and "transfer" the obstacle to another new object following the cow's every move...
    At this point I should probably raise my nitpick shield and state the following: All this fuss about collisions or interactions could probably be dealt with by something as simple as defining a circle radius or two and doing some simple math. I know. But being able to develop and visualize something quickly, which is what a collision sprite can offer, sometimes trumps elegance or minimalism, especially when you don't develop a heavy 3D game with lots and lots of calculations. The way Game Maker: Studio is set up with sprites as collision masks practically begs you to begin prototyping in this way. If the need to save some CPU cycles arises, I will go the math way. But for now I'm good with this approach.

    D) OK. So cows can be kept either inside the barn or outside. You can place fences in your farm and keep your cows inside them. Obviously cows cannot go through fences. That would defeat the purpose of the fence, right? But, when outside, cows can only be fed when there is a patch of fully grown grass available on your farm. So now that fences are in the game and cows can be constrained to a particular area of the farm, how will the program tell if a cow has access to a grass patch when it performs said check when the PC goes to sleep?

Will the cow manage to reach the grass? The plot thickens!! (hint: no it won't)

    This is the precise point where you shut your eyes, take a deep breath and wonder why you didn't decide to develop a toaster simulator. It could end up on Steam, after all!
    A first thought was to run a pathfinfing algorithm from each outdoors cow to every patch of grass on the farm. But that's way too heavy for the CPU, especially for a program like GM: S where your code isn't compiled to zeroes and ones (unless you own the YoYo Compiler). For example, if you have 10 animals and 10 patches of grass whose locations would be pre-cached, the pathfinding algorithm  would run 100 times on a 57x30 grid!
    A more elegant solution is to use a flood fill algorithm starting from each animal. "Flooded" tiles are stored to their respective group. So if you have a 4x4 enclosed space somewhere in your farm and a 5x5 enclosed space somewhere else in your farm, the algorithm will generate 2 groups: the first will contain the 16 tiles of the first group and the second the 25 tiles of the second. Worst case scenario, if you don't have any fences placed, the entire farm is flooded, but this will happen only once: Each subsequent animal can tell if it already stands in a flooded space.

    At this point I'm going to stop listing the avalanche of issues to tackle with animals. We haven't even scratched the surface yet: Can you push them around? What if the PC gets stuck among them? How are they randomly placed around the barn? The list goes on and on and on.
    Granted, so far I 've managed to resolve all of the above (I think. I need to test it more- hey you! Yes, you, who are reading this article now! How would you like some testing? Drop a comment on how to reach you! Thanks!). But it requires lots and lots of thinking, and also revisiting parts of the game you thought you were done with.

    At least the animal infrastructure is ready. And my cows look sexy. Onwards! And, GM:S users, always remember: Queues and stacks, are your spear and axe! (sorry I couldn't help it)


3 comments:

  1. Wonderful article, I'd love to test it for you! I have a special request though -- is it possible for an account/copy for my wife as well? I know she'd love to be able to play a game with me that I've never played before for the first time, and I feel like yours may be just right!
    Best wishes,
    Brandon
    brandon.boyd@axxesslimited.com

    ReplyDelete
  2. Ahh the joys of game development. Great article! You had me at the potatoes part, this really opens my eyes though to the different bugs that could occur (From a RPG Maker User now coming to Game Maker, some of the issues faced are quite different which is interesting)
    I'll be happy to help you test out your game, and provide any feedback. Although I'm quite new to Game maker I do have some prior game development experience.
    I hope I can help you with testing, as always keep up your awesome work.
    Cheers,
    Tartelii
    You can contact me via:
    tartelii.art@gmail.com or supereliz@gmail.com

    ReplyDelete
  3. Hey! Fellow game developer here, and I love following blogs of other small time developers like you and me, and plan on starting a blog of my own soon. I used to use GameMaker for a few years before eventually moving onto java, so I can imagine exactly the sort of obstacles and methods you deal with. I love the concept of the game as someone who grew up with harvest moon, and would love a chance to play it and help playtest it for you!


    If interested, alex_schacher@hotmail.com

    ReplyDelete