Blog

HOW TO SUCK AT: Coding


 
FOREWORD:


This is part 2 in a series of awkward devlogs where I talk about the various subsets of game development, and why I suck at at them.

 

Part one (art) is here
 
The modern expectation of a videogame is some software that responds to user input to generate audiovisual feedback.  Even with this barebones description, you have three very distinct fields to grapple with- some kind of coding to tell the computer what to do, some kind of audio skill to generate the sound, and some kind of artistry to generate visual feedback (That’s before getting into all the other hidden soft skills). I have yet to speak to someone who hasn’t at least struggled with one of these. Here’s how I (try) to tackle one of them

 
CODING: WHAT’S THE DEAL?

 

Today’s subject- coding! I suck at it, and you can too! 

The thing about computer games, is the ‘computer’ part can be… tricky. 
Thankfully, we live in a golden age of game engines, no-code tools and other software tools that streamline the process of telling a computer to move jpegs and text around a screen and rotate some meshes. 
Unfortunately, even the friendliest engine won’t take away the problem solving and abstract element of coding, so (as with art) you either need to do that problem solving, or get someone else to think for you.  I’m poor and antisocial, so I’m stuck on the former. 

Let’s have a look at a way we can Suck at Coding, that’s applicable to the majority of engines a typical dev is likely to encounter.

 

CASE STUDY: CODING BIRDS

 

I’m going to assume that if you’ve made it this far, you’ve probably got some familiarity with the basics of writing code, i.e. you know what a variable is, what a function is, and so on.  You might even know that an ‘object’ or a ‘class’ is, which will be the focus here. 

Say we want to develop a game about Birds.  Maybe it’s a platformer (flyyn’), or maybe it’s an artificial life sim (sim earth) or maybe it’s an arcade racer(sonic riders). The details don’t currently matter, just that our game needs Birds, and Birds of lots of types.

So we code our first bird.  

This initial bird is the generic, platonic ideal of a bird for our game.  It is the lowest common denomibird.  It can flap_wings(), peck(), lay_eggs(), sing(), and has .feathers, with a particular feathers.colour. 

 

The platonic ideal of a bird

 


Class Bird{

    Public method flap_wings(){
        Make bird fly
}

    Public method peck(){
        Make bird peck
}

    Public method lay_eggs(){
        Make bird lay eggs
}

    Public method sing(){
        Make bird sing a pretty song
}

Public property feathers = standard bird feathers


}
endclass


Now remember, our game needs lots of birds, so we code our bird in a reproducible way, we make it a Class, or if you’re more fluent in unity, you can think of it as a prefab, or a godot scene or whatever.  In short, we’ve created a blueprint of this bird that we can use to spawn or stamp out as many instances or duplicates of this bird as required.  

Good start- but variety is the spice of life- not only do we want many birds for our game- we want many *types* of birds. 

One way to do this is to re-write the above class again but *slightly differently*.  This is a bad idea! Not only is it an arduous and boring task, it also means if you need to tweak something that applies to all birds, (e.g. make every bird able to roost()) you need to replicate that change through all your many birds.  That’d be boring, and you’d probably make a mistake, and you’d get weird bugs in your game, then you’d be confused and angry. 

The alternative, is to make use of a concept that’s present in many tools and environments called ‘inheritance’. 
Consider the woodpecker-

 

A Woodpecker

 

We want the woodpecker to be like our normal bird, but with a different peck(). We *could* do the following-  

 

Class Woodpecker{

    Public method flap_wings(){
        Make bird fly
}

    Public method peck(){
        Make bird do a strong peck
}

    Public method lay_eggs(){
        Make bird lay eggs
}

    Public method sing(){
        Make bird sing an annoying song
}

Public property feathers = standard bird feathers


}
endclass

 

Or we could do the smart thing:

 

Class Woodpecker isa Bird{

    Public method peck(){
        Make bird do a strong peck
}

    Public method sing(){
        Make bird sing an annoying song
}

}
endclass

 

This is much more compact, and we can clearly and easily see how a Woodpecker is a Bird with different Peck and Sing behaviour (these methods *override* the parent class methods), and the woodpecker inherits all the other bird properties. 
So if you go back to your Bird class and make a change there, your Woodpecker class will see that change too. 
(One of my metrics for good code is ‘how much typing do I need to do? The closer this is to “none at all” the happier I am and the better my code is, usually.)

Not only can you change the existing behaviors, you can add new behaviors to your class too, e.g. 

 

A Stork

 

Class Stork isa Bird{

    Public method swim(){
        Make bird swim in water
}

    Private method deliver_babies(){
        Don’t ask
}

}
endclass

 

The Stork here inherits all the standard Bird behaviour, but can also swim() and deliver_babies() (obvs). 

