Sometimes Simpler is Better

Today I’m going to take a quick break from all of the computer science stuff to talk about game design. Developing Roggle has been a huge learning experience for me, so I thought I’d share a little bit of what I’ve picked up along the way. In my original vision, Roggle had five physical weapon types and five magic weapon types. Physical weapons could be Blade, Pole, Blunt, Ranged, or Unarmed, while magical weapons could be Arcane, Willpower, Death, Manipulation, or Elemental.

You had stats measuring your proficiency with each of those skills. On paper it sounds OK. Here’s what that looked like in-game:

Old Menu

That’s a lot of bars. Weapons could also be multiple types, so a Fire Bow might give you experience in both Ranged and Elemental. I thought that combining this many stats with weapons that took their effectiveness from multiple categories would result in depth. After playing the game like this for a while, I realized it wasn’t rewarding me for specializing- it was punishing me for branching out. In a game built around constructing a skill-set out of different equipment combinations, this was working directly against my design goals.

I wanted the player to gradually get better at using specific weapons and abilities, but not lock them out of other options if they find something better. So, instead of having ten different weapon skill stats, I reduced it to three. To make up for the lost variety, I gave abilities themselves stats too- these are Affinities. Now, an ability could be aligned with Mind, Body, or Soul. Weapons can be Melee, Ranged, or Magic. Any action you perform draws from two of these stats. Here’s what the updated status screen looks like:

Final Menu

Now if you rely on a specific ability type or style of play, switching equipment will at most only affect one of the two stats considered- Fireball is always going to benefit from a high Mind stat, while Smite will always benefit from Soul. Switching weapons may give you a smaller, temporary setback, but you will quickly gain the Skill levels in the new weapon to compensate.

By switching from a large number of independent stats to a smaller number of interconnected stats, equipment choice is suddenly a much more interesting decision. Making this change has me looking at every other game mechanic to see if any fat can be trimmed.  If you’re interested in hearing more about Roggle‘s development, follow my development blog at devblog.dangermomentum.com or twitter. Thanks for reading!

CS101: Pass by Value and Pass by Reference

Part 7! This will be a short one. I didn’t elaborate on the difference between pass by reference and pass by value when I wrote about methods, but it’s worth revisiting. Code speaks louder than words here:

Running this will output:

Well that seems odd. We gave the method both our object and our integer, the method sets both to 0, and only the object is affected? That’s right, because primitives are always passed by value. Pass by value means that when a primitive variable is passed as an argument, we aren’t passing the variable itself- we’re passing its value.

You can think of it as Java looking at the variable, writing its value on a post-it note, and passing that note over to the method, where the method does whatever it does. Since the method just has the post-it, scribbling on the note has no effect on the variables original value.

Objects, on the other hand, are passed by reference. When you pass an object to a method, you’re passing the object itself, not just its value. Since an object can contain other objects and primitives, it’d be difficult to copy every time you pass one as an argument. If you’re familiar with C++, this is how pointers work; they’re just references to objects or variables.

There’s one more point worth covering here; Immutable Types. An immutable type is a class that, once instantiated, cannot change any of its values. There isn’t a keyword or anything for this in Java, it’s simply something that can be enforced by carefully designing your class. Immutable types tend to act more like primitive types, because any changes you make aren’t actually changing the object you passed in- they’re instantiating a new object of the same type with the new value you gave it. This happens behind the scenes thanks to a magic Java feature called autoboxing. Examples of immutable types in Java are String and the class versions of primitives- Integer, Boolean, Character, etc. As a rule of thumb, you can just treat these like they are pass by value and things will work as you expect.

Hopefully this cleared up some of the details of how methods do their thing; Thanks for reading!

CS101: Object Oriented Programming

Wow, we’re up to part 6. I suppose it’s time to talk about why we’re doing all of this, huh? Sometimes computer science is a little more art than science. Can’t we just put all of our code in one class? I mean, I wrote it, I’ll remember what it does. This all seems like a lot of effort for something that just works the same in the end, doesn’t it?

Ok, I have to stop. It was physically painful writing that. All of this stuff about classes and objects and inheritance is really really powerful, but with great power comes great responsibility. You are responsible for ensuring that your program doesn’t become a writhing pile of spaghetti code. In case you’ve never heard the term spaghetti code, Urban Dictionary has a fantastic definition:

In computer programming, code that is poorly structured and which makes it hard to update because of multiple undocumented and unexpected links/dependencies. You touch it in one place and you see other things get broken or modified in an unexpected way. Just like sticky spaghetti – you pull one end and you see a number of places start moving.

Alternatively:

Horrible, horrible, horrible code, but still (usually) fulfills it’s intended purpose. The English equivalent would be “I is go store buy vodka drink drunk sergawsdawq zzzzzz uuuugh talk loud”. It is completely screwed up in almost every way, but you still know it meant “I am going to the store. I will buy vodka. I will drink. I will get drunk. I will babble incessantly. I will pass out on the couch. I will wake up, go to work, and complain about my hangover.”

