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

Starting Out With Lowerdash Part 4

Root / Submissions / [.]

kldck_hulCreated:

Recalling that our Ship is just some highly upgraded Space Junk

This is a continuation of the Starting Out With Lowerdash Tutorial. In this tutorial series we are building an Asteroids clone using Lowerdash. Previously on Starting Out With Lowerdash...
  • You made Ship prototypically inherit from SpaceJunk. Gaining its strength.
  • You fleshed out the Ship Module. Mmm.

Round and Round We Go

We don't just use objects in a game, we want to try to think of our overall game as an object too! As you may be aware, most games have something called a "main loop". This is a loop in your code that keeps everything updating and responding to player inputs and events. This main loop often only runs when the game is in a specific state. Games are a classic example of what is called a "State machine" - Something that transfers from state to state based on an "interface" - e.g. from menu screen, to game screen, to pause screen when you press buttons on a controller. As this example shows, to the outside world, this "machine" might as well have a physical set of inputs; We'll kick off our start state with a run command. In another scenario, it might be putting a coin in an arcade cabinet, or just hitting play from some home screen! We'll create a self-contained module for our game to hold all of its properties and provide a namespace to put all of its states inside. Recall that STATIC DEFs exist on the module itself. Let's call our module AstroGame:
  MODULE AstroGame
    VAR player$
    VAR space$[]

    STATIC DEF run
      'main loop
    END
  END
Here I used [] without a size. Lowerdash is smart enough to figure out this array is empty for you. Now we can add a menu state we can access:
    STATIC DEF menu
      CLS
      LOCATE 14,14
      PRINT "PRESS ANY BUTTON TO START"

      'WAIT FOR A BUTTON (can't be held down)
      WHILE !(BUTTON(3))
        VSYNC
      WEND
    END
Nothing fancy! Our Game won't have the concept of transitions, but if you wanted, you could check a flag every update and trigger a transition; allowing you to have branching menus and choices. After our menu screen, we'll want a state where we can prepare our game to be played:
    STATIC DEF setup
      CLS
      _.player$ = new Ship()
      _.player$.place 200,120
      PUSH _.space$, _.player$
    END
With our game setup, we can finally code our main loop. Our main loop's primary responsibility is to poll for and handle changes in "machine" inputs. It will check what buttons are held down and tell the player's ship what to do in response. Sort of like drive by wire!
    STATIC DEF play
      VAR BTN%
      WHILE _.player.hp% > 0
        'HANDLE HELD INPUT
        BTN%=BUTTON()
        IF BTN% AND #UP THEN
          _.player$.thrust 1.0
        ELSEIF BTN% AND #LEFT THEN
          _.player$.rotate -1.0
        ELSEIF BTN% AND #RIGHT THEN
          _.player$.rotate 1.0
        ENDIF
        
        'HANDLE FULL INPUT
        BTN%=BUTTON(3)
        IF BTN% AND #A THEN
          _.player$.shoot
        ENDIF
        
        FOR o$ in _.space$
          IF LEN(o$) THEN o$.update
        NEXT

        VSYNC
      WEND
    END
When our player dies, we'd like to reset the game's state and return to the menu:
  STATIC DEF reset
    FOR o$ IN _.space$
      _del o$
    NEXT
    adel _.space$
  END
This code manually calls Lowerdash's built-in delete function _del. This is far from ideal, and we'll come back to this in a later part.

Don't forget our imports

Since we create a Ship in our setup, we actually need the Ship module available to us. Let's import it at the top of our file:
IMPORT "_Ship"

Assemble Voltron!

Now that we've defined the range of states our AstroGame can be in, lets write our run command. We already have well defined states, we just have to put them in order:
  STATIC DEF run
    @START
      _.menu
      _.setup
      _.play
      _.reset
    GOTO @START
  END
Go ahead and save this module as "_ASTROGAME"! We'll be bootstrapping it directly from our MAIN method next.

I don't need anything but my Game Machine!

Now that we have a unique AstroGame, we can bootstrap it in our "GAME" file. Bootstrapping is just creating or accessing Lowerdash objects from SmileBasic and kicking off the callstack. Recall that our "GAME" file was created from the "TEMPLATE" file that came from Lowerdash. Since our AstroGame module has it's own imports, we only have to worry about bringing it in. That means we only have to write one import statement:
head
IMPORT "_ASTROGAME"
Now we have access to the AstroGame module. As we saw, AstroGame has a static function called run. Because this is static, we can access it everywhere; even outside Lowerdash.
main
AstroGame_run

Lets start playing!

Sure is a lot of space...

We can now run our GAME program, and Lowerdash should compile all the files we've made so far. You'll get a menu screen, and then be taken to a screen with nothing but your spaceship. The game loop should respond to button presses, and things should generally be good. But wait! Where are our bullets!?!? I NEED BULLETS! They're in part 5!

RIP Part 5.

RIP kl'dck hul