LoginLogin
Nintendo shutting down 3DS + Wii U online services, see our post

Starting Out With Lowerdash Part 1

Root / Submissions / [.]

kldck_hulCreated:

Motivation

Hey guys, its been a while since I've posted here. With SmileBasic BIG getting a release, and the talk of more platforms in the future, its still a great time to start developing an ecosystem for game development. I created Lowerdash for the purpose of building libraries and distributing them, hoping to make SmileBasic game development easier and faster. But maybe you've never heard of Object-Oriented programming, or the awesome power it can bring? Maybe you're just starting out programming and Lowerdash is that thing that was too hard to learn? Then these tutorials are for you. In this series, I will attempt to teach how to use Lowerdash and build a foundation for learning object-oriented programming techniques. This first tutorial focuses on what OOP is, and later tutorials will have you building a basic Asteroids clone.

OOP OOP!

sorry, not sorry So what is all the fuss about anyway? What are objects and why do I want them? OOP is a style of programming that breaks down the things that need to happen into your game into smaller, isolated pieces that are easier to think about. Each piece can run without the rest of the program, and can even be used in other games or libraries. We call these pieces objects.

Why Not Spaghetti?

As I mentioned, OOP is about creating reusable code. Code that gets used a lot of places needs to maintainable - that is understandable, adaptable, and extendable. If you're serious about making a good game, you're not going to release it on the world and never fix a bug or add new features. If your program then contains lots of copy/pasted code, you open yourself up to not fixing it everywhere, or having things work in slightly different ways by the time you're done. Think about how you re-use DEFs and Labels and the convenience they add. OOP is that, after some rare candies. As an example: Consider the code:
var monsterName = ['Goblin', 'Dragon', 'Goblin']
var monsterHealth = [20, 300, 18]
This is a common pattern, using IDs to reference data in an array. Assume when a monster is killed, you call a function to remove it from the arrays, slayBeast(index) This code can be problematic. First, because you have to make sure any variables referencing monster have been updated to point to the new array indexes. And second, What would happen if you now decided that all monsters should be able to cast spells, and now need a mana pool? slayBeast and anywhere else that modifies arrays now needs to be updated to also remove the monster from monsterMana. If it doesn't, you might find your Goblin casting Doomsday a little too often.

Getting Set Up

I'll start off by showing the basic Lowerdash building blocks in context. If you want to follow along, you'll need to get Lowerdash set-up. You'll want to have a new project with the required Lowerdash files copied into it. If you haven't yet, see Setting Up A Lowerdash Project for instructions. Writing our imports and main entry point are part of this tutorial, so you can skip the last two steps. Now, you'll want to create a blank file and save it as "_SHIP". Pro Tip: For organization's sake, I always put a "_" before the name of any file containing Lowerdash Modules. I recommend adopting this or another convention for when your projects get large.

Orienting to Objects

In Lowerdash, objects take two forms: Instances and Modules. I'll try to illustrate both. An Instance is an object that is created from a Module using the new command:
VAR mySpacecraft$ = new ZClassCruiser()
you don't need to copy this Using new creates a new object using the "blueprint" of a Z Class Cruiser and returns it. Here we store it in an ordinary variable. In Lowerdash, objects are returned as "pointers". The variable type $ is a pointer; in Lowerdash, it can point to Objects or Strings. As I mentioned, the aforementioned Module can be thought of as a blueprint. A Module encapsulates the functions and variables used by something of its "type". When using new, the module describes the materials (variables) needed to assemble the type of object it describes. In other languages, a Module might be called a Class, except in Lowerdash, Modules are also objects ( "singletons"). They can behave very similar to Instances without ever needing to create Instances. Lets create a Module for our Z Class Cruiser. "ZClassCruiser" is a little long to be typing on the 3DS, so lets creatively rename this module to "Ship"! Note: Anytime you see text like Ship, it denotes a Module or "type" of object. We'll write the following code in the "_Ship" file:
MODULE Ship
END
Now when somebody calls the new command with your module, Lowerdash will actually try to call a specific function inside the module called new. Lets add that function:
MODULE Ship
  EXPORT DEF new()
    RETURN me
  END
END
This DEF has EXPORT before it. That means its going to the "class table", or in our blueprint metaphor, being drawn on the plans for this Module's Instances. EXPORT DEFs are made available to Instances and are often called the methods an object has. new is what is called the "constructor function" for the Ship module. As I mentioned, when you create a new Instance of a Module, this function is called. When that happens, the variable me is set to a new Lowerdash object Instance. In this code, we RETURN me because we intend to store our object in a variable somewhere.

Rhetorical Devices

Now that we know what an object looks like in Lowerdash, lets get into what makes one up. Since an object is expected to be an isolated piece, it is considered to have a State and Behaviors separate from the rest of the program. The State is how you would describe the object - often using is or has as descriptors. A spaceship has an ion cannon and an alien is out of shields. The Behavior of an object is what it can do - often in the form of a verb. A spaceship scans for aliens, fires its thrusters, and shoots its ion cannon.

Solid State

You may have seen the object-oriented example with cars and adding tires or something to them. To illustrate state, we're going to do something similar and add an ion cannon to our spaceship. In Lowerdash, we can write:
MODULE Ship
  MEM gun$

  EXPORT DEF new()
    me.gun$ = new IonCannon()
    RETURN me
  END
END
Two things are happening here:
  • We added a MEM declaration to the top of our module. MEM adds whats called a "member variable" to the class. Every object created in new will have a unique copy of every member variable.
  • We set me.gun$ in the constructor. me is an object and we can lookup variables on it using the "dot" operator.
Any given Ship instance now owns an IonCannon instance.

An Ongoing Example

Now that I've hopefully laid some groundwork on what OOP is, I want to motivate its use through an example. For the rest of this series, we are going to be building an Asteroids clone! What a great way to re-use our Ship module! Asteroids is a great example, because it contains a very small number of describable "pieces". Wikipedia describes the game as: The objective of Asteroids is to score as many points as possible by destroying asteroids and flying saucers. The player controls a triangular-shaped ship that can rotate left and right, fire shots straight forward, and thrust forward. As the ship moves, momentum is not conserved – the ship eventually comes to a stop again when not thrusting. You'll notice several distinct "things" that are being described in this paragraph. There are asteroids, flying saucers, a player controlled ship, and even bullets. The description goes farther and tells us about the behavior of the player's ship: it can rotate left and right, shoot, and thrust. Let's add those behaviors to Ship. Remember, we can add methods to a module with EXPORT DEF:
MODULE Ship
  MEM gun$

  EXPORT DEF new()
    me.gun$ = new IonCannon()
    RETURN me
  END

  EXPORT DEF shoot
  END

  EXPORT DEF rotate M#
  END

  EXPORT DEF thrust M#
  END
END
We're at the end of this first part. Go ahead and save this file! Think about how you might implement the code behind these methods. The next tutorial will have us fleshing out the player's Ship Module. On to Part 2!

The "On to part 2!" link is broken