These are some exciting times for indie developers. Not only has the advent of digital distribution opened up a huge market for all sorts of innovative games by small creative teams, but now we have Epic, with undeniably the most advanced game technology in the industry, opening up their platform to anyone with an urge become the next Shigeru Miyamoto (or Kim Swift)!
As a long-time Unreal developer, I’ve jumped on this bandwagon, and over the coming months I’m going to be putting together a series of straightforward mini-game demos on the UDK. My goal is to provide the growing community with some open-source, open-content examples of ways to implement various types of gameplay within the UDK. These should be relatively simple chunks of code and content that may be more easily digestible by Unreal newbies than the full-course meal that is Unreal Tournament.
So without further ado, let’s chow down! (mmm now I really am hungry)
When thinking about what kind of game to start with, I noticed that some people seem to be wondering about creating various kinds of third-person games with Unreal, which is an easy thing to do once you know how. Also, I just came off a round of playing PixelJunk Monsters, so I’m in kind of a “Tower Defense” mood. Fighting off hordes of beasties by strategically building stuff just seems like… lots o’ fun.
Therefore, the first mini-game that I’m going to tackle will be called “Dungeon Defense”, and it will be a semi-topdown (more like ¾ perspective) action/tower-defense hybrid. You’ll play as a l’il mage who, ala the “Sorcerer’s Apprentice”, has got in over his head with defending his mentor’s lair while he’s away. You’ll have to use a variety of “summoning” spells to produce magical defenses throughout the lair, and zap stuff with your magic staff when the defenses happen to get overrun. Should be a nice hybrid of action tactics and resource-management strategy, and with Unreal implementing all of this craziness is going to be a pleasant breeze.
So over the weekend, I did some design work to plan out my assets and control schemes, and then today I officially started programming. First, I started with implementing my own GameInfo, Pawn/Player, Player Controller, and Camera classes. I’ll describe what they do:
The GameInfo class contains the global rules of the game, and so far in my case I just overwrote its default values to spawn in my own custom PlayerPawn and PlayerController class(1). The PlayerPawn is of course the physical character in the World, and the Controller is the class in which the user’s input is transferred into gameplay action on that PlayerPawn. For the camera class, I modified the UpdateViewTarget function in order to position the camera above the Pawn, rather than looking directly out its eyes like UT, and also to dynamically offset a little in the direction that the player is looking, so that it tends to rotate towards your target direction(2). I made use of Epic’s built-in RInterpTo and VInterpTo functions to handle the Rotator and Vector interpolations respectively, which are always handy. This allowed me to lag the Camera from the player’s current location (and rotation) a little bit, giving it a smoother feeling than it if was locked down exactly on his position.
In the PlayerController, I changed the PlayerMove function to only change Rotation Yaw, and no Pitch (so that the character’s orientation is restricted to the 2D plane). At first I was just using mouse delta to try to change the Yaw a little every frame as you scrolled the mouse, but it didn’t feel very natural. It was just too imprecise for the PC. We just want the character to look directly at wherever we’re pointing, right? So I wrote a unique bit of code that gets the results of a “canvas deprojection” of the current mouse position, and then raycasts that 3D vector against the world to find out where in the World the user is pointing at – then makes the character look towards that point.(3)
Of course, I also transformed the input directions by the camera rotation, so that the inputs result in intuitive “camera relative” movement (remembering the ever-useful TransformVectorByRotation function, equivalent to the “vector>>rotator” operator). The Player-Pawn remained pretty much like the default Pawn, except that I did some fun Animation Tree work to blend between multiple custom full-body animations, so we don’t get any pops even if we’re trying to play several animations in sequence.(4) Working with the Anim Tree system, I was reminded of how much I enjoy the Unreal tool suite… configuring your character’s blending visually with real-time feedback sure beats having to hardcode it!
But that stuff only took a couple hours, so I wasn’t ready to call it a day just yet. Next, I got to work on the Mage’s Staff weapon. I sub-classed Weapon and modified it to support “charging” the weapon when it’s held, and only firing upon release (I want the Staff to support variable charge attack)(5)– and then I sub-classed Projectile to support a variable-strength projectile as well, which procedurally scales all of the visuals accordingly.(6)
I should mention that I find it extremely useful to spawn “Archetype” references rather than a direct class reference(7) -- you can specify an Archetype in the “Spawn” function, as the so-called “Actor Template”) If you spawn Archetypes for gameplay, then you can have your entire library of gameplay objects ready to be configured real-time in the Editor, rather than having to go change the “Default Properties” every time you want to tweak a value. It also makes it a lot easier to visually configure values, swap out media, and create multiple variations of the same core class that differ only in properties. I’ll get into more detail about the power of Archetypes later, but suffice it to say that it helps me loads for iteration. And, of course the “Remote Control” is another really useful tool for real-time iteration, which you can access by launching the executable with the “-wxwindows” argument. I’ll talk more about the power of the Remote Control in another post!
Next, I got to work on the AI Controller for my first enemy, the Goblin. I wrote a bit of “state logic” that picks a target (based on all Actors that implement an “interface” that returns a targeting weight)(8) , then decides when to pathfind, when to navigate directly to the target, and when to stop pathfinding/moving & launch an attack(9). I’ll go into more detail about the AI script later on. I also implemented a nifty MeleeAttack state for the Goblin enemy, which uses animation notifications to enable/disable Tracing (a box sweep) each frame between his current and previous “hand socket” locations.(10) This ensures that the area that the Goblin swipes for damage actually depends on the animation and its timing, rather than any hardcoded values. I also made sure that the Goblin only damages each “traced” Actor once per unique swipe, by maintaining a list of all Actors hit during the current swipe and checking against that.(11) When all was done, this melee attack felt really good and accurate to what the animations were conveying.
Then, I couldn’t resist and implemented a basic “tower turret” that attacks the enemies. I didn’t bother with an AI Controller for this simple non-moving Actor, and instead just pick targets via a Timer (and remember that you can use State logic for any Object, not just Controllers). (12) I also added a LookAt Bone Controller to this Turret’s Animation Tree, to get the top of the turret to look towards any target that it picks.(13) Once the Animation tree was setup, all that took was one line of code to tell it where to look. Yay.
With the gameplay really starting to take shape, I went ahead and implemented the “Crystal Core” that the enemies will attempt to destroy as their primary objective(14). I used the ‘interface’ I created for any targetable Actor(15), to give the Core an especially high priority, so that the enemies are drawn to it with a greater intensity than the player or towers. ‘Interfaces’ allow you to have Actors of totally different classes share a common set of methods, so that they can interact or be checked in the same way. So even though my “Crystal Core” class is not directly related to by “Player Pawn” by hierarchy, they both implement the same targeting-weight function provided by the shared interface, which the enemy AI generically accesses to determine which entity is a more important target. Cool!
And then finally, the project’s lead artist, Morgan Roberts, put together a test level that represents the Mage’s Lair quite nicely, and so by setting up a bit of Kismet I created some waves of enemies to repeatedly spawn-in and proceed to attack the core.(16) So there we had it, an essentially playable prototype in about a day.
Well the gameplay’s already too challenging for me, so in the coming days I have some serious balancing work to do, along with of course implementing a bunch of additional mechanics and refining what’s there. Thanks to the great tools of Unreal it’s just so much fun to implement this stuff!
In the next posts I’ll go into more detail about many of the subjects briefly addressed above, and also start to review bits of the code or functionality that I think you’ll find interesting or particularly useful. And once we have some visuals for you to see, we’ll get some screenies up too. Cheers, I’m looking forward to you all playing this little game soon enough
Now to get that pizza I was thinking about earlier…
- Main.uc: 618, 638
- DunDefPlayerCamera.uc: 240 - 248
- DunDefPlayerController.uc: 1561 - 1652
- DunDefPawn.uc: 222
- DunDefWeapon_MagicStaff.uc: 111
- DunDefProjectile_MagicBolt.uc: 24
- DunDefInventoryManager.uc: 13
- DunDefEnemyController.uc: 222
- DunDefEnemyController.uc: 764
- DunDefGoblinController.uc: 52
- DunDefGoblinController.uc: 32
- DunDefTower_ProjectileType.uc: 99
- DunDefTower_ProjectileType.uc: 95
- DunDefCrystalCore.uc: 19
- DunDefTargetableInterface.uc: 15
- DunDef_SeqAct_BasicActorSpawner.uc: 11