That about sums it up. If you write spaghetti code, your coworkers will hate you, your dog will hate you, and you’ll hate yourself when you have to go back and make a change in a few months. It may seem like I’m blowing this out of proportion, but it’s only because there’s an easy solution to this. It’s a pair of concepts called abstraction and encapsulation.

Abstraction is something you do every day. When you get to your car to drive to work, you don’t think “I need to make my car door open,  but it’s locked. I guess the most direct way to unlock it would be to shove a coat hanger into the window and pull the locking mechanism, because that’s what’s preventing me from entering my car. Alright, time to get the engine running. I’ll pump some fuel into the engine by hand. Hm, but the spark plugs need power too. I have an extension cord I could use…”

Obviously you would just click the unlock button on your keychain, hop in the car, turn the ignition and get on your way. That’s because you abstracted the function of your car to something as simple as “Push the gas and it goes forward.” This is exactly how your code should work.

Whoever uses your classes, even if its you, should not need to know how they work to know how they are used. This is where the modifiers public and private come in. To review, anything declared as private can only be seen and used by the class itself. Anything declared as public can be accessed and used by anything that has a reference to that object. That could get dangerous really fast; make something public that shouldn’t be exposed and I guarantee you’ll have someone reaching into the back of the TV to change the channel when you’ve already given them a perfectly good remote control. That person may even be you, if you’re not diligent in applying this.

The process of hiding the internal workings of a class behind abstraction is called encapsulation. Your class designs need to be fully encapsulated; make sure they can’t be broken by the user incorrectly using your public methods. By managing all input and output from your classes with carefully chosen public methods, your code will be easier to maintain, debug, and read. You will be able to track down problems faster and prevent unimaginable frustration. To end this post, I’ll leave a quote here from a pretty smart guy explaining this concept:

Objects are like people. They’re living, breathing things that have knowledge inside them about how to do things and have memory inside them so they can remember things. And rather than interacting with them at a very low level, you interact with them at a very high level of abstraction, like we’re doing right here.
Here’s an example: If I’m your laundry object, you can give me your dirty clothes and send me a message that says, “Can you get my clothes laundered, please.” I happen to know where the best laundry place in San Francisco is. And I speak English, and I have dollars in my pockets. So I go out and hail a taxicab and tell the driver to take me to this place in San Francisco. I go get your clothes laundered, I jump back in the cab, I get back here. I give you your clean clothes and say, “Here are your clean clothes.”
You have no idea how I did that. You have no knowledge of the laundry place. Maybe you speak French, and you can’t even hail a taxi. You can’t pay for one, you don’t have dollars in your pocket. Yet I knew how to do all of that. And you didn’t have to know any of it. All that complexity was hidden inside of me, and we were able to interact at a very high level of abstraction. That’s what objects are. They encapsulate complexity, and the interfaces to that complexity are high level.

Steve Jobs

Next post: Pass by Value and Pass by Reference

CS101: Inheritance and Polymorphism

Welcome to part 5 of CS101: Inheritance. We’ve made some good progress covering classes and objects. It’s time to explore one of their most useful features, inheritance. As we covered in the last post, methods are a great way to reuse code. Reusing code is fantastic- instead of building a feature or system from scratch every time you begin, you can Lego-together existing methods and objects into new functionality. There’s no need to reinvent the wheel every time you need to sort a list, pathfind, or do any other task that’s common to multiple parts of your program. But what if two classes need to share a method? Maybe you have a HealthPotion that needs to restore health to any character in your game, whether they’re a Warrior, a Wizard, or a Goblin. Instead of writing a different giveHP() method for each class, we can use inheritance to give them shared behavior. A diagram should help:

inheritance_diagram_1

As shown in this diagram, a Wizard is a Unit. So are Warrior and Goblin. These three classes are now subclasses of Unit. That makes Unit their superclass. You’ll also hear people use the terms child class and parent class. Anything that is present in the superclass can be used in the child class. If you have the same method declaration in the parent class and the child class, the child class overrides the superclass method. That’s what our act()  method does. This means we can start with a generalized class, like our Unit class, and extend it into more specific subclasses. You merely tell an object to act() , and it will perform the appropriate method depending on which subclass it was instantiated from. Radical! Code, as always, will make this clearer:

Phew, that was a lot. Here’s what this outputs:

When we call act() , Java is smart enough to know what class it was originally instantiated from and calls the appropriate method. Not only that, but did you notice the type we declared for each character? They were all declared as Unit. But player isn’t a Unit, it’s a Warrior! That’s the beauty of inheritance- variables declared as a superclass can contain any subclass. Read that again if this is new to you, it’s important. This is called polymorphism. Not to be confused with the magic card, polymorphism is an object’s ability to have more than one is a relationship. As we mentioned up top, our enemy object is a Goblin, but it also is a Unit. That’s huge! It’s simultaneously the entire basis of Object Oriented Programming and a loaded gun to shoot yourself in the foot with repeatedly.

Before we move on, I should also mention the new keywords that showed up in our program, extendsabstract and super. A class that extends another class is a subclass. A method marked as abstract has no implementation. Instead of being followed by brackets, we end it with a semicolon. Abstract methods can only exist in abstract classes. An abstract class cannot be instantiated; it can only be extended. It’s used as a common origin for subclasses that have similar or shared behavior. The keyword super just refers to the superclass. In this case, we use it to call the constructor of the superclass.

We’ve covered most of the “how” of Object Oriented Programming now, which means it’s time to talk about the why. Join me next time when we talk about treating objects like people.

Next post: Object Oriented Programming

CS101: Methods

Welcome to part 4 of CS101: Methods. You’ve seen one of these already- that ugly line called main in the previous article. You’ve probably figured this out, but a method is just a way of grouping a whole bunch of code together and giving it a name. Then, next time you need to perform that same task, you can just use the method instead of repeating your code. Neato. A simple concept, but looking at real code always helps. Let’s keep building our Warrior example from last time.

Well look at that, our program cleaned up a lot! By putting code that would otherwise be duplicated into methods we can make our code significantly easier to both read and use. You may have noticed the  public void  in front of our method. The first word is a modifier, which sets where we can access this method from. Public and private are the ones you’ll see the most. Public means it can be accessed from anywhere. Private means it can only be accessed inside of that class. We can use these on variables declarations, too. Void is our return type. See, methods can be used to calculate a value or result; we call that the return value. Void simply means we aren’t returning anything. Any type can be used instead of void as long as you include a matching return statement.

Then we have those empty parenthesis at the end. Methods can take in arguments to change how they behave. An argument is a value or object that we pass in to a method. You can already see this in our main method, although we never use the value we pass in. Arguments are listed first by type and then by name, separated with a comma if there are more than one.

Last time, we ended with a mention of constructors. A constructor is a method that is called automatically when an object is instantiated. It looks like this:

Even neater! As you can see, constructors use the parenthesis after the class name to pass in arguments. You’ll also notice that since we no longer need to set our variables outside of the class, I’ve made them private. When designing your classes, pay very careful attention to what you leave accessible to the outside. They should be a bit of a black box- other parts of your program know how to use them, but don’t know or care how they work. When classes start relying on each other to function, you are on the dangerous road to spaghetti code.

That’s it for today! Next time, we’ll start getting into the real meat of classes and objects- inheritance and polymorphism.

Next Post: Inheritance and Polymorphism

CS101: Objects

Welcome to part 3 of CS101: Objects. So far we’ve mentioned objects quite a bit. We learned in the first lesson that an object is a collection of primitive types, methods, and other objects. Then we learned that objects require a blueprint, called a class, to declare what an object contains. We’re finally ready to start instantiating some objects! Last time, we created a class called Warrior. Let’s look at that again, this time with a little more context:

Whoa, lots of new stuff! This is pretty much a complete Java program, now. Let’s break this down and see what it does. The first thing you’ve probably noticed is that we added a second class, and our existing class is inside of it. Just like classes can contain variables and methods, they can also contain other class declarations. In fact, your entire Java program is really just a set of nested classes. So where does your code begin executing? The Java VM knows about a special method called main, and that’s our entry point. A Java program’s main method always looks like this:

Don’t worry too much about the public static part, we’ll come back around to that. Just know that this method is special, because Java says so. Your program starts here. Now we’ve finally reached our object instantiation.

This is pretty similar to declaring and initializing a primitive type, right? We start with our type, Warrior, which is the same as the name of our class. That’s how we use our blueprint. We name this object  player , and we set it equal to new Warrior() . The new operator creates an instance of an object. This is a powerful aspect of objects; you can create more of them. Understanding the difference between a class and an object instance is very important. Here’s an example:

If we run this program, it outputs:

Pretty simple stuff. As you can see, changing hp or name in one object does not affect the other object. But isn’t it a pain typing out a whole line to change each variable? There has to be a better way! There is, and it’s called a constructor. A constructor is a method that runs automatically when an object is instantiated. Before we get into constructors, though, it will be helpful to review methods in general. There’s a lot to cover, so constructors and methods will be the next step in our Java journey. Until next time!

Next post: Methods

CS101: Classes