We have three birds now, but what if we want more? What if we find that lots of our birds are similar to each other? Well, what we can do is take our new inheritance trick and apply it recklessly to all our problems! 

 

Class WaterBird isa Bird{

    Public method swim(){
        Make bird swim in water
}
Endclass

 

A Stork

 

Class Stork isa WaterBird{

    Private method deliver_babies(){
        Don’t ask
}

}
Endclass

 

A gannet

 


Class Gannet isa WaterBird{

    Public method dive(){
        Make bird dive underwater
}

}
endclass

 

Now we’re really happy- we can write code very quickly and efficiently to describe *subclasses* of birds that still do bird things, but also do waterbird things, but also can be extended so different waterbirds have unique or slightly different behaviors.  We can keep doing this forever, creating ever more refined and rarefied categories of avian.  
SURELY NOTHING CAN GO WRONG.

Let’s say that for whatever reason, your game has an ice level.  Birds + Ice = penguins

So we crack out our WaterBird class.  You test the game, and something weird happens.  Your player character startles a huddle of penguins, and they all flap their wings and fly away. Hmm. 

The issue here is the penguin here has inherited the flying behaviour from the waterbird class, which itself has inherited it from the base bird class. So what do we do? We can’t really delete the ‘flap wings’ behaviour from the base bird, but what we could do is override the flap_wings so that it doesn’t do anything. 

Of course, we create a new class, because we want to produce many different types of penguin 

 

Class FlightlessWaterBird isa WaterBird{

    Public method flap_wings(){
        Bird does nothing 
}
Endclass

 

A penguin

 

Class Penguin is a FlightlessWaterBird{

    Public method waddle(){
        Waddle waddle 
}
Endclass

 

Now things are starting to get confusing- can we remember what methods are being overridden? Should we override sing in the penguin class or the flightless waterbird class? 
What if we want to code in ostriches and emus? They’re flightless too- but they cant swim. Do we create a FlightlessNonWaterBird class and override the swimming behaviour? That’s obviously dumb. Or do we create a Flightless class and have penguins inherit from that instead and add swimming to the penguin class? But then we’re duplicating code, which the whole point of this exercise was to avoid. 

This isn’t a unique edge-case problem either- 

Consider the Bat- either we reduplicate the majority of our flying code, or we end up with something like this

 

A Bat

 

Class Bat isa Bird{

    Public method peck(){
        Bats don’t peck
}

    Public method lay_eggs(){
        Bats don’t lay eggs
}

    Public method sing(){
        Do echolocation
}

Public property feathers = leathery wings


}
endclass

 


This is obtuse.  It’ll probably work for a while, but one day you might innocently add a gizzard to your base bird class, and before you know it all your bats are mysteriously eating gravel. 

Fastforward a frustrating bughunting session and you bite the bullet.  Bats are Not Birds, there’s no sensible way to fit them into the Bird class.  So you make a new Mammal base class and a Bat subclass and resentfully duplicate the fly code into the bat class. 

 

Everything is fine until you decide to make a Oceania DLC for your game and you start writing your platypus class

A platypus isn’t a Bird, but it has a beak, a platypus is (enough of) a mammal, but it lays eggs. It also produces milk.  

 

A Platypus


Either you shoehorn your platypus into a class it doesn’t quite fit into, and override and duplicate code to prevent horrendous buggy behaviour, or you create an orphan class that doesn’t inherit from anything of substance and duplicate *all* the code. 

What do you do? 

Firstly, we need to stop using inheritance to solve all of our problems.  
What we do instead, is something we should’ve done a long time ago. Use Composition.   Instead of creating some kind of platonic ideal of a Bird, we break the bird into pieces. 

The bird has wings, so we write a wings class with the fly behaviour
The bird has a beak, so we write a beak class with the beak behaviour
Some birds have swimming behaviour, so we write a swimming module with the swimming behaviour. 
Penguins have flippers so we write a flippers class and have penguin override the bird wings class with a flippers class, if we still want to have some barebones bird class (alternatively, just make a penguin an Animal with Flippers, a Beak, etc, depends on your game) 

Our Bat and Platypus problems disappear too- a Bat has wings, so we can use the Wings class, and we don’t need to re-write our flying code. And so on. 

So what’s the lesson here? 
Favour Composition over Inheritance.  Class inheritance is an extremely powerful tool- present in almost every object oriented framework, but if it’s applied thoughtlessly, you’ll run into interesting, inscrutable bugs. 

Oftentimes it’s better to think of your code not in terms of what it is (inheritance) but what it has (composition), and what it does

You’ll often find this described as duck typing.  If it walks like a duck, quacks like a duck, and swims like a duck- it’s (for all intents and purposes) a duck. 

(haha. Puns) 

You can see these 1337 coding skills in action in both of the games on my itch page. Neither contain any birds whatsoever, only pasta and worms.