The Project Formerly Known as Arconia


#1

Hey folks, I wanted to introduce our project which was formerly known as Arconia (but does not have a new name yet).

We are developing in :ue4: with the majority of our code being C++. We are new to :sk: and are taking baby steps integrating it into our project while we/I come up to speed on it.

The Project

We describe our game as Legend of Zelda in space. It also has elements of Star Control 2, Geometry Wars and Blaster Master. If you know what all 3 of those games are, you’re officially on our list of cool people to hang out with :wink:

The main character is this little guy.

Instead of riding around on a horse, he rides around in various spaceships. He can hop in/out of his ship to explore various areas of the game.

You can see more info about the game along with some really early prototypes on our UE4 forum thread (which hasn’t had a proper update for half a year). We hope to have a decent update out soon.

Why :sk:

Our previous game had all of the game logic written in LUA. LUA was tolerable and had a fairly fast iteration time, so it was pretty great for rapid prototyping. When we made the jump to :ue4:, it was back to C++ with Blueprints (BP). For the last 3 years, I haven’t been happy with either of these choices.

BP’s are great if you’re not a programmer… as a programmer I was immediately disappointed when I realized I was missing basic necessities like access to TMap and TSet. As a programmer I found working with BP slow, even doing a simple piece of vector math (a 1-liner) takes up a ridiculous amount of screen real-estate. I also found strong urges to hurl my body out of my 2nd story office window once I realized that diff’ing BP is akin to playing Where’s Waldo :family:

What initially attracted me to :sk: was the ability to Race, Sync and spin off coroutines that could block without blocking the game thread. This was stuff that was hard to do in our last LUA based engine, where you had to take a timeslice approach (ok, we’ve been working for 2 ms this frame, let’s wait until the next frame to continue our work). And in :ue4: in C++ you’d have to fire up timers or async threads and shuffle your data back and forth in a thread safe queue :crying_cat_face:

Games are hard to make :confused: and C++ wasn’t made for rapidly iterating on complicated timing-based game logic. In that context, :sk: is the most exciting language on the horizon for me.

Our Use of :sk:

I’ll continually update this thread as :sk: sneaks into our project. As I mentioned before, we’re taking baby steps while still learning the ins and outs of the language. I mean, you’re a newb until you’re not, right? I’m still a :sk: newb :new:

###Command Prompt - Cheats, Teleports, Etc
It’s often that we need cheats in the game to test various things quickly. For us, the quantity of cheats that we have and tracking their key-binds or exec strings (we use CheatManager) can get quite cumbersome. In the past we either had to bind cheats to un-used keys (try rationalizing to your team why [ maps to unlimited health) or look up their exec string in the code. Now anyone can browse through the cheats and quickly execute the ones of interest. A sampling:

//
// CHEATS!
//
// God Mode
GameLib.player_controller<>ShipPlayerController.cheat_god_mode

//
// TELEPORT CHEATS
//
// Teleport to Arconian ship entrance
GameLib.player_controller<>ShipPlayerController.teleport_arconia_pawn(Vector3!xyz(-1759.635864, -12175.116211, 0))

// Teleport to warp gate
GameLib.player_controller<>ShipPlayerController.cheat_move_to_warp_gate

// Land/takeoff nearest station
GameLib.player_controller<>ShipPlayerController.cheat_land_on_nearest_station

//
// INVENTORY CHEATS
//
// Unlock all player items
GameLib.player_controller<>ShipPlayerController.cheat_give_all_rob_items

// Reset scanner database
GameLib.player_controller<>ShipPlayerController.cheat_reset_scan_entries

// Unlock all scan entries
GameLib.player_controller<>ShipPlayerController.cheat_unlock_all_scan_entries

###Debugging
I had a really hard time tracking down some camera transition bugs. :sk: made the work far easier by allowing me to arrive at the reproduction case with a single keystroke (as opposed to flying to area X, entering through the door and waiting for a 3-second transition).

Efficiency is so important when making games. Being able to repro a bug in 1 second vs 1:30 is a huge time saver for everyone!


Help promote SkookumScript to make it even better!
#2

Well, we’ve moved beyond using :sk: just for debugging and are starting to replace key systems where it makes sense. The first system I have replaced is the core ability loop for Rob.

Before it was basically just a really long Tick() function in C++ that reads input and fires off abilities. Now it’s arguably much cooler, I’ll get to that.

This is kind of new ground for me, there isn’t really an instruction manual on writing great coroutines. All I can say is that what I’ve written works exactly how I want it to and it’s sooo much easier to extend now.

This is my high-level core ability loop. Rob has 2 modes, Normal and Suit. So this code simply toggles between the 2 modes. When in Suit mode, you use heat, if you overheat you get kicked out of Suit mode. _change_modes contains some additional cooldown logic to prevent going back to _suit_mode before cooldown.

loop
  [
    race
    [
      _normal_mode
      _change_modes
    ]

    race
    [
      @suit_overheated?._wait_true
      _suit_mode
      _change_modes
    ]
    // Reset any abilities that are specific to suit mode
    @using_afterburners? := false
  ]

The fun stuff happens in _suit_mode where I’ve just been having a literal blast testing out all sorts of firing patterns that would have taken me a long time to prototype in C++.

Check it out!
Here is your standard pew pew laser firing mode with a simple delay between shots.

if @laser_is_enabled?
[
  fire_projectile(1.0) // scale of 1.0
  _wait(@suit_firing_rate)
]

Here is more of a burst shot mode with a delay at the end

if @laser_is_enabled?
[
  race
  [
    _wait_not_firing
    [
      5._do
      [
        fire_projectile(1.0)
        _wait(0.1)
      ]
    ]
  ]
  _wait(1)
]

And then something a little more crazy. A 3 round burst followed by 4 shots with increased size and delay.

if @laser_is_enabled?
[
  race
  [
    _wait_not_firing
    [
      // Fire 3 small ones
      !scale : 0.5
      3._do
      [
        fire_projectile(scale)
        _wait(0.1)
      ]
      
      // Wait for the big ones
      !delay: 0.3
      _wait(delay)

      // Fire 4 projectiles that increase in size
      4._do
      [
        scale += 2.0
        delay += 0.08
        fire_projectile(scale)
        _wait(delay)
      ]
    ]
  ]
  _wait(1)
]

:sk: :guitar:

A final implementation would replace all the magic numbers with blueprint variables to allow for easier tuning by other team members. I was just so thrilled by this that I wanted to share.


#3

Back again. This time with some AI. Over the last few nights I’ve implemented the majority of Craig Reynold’s Steering Behaviors for physics based movement.

Here I have a simple probe moving between the 4 glowing points using seek. Debug is turned on so you can see avoidance checks and forces. This is pretty similar to the :sk: demo:

loop
[
  BP_Waypoint.instances._do
  [
    probe.@steering_behavior._seek_actor_with_avoidance(item, 5.0)
  ]
]

I also made a :sk: Radar Behavior Component that lazily updates all threats in a definable range. Combining this with the movement behaviors, my probe bot AI is starting to show signs of life.

It’s as simple as

race
  [
    _move
    _attack
    _update_goals
  ]

And each of those coroutines is looping at an entirely different rate. _move happens every frame, _attack happens every 1/10th of a second and _update_goals updates every half a second.

Here’s the probe laying waste to some sneaky local wildlife. Part of _update_goals checks to see if the probe has strayed too far from Rob. If so, he returns, I illustrate this at the start of the video.


#4

I’ll be honest here…

I LOVE THIS!