Welcome to part 2 of CS101: Classes. Last time we looked at what a variable is, and briefly introduced the idea of primitive types. The existence of primitive types implies there’s another kind of type, right? They’re called composite types, but nobody calls them that; in Java they’re just objects. An object is a collection of primitive types, other objects, and methods. Most objects have a name, which is used when you want to instantiate a new one. To instantiate an object is a fancy way to say make a new one. You see, with primitive types, Java already knows that int means “this variable is an integer”. For objects, we need a blueprint to tell Java “Hey, I need a thing made up of some numbers, a string, and these methods.” That blueprint is called a class. Let’s look at some actual code:

Here we have a simple class declaration. Our first line starts in a very similar manner to our variable declaration from last time. We have our type and name, but unlike last time, no assignment operator (that’s what we call an equals sign). Instead, we have brackets. These represent the start of a new scope. We’ll talk about scope more later, but for now just know that its a chunk of code that is separate from its surroundings. Also note the lack of a semicolon. For the most part in Java, you only use semicolons when a statement doesn’t start a new scope (marked by brackets).

Alright, so that just leaves the stuff inside our class. Our Warrior class has two integers, representing the warrior’s health points and strength, and a string for their name. A string is technically not a primitive type, but it’s a kind of object that Java allows us to use as if it were. As you can tell from the example, a string is just an object that holds some text. By putting all of this information together in a class, we keep it organized and reusable. Right now, though, this blueprint doesn’t actually do anything; a blueprint just contains instructions on how to build something. That’s where objects come in, our next topic.

Next post: Objects

CS101: Variables

Before we dive into the meat ‘n potatoes of game development, it will be useful to review some of the basics. Let’s bring it back to CS101 and talk about variables. You’re probably pretty solid on all of this stuff, but it can’t hurt to be sure. You might learn something, you know?

Let’s hit the books and start with the dictionary entry.

variable

noun – something that changes or that can be changed : something that varies

mathematics : a quantity that can have any one of a set of values or a symbol that represents such a quantity

So a variable is just a symbol that represents a value. You probably remember variables from Algebra 1; y=mx+b and all that jazz. Back then, variables stood in as placeholders for numbers. In programming, variables function in much the same way. There’s one important difference; variables remember their value. So let’s hop into some Java and look at a variable declaration.

Pretty simple, but there’s a lot here. This isn’t just a declaration; it’s actually an initialization, too. What’s the difference? A declaration gives our variable a type and a name. An initialization is the first value we assign to our variable. In most languages, you can do both at the same time. For the most part, you always want to initialize your variables when you declare them. Many languages, Java included, have default values that variables initialize to when you don’t explicitly give them a value, but it’s clearer to do it yourself. Any time your code can give more information to whoever is reading it, including you, it’s a valuable inclusion. Let’s break this line down further.   int  is where we state our type (in this case, it’s an integer).  x  is our variable name.  99 is our initial value. The semicolon is part of Java’s syntax and signifies the end of an expression.

We’re getting into language specific stuff here, so from this point on, everything I’m talking about is specific to Java. Many languages work in almost the exact same way, including C++ and C#, so it’s still important stuff if Java isn’t your language of choice.

I mentioned that variables have types. Our variable up there was an integer. Java is a statically typed langauge, which means that every variable must have a type declared and its type cannot change. Java has a lot of variable types; here is a quick list of some of them with example initializations.

Those of you who have spent some time teaching themselves Java might be thinking, “Wait, you forgot about Strings and Objects!” I didn’t forget about them; they aren’t primitive types. A primitive type is the simplest kind of data a program can represent; it cannot be broken down into simpler values. Primitive types are also defined by the language itself. You can’t make new primitive types. Can you make new, non-primitive types? Of course! That’s a huge part of object oriented programming and we’ll get to it soon. One last important point about primitive types: primitive types are always passed by value. The difference between pass by value and pass by reference will be covered when we dig into methods. Our next topic is the blueprint for composite types: classes.

Next post: Classes

CS101: Introduction

I’ve spent a huge part of my life reading and learning every single thing I can about computer science and game development, and finally decided to do something with it. I’m turning this site into a blog for both topics. Programming is my passion and I want to share what I’ve learned with others, so here we go!

After spending years self-teaching, finally sitting in a real computer science class was fantastic. All of these half-grasped concepts started coming together into something concrete, and suddenly everything clicked. My goal with this blog is to introduce and explain these concepts in the same enlightening, interconnected way. I want to help others who taught themselves programming get a solid grasp on computer science and apply these concepts to game development, the field that got me interested in programming back when I was ten.

If you’re new to programming or a veteran, I hope you’ll find something to learn here. I’m going to be writing with the assumption that you have a rudimentary programming background, but want to develop it into something solid. We’ll start with the most basic of basics and work our way up to all of the fascinating aspects of game development. So subscribe below, get your brain ready, and we’ll dive into the simple stuff: variables.

Ready to learn?

Keep your skills sharp- subscribe by email and don't miss a post!

Next post: Variables