2011-03-25

udk/unrealscript rpg

Lately I've been interested in experimenting with game design, so here are the results: A basic RPG framework written for UDK, Epic's Unreal engine development environment.


download

An archive of my Unrealscript classes, the DefaultInput.ini for key bindings, and a map where I store my UI. I'm not sure what the best way to import this is. The classes need to have the editpackage added as described in the docs. The map might be found automatically, I don't know. I built this with the March 2011 SDK.

disclaimer

Before we get started, let me make it clear that this post is a by-beginners-for-beginners affair. I've only been using UDK for a handful of hours, just long enough to implement my basic requirements. I am undoubtably doing many things that are Really Dumb. However, during the course of doing this I noticed a lot of people seemed to have the same questions I did, but the answers were scattered around, so I figured I would compile what I learned.

what it does

The framework I have implements a skill board and lets users adjust skills that affect the fire rate of pistols and sniper rifles. In use, there are just a few controls: Press 'O' (that's oh, not zero) to switch between a pistol and rifle, press 'P' to open the skill board. With the skill board open, the game pauses and the mouse can be used to add (left button) or remove (right button) skill points. If any of the points added affect the pistol or sniper skill, those weapon's fire rate will have changed when you press 'P' to toggle off the skill board and return to the game.

The skill board is worth explaining since it was the main idea I was interested in exploring when I started the project. Characters are defined by an archetype -- Razor, Believer and Anomaly (which you can switch between by clicking on the name when looking at the skill board). An archetype is a collection of tiles arranged in a specific shape. Each tile can store either an attribute (currently there are Faith and Insight) or a skill (currently Pistol and Sniper).

Attributes govern skill abilities by extending their influence to the nearest tiles on the board. As attributes increase in level, their influence extends to more tiles. Since this is supposed to be as close to a clean framework as possible, currently the attributes don't affect different properties of the skills -- everything simply increases the fire rate.

The archetype boards have (in theory) a profound impact on how the character develops. The Razor has no intersecting paths, meaning attributes will have less impact, so the Razor is dedicated more towards building individual skills like in a traditional RPG.

The Believer has Faith at the center of two intersections, where it can impact the most number of tiles, with a downside that if the Faith attribute becomes poisoned, it will negatively impact the most number of tiles.

The Anomaly has multiple Faith attributes it can dynamically switch between, dynamically changing how the character plays, and letting the Anomaly avoid poison damage to its Faith.

how it works

Since I like open world RPGs and also FPS games, UDK seemed like a good starting point -- certainly, it's got the FPS part down. The main questions revolved around how to support the RPG side. Before starting, I noted the basic implementation questions I had:

  • How to write a custom HUD/skill screen?
  • How to implement skills, affecting properties of items?
  • How to perform custom file IO?
  • And what about that open world part?

before any code... key bindings

It's very helpful to know how to bind functions to keys, so let's summarize that quickly. On the script side, you need a function for handling the key. For example,

exec function handleP()
{
`log("Back off, crawhead");
}

might be used to handle pressing 'P.' I believe the function can go anywhere, but I've placed mine in the PlayerController, as that seems obvious.

Next you need to modifythe Config/DefaultInput.ini file:

In section [Engine.PlayerInput] add

.Bindings=(Name="GBA_handleP", Command="handleP")

In section Game Keyboard/Mouse Bindings add

.Bindings=(Name="P", Command="GBA_handleP")

custom skill screen

The first thing we need is the basics for what will become a fairly extensive custom UI. UDK has apparently gone through several iterations of UI handling, with the most recent downplaying custom scripting for Flash/Scaleform. This is nice for real game developers, but it requires a Flash authoring tool. Adobe's is around $700, and the alternatives (there's one called sothink that's mentioned repeatedly) aren't officially supported, and lack any documentation for how to integrate. So as a non-artist just curious about poking the UDK with a stick, I decided I would have to go the simplest route and use Unrealscript.

The entry point for our skill screen, which is basically a modal HUD, is RpPlayerController. As described above, the P key is captured, then handleP() uses Unrealscript's (very nice!) state mechanism to flip to a "skill board is active" state. This state captures the DrawHud() method to handle all custom drawing. The main class for drawing is RpCanvasSkillTree, which is responsible for creating a visual representation of the skill board and drawing it. There are several support classes, most notably RpSkillLayout.

The other side of the custom UI is handling interactions. Again, our HUD state overrides StartFire(), which is mapped to the mouse buttons, and uses our cached layout to interact with screen elements.

skills and items

Implementing skills is a combination of RpCharacter, which stores skills (in the form of RpSkillCell, which in turn stores the actual, individual RpSkill) and the RpCharacterItem interface, which is implemented on Weapon subclasses. When the UI detects a change in the skill board, RpPlayerController::SkillsChanged() is fired to update all the tiles to reflect the changes.

Finally, RpPlayerController overrides NotifyChangedWeapon() so that we can install a skill on its matching inventory item (a weapon, in this case). There are several support classes that take care of our current example Pistol and Sniper skills: RpSkillPistol and RpSkillSniper are RpSkill subclasses that reside in the RpCharacter, and RpWeaponPistol and RpWeaponSniper are the custom Weapon classes that know how to alter their characteristics based on the matching skill. The Weapon classes are instantiated in RpPlayerController::handleRpWeapon(), a test function fired from the 'O' key that just cycles through our weapon list.

custom file IO

Unrealscript seems far from ideal for implementing the somewhat complex file saves most RPGs use. I will refer you to the pattern described here, which I began implementing, but put on hold. I'm fairly impressed that it works as well as it does, but I find it clunky enough that I will probably poke into seeing how well DLLBind works for file IO. So for now this item is a qualified "possible, but not desireable."

so, what about that open world part?

One of the big points in UDK's favour is the Seamless Worlds technology, for dynamically streaming maps into memory. However, I haven't experimented with it yet, so I don't know what issues there might be in practice.

classes

Here's a summary of the classes in the download, to help with getting an entry point into how the system works. Let's start with the most important ones:

CluOneGame. The game info subclass, the main entry to all our custom code. This project began from the CluOne tutorial on Epic's site, hence the nonstandard name. The main point about this class is it's used to supply our custom RpPlayerController and RpPawn classes to the system.

RpPlayerController. The main class for handling all our custom user interaction and drawing. This class handles keyboard callbacks (handleP(), handleRpWeapon()), drawing the UI (state HudBoardOpen), and keeping the character skills in sync (SkillsChanged()). It also serves as the root data model class, storing the character. It's possible putting the character in the game info would make more sense.

Here are the data model classes:

RpCharacter. The root of the data model, characters store a board of skill cells.

RpSkillCell. The skill cell is essentially a configured skill, providing a location on the board, current levels, and storing the actual immutable skill class.

RpSkill. A skill is a single ability a character might have.

RpSkillTree. The skill tree provides miscellaneous support tasks for working with skills, such as initializing a character's skill board based on the archetype defaults.

RpCharacterItem. This interface lets items (such as weapons) participate in the skill system.

The user interface classes:

RpCanvasSkillTree. The main entry to the UI, storing a skill layout and any other views.

RpSkillLayout. The cached visual representation of the character's skill board.

RpView. An abstract class that might some day sit at the root of the UI hierarchy. Right now all it does is provide a location.

RpArchetypeView. A custom widget for setting the current archetype.

Support classes:

RpPawn. Does nothing but turn off the visual representation of the player character, which seems to be turned on by something up in the game info hierarchy, but I'm doing a first person game, not a third.

RpPlayerInput. Simple class for grabbing mouse input. Used for drawing the cursor when the user is editing the skill board.

RpSkillBuilder. A utility for computing the attribute levels for each tile in the skill board.

RpIo. The basics for an Unrealscript file IO system, not complete and currently unused.

Here are the pieces that provide some default behaviour to our system so we can test things out:

RpSkillFaith, RpSkillInsight. The attribute implementations. They do nothing but provide a visual icon.

RpSkillPistol, RpSkillSniper. The skill implementations, for translating attribute values into properties on their respective skills.

RpWeaponPistol, RpWeaponSniper. Our custom weapon implementations.

No comments:

Post a Comment