Friday, October 19, 2012

Diary: Co-op gameplay

One of the ideas of how to improve current game concept is to add co-op gameplay feel:

  • multiple playable characters in a level, different set of skills
  • need to cooperate to reach the level goal
    • e.g.: button at the end of small tunnell -> only smaller character can reach
    • movable objects -> only bigger character is strong enough, etc.
  • possible gameplay variations:
    • singleplayer - switchable characters
    • multiplayer:
      • local co-op - splitscreen
      • co-op

Anyway, I'm back on track, pushing development on and on ;). Today I implemented possibility to have multiple playable characters in one level (switchable). To proof this concept I've prepared a small level, you can take a look at this video:


Stay tuned for upcoming news!

Thursday, October 18, 2012

Steam Greenlight & moving forward!

After being rather busy for the last few weeks doing my part time contract I'm back to UDK. I've some ideas I want to track and implement:


Co-op basics:


  • two playable characters (ball-like robots)
  • each with differing set of skill (switching gravity, jumping, moving objects)
  • need to aid each other to finish a level
  • local co-op gameplay/controls/mechanics
  • switching between characters (to enable single player capabilities)
Stay tuned for some news in the days to come!


Steam news:



Furthermore, as Steam has reintroduced it's Greenlight for free (new concepts section), you can find this project on steam site now! In case you like it, feel free to endorse it or leave a comment. It is always appreciated to know what others are thinking. Thank you!

Tuesday, October 16, 2012

Cookbook: UDK command lines

There are many things that can simplify your work and increase productivity. I think that in case of UDK that requires restarting editor and recompiling after each minor script change you can save some time by using batch files for starting everything you want without the need to manually open some level, etc.

You can find some additional tips on getting started with UDK in this tutorial.

So here are some useful command lines (use them in your batches):
  • compile script

call Binaries\Win64\UDK.exe make
  • run editor with your level + show log

call Binaries\Win64\UDK.exe editor YOUR_LEVEL_NAME -log -NoGADWarnings

Aforementioned command lines are for 64bit systems, in case you're using older 32bit systems, please replace Win64 with Win32. Create those batches in your UDK install dir and put only a shortcut on your desktop to make it work with relative paths.

Using UnrealFrontend:

When packaging your game and cooking your levels you'll need to work with Unreal Frontend (%UDK_INSTALLDIR%\Binaries\UnrealFrontend.exe).

  • don't forget to have all your maps/levels listed in Maps to Cook window prior to any cooking
  • don't forget to use Script/Full recompile after changes to script
  • this has to be followed by Cook/Clean and Full Recook of levels (to actually use changes in script)
  • after cooking, launch your game to make sure everything is intact and up to date
  • only after doing the check (in case everything is ok) do the actual packaging
And last but not least, don't forget that you cannot compile scripts with editor running (this will cause compilation warnings and errors)!




Monday, October 15, 2012

Cookbook: Typecasting and utilizing class hierarchy

Even unrealscript enables you to utilize inheritance and class hierarchy of your custom classes. So it is a good idea to design your actors/object in a way, that as much of the shared functionality and variables are in parental classes (to avoid copying the same code over and over) and be able to access that basic functionality after typecasting to a parent class (for example useful for storing all differing actors with same parent in one array and accessing them by their parent class...

Let me show you all of this in an example:

Let's say we need a couple of types of platforms, one that turns on some lights, one that opens doors, one that gives player some points. What they have in common is a mesh and slight movement upon touch (to emulate being used). Additionally there is a class that stores a set of references to such platforms and handles global resetting, changing of states, etc.

All the common functionality goes into some PlatformBase.uc:


   1:  class PlatformBase extends Actor
   2:      placeable;
   3:   
   4:  //our mesh
   5:  var (StaticMesh) StaticMeshComponent StaticMesh;
   6:   
   7:  /** movement offset from base position */
   8:  var(Game) vector vMoveOffset;
   9:   
  10:  //========================================================================
  11:  function TriggerAction()
  12:  {
  13:     //move
  14:     SetLocation(Location + vMoveOffset);
  15:  }
  16:   
  17:  //========================================================================
  18:  simulated event Reset()
  19:  {
  20:     //reset
  21:     SetLocation(OrigLocation);
  22:     super.Reset();
  23:  }

In the inherited classes you only need to add additional functionality, all the functionality of parental class is intact and can be used:

PlatformPoints.uc:

   1:  class PlatformPoints extends PlatformBase
   2:      placeable;
   3:   
   4:  //========================================================================
   5:  function TriggerAction()
   6:  {
   7:     super.TriggerAction(); //call parent method (move platform)
   8:     
   9:     PlayerController.AddPoints(100); //add some points
  10:  }

PlatformLight.uc:

   1:  class PlatformLight extends PlatformBase
   2:      placeable;
   3:   
   4:  var(Light) const LightComponent    Light;
   5:   
   6:  //========================================================================
   7:  function TriggerAction()
   8:  {
   9:     super.TriggerAction(); //call parent method (move platform)
  10:     
  11:     Light.SetEnabled(true); //enable referenced light
  12:  }
  13:   
  14:  //========================================================================
  15:  simulated event Reset()
  16:  {
  17:     super.Reset(); //call parent method
  18:     
  19:     Light.SetEnabled(false); //reset light state
  20:  }

PlatformDoor.uc:

   1:  class PlatformDoor extends PlatformBase
   2:      placeable;
   3:   
   4:  //========================================================================
   5:  function TriggerAction()
   6:  {
   7:     super.TriggerAction(); //call parent method (move platform)
   8:     
   9:     //trigger event with myself as instigator
  10:     TriggerEventClass(class'SeqEvent_DoorOpen', self);
  11:  }
  12:   
  13:  //========================================================================
  14:  simulated event Reset()
  15:  {
  16:     super.Reset(); //call parent method
  17:     
  18:     //trigger event with myself as instigator
  19:     TriggerEventClass(class'SeqEvent_DoorClose', self);
  20:  }

The handler class than collects references to all platforms by their parental class and can access all the basic functionality or typecast it to inherited class to use additional functionality. And remember accessing basic functionality of class referenced by its parental class actually calls the overriden method of actual class!


   1:  class PlatformHandler extends Actor;
   2:   
   3:  //references to all platforms
   4:  var array<PlatformBase>    Platforms;
   5:   
   6:  //========================================================================
   7:  event PostBeginPlay()
   8:  {
   9:     local PlatformBase platform;
  10:   
  11:     //iterate over all actors with exact or parental class of PlatformBase
  12:     foreach WorldInfo.DynamicActors(class'PlatformBase', platform)
  13:     {
  14:        Platforms.AddItem(platform); //store reference
  15:     }
  16:  }
  17:   
  18:  //========================================================================
  19:  function ResetActors()
  20:  {
  21:     local PlatformBase platform;
  22:     local PlatformDoor door;
  23:   
  24:     //reset all platforms
  25:     foreach Platforms(platform)
  26:     {
  27:        //call the reset 
  28:        //(this will call actual reset of real platform class type!)
  29:        platform.Reset();
  30:   
  31:        //you can even typecast to some inherited type
  32:        door =  (PlatformDoor)platform;
  33:   
  34:        if (door != none) //success, this one is really platformDoor
  35:        {
  36:           //call method unique for PlatformDoor!
  37:           door.StringToHUD("door opening!");
  38:        }
  39:     }
  40:  }

Friday, October 12, 2012

Cookbook: Referencing objects

"I'm trying to call a certain function of Controller from a different class. How can I do it?"

There are situations when you need to call a method of a different class (update stats, test some conditions, display something on the HUD) from your custom actor. As in UDK the centerpiece of all action handling is  the Controller class, you may need to store reference to it in your actors that change somehow gameplay status.

To set this reference you can use a simple iteration approach (iterate over all actors of some class):

Controller.uc:

   1:  var array<CustomActor>    Actors;
   2:   
   3:  //========================================================================
   4:  event PostBeginPlay()
   5:  {
   6:     local CustomActor actor;
   7:   
   8:     foreach WorldInfo.DynamicActors(class'CustomActor', actor)
   9:     {
  10:      actor.Controller = self; //set myself as controller
  11:          Actors.AddItem(actor); //store reference
  12:     }
  13:  }
  14:  //========================================================================
  15:  function Disable()
  16:  {
  17:     local PuzzleActorBase actor;
  18:   
  19:     //disable all parts (use stored references)
  20:     foreach Actors(actor)
  21:     {
  22:      actor.DisableActor();
  23:     }
  24:  }

This way you can later call methods of you controller when actor is touched/triggered/hit, etc.:


CustomActor.uc:
   1:  var CustomHandler Controller;
   2:   
   3:  //========================================================================
   4:  function UpdateTriggered() //some method
   5:  {
   6:     if (Controller != none)
   7:     {
   8:        //use reference
   9:        Controller.TriggerAction(self);
  10:     }
  11:  }

This can be of course generalized and reused for other situations. Let's say we have a handler class that stores references to all objects of some type (or inside some volume) and evaluates some logic (push platforms that are a part of some puzzle and handler that checks if they are pushed in some order, etc.). This handler can also iterate over all necessary objects and store references to desired objects....

Thursday, October 11, 2012

Cookbook: Custom input bindings

In case you're not simply extending some UTGame and creating another clone of a shooter (which UDK is rather streamlined for) sooner or later you'll need to extend controls setup/rebind input keys, etc.

I recommend to create a custom input config, where you can keep only things you really need and avoid problems with upgrading to newer versions of UDK (conflicts while merging your changes to those from Epic). Apart from that you'll avoid problem with overriding bindings (last appearance of binding disables all bindings to the same key found anywhere before in the hierarchy of config files!). As with all other config files in UDK, create Default version of your input config (UDK version is going to be created automatically when launching editor):


   1:  [BallPuzzler.BallPuzzlerInput]
   2:  ; types //this is just a comment
   3:   
   4:  //alias for binding command (reused for PC/XBOX in the same config)
   5:             //name to identify        //command to exectute
   6:  Bindings=(Name="GBA_ShowMenu",Command="CloseEditorViewport | onrelease ShowMenu")
   7:   
   8:  ; pc
   9:             //key pressed, command to execute
  10:  Bindings=(Name="X",Command="ToggleZoom")
  11:  ...
  12:   
  13:  //use previously defined alias
  14:  Bindings=(Name="Escape",Command="GBA_ShowMenu")
  15:   
  16:  ; xbox
  17:               //key pressed, command to execute
  18:  Bindings=(Name="XboxTypeS_Y",Command="ToggleZoom")
  19:   
  20:  ...
  21:   
  22:  //use previously defined alias
  23:  Bindings=(Name="XboxTypeS_Start",Command="GBA_ShowMenu")

To use custom input config you need to do two additional steps:

  • create an extension to PlayerInput class with config file specified:

   1:  class BallPuzzlerInput extends PlayerInput within BallPuzzlerController
   2:   config(BallPuzzlerInput);

  • setup it in your controller class (defaultProperties):

   1:  //======================================================================= 
   2:  defaultProperties
   3:  {
   4:     InputClass=class'BallPuzzlerInput';
   5:   
   6:     ...
   7:  }



Later you can react (in you controller class) on custom commands being executed:


   1:  //========================================================================
   2:  exec function ToggleZoom() //is triggered according to config key binding
   3:  {
   4:     //some code you want to run when X/XboxTypeS_Y is pressed
   5:     ...
   6:  }

Wednesday, October 10, 2012

Cookbook: Custom postprocess chain

In Unreal postprocess effects are set per level (WorldProperties/Default Postprocess Settings). But what if you want to have the same atmospheric setting for many of your levels? There comes the possibity to specify your custom PostProcessChain and reuse it in every level where you want it to be (and edit settings of all such levels just by tweaking one PostProcessChain).

What do you need to set it?

  • create empty PostProcessChain (right click in Content Browser -> New PostProcessChain, specify package name, etc.
  • setup your postprocess (double click on PostProcessChain):
    • you can specify a chain of different nodes (like in kismet) where output of the previous node is the input for the next one
    • UberPostProcessEffect lets you specify almost everything that is being set in aforementioned Default Postprocess Settings
    • MaterialEffect lets you use any screenspace shader you want

  • use it in level:
    • just select your new chain and use it in WorldProperties/World Post Process Chain

  • you can preview all parts of effect chain directly while in editor:
    • either use Post process effect/Show in editor checkbox directly in properties of individual nodes
    • or click on Game View button on your viewport panel (big G)
Postprocess off

Postprocess on

Tuesday, October 9, 2012

Cookbook: actionscript -> kismet commands with parameters

At some point in your project, you'd like to create some nice menu and be able to load different levels, setup resolutions, etc. Let me show you the way how to simply do it and additionally use utilize parameters as well.



For my demo installer I needed some simple menu (possibility to choose from a set of levels and change resolution for older HW/notebooks). I didn't have much time to play with Scaleform and so I've chosen actionscript 2.0 approach that was more familiar to me. Easiest way to send a string command to unreal is by using fscommand.


   1:  buttonLevel[i].onPress = function() {
   2:              //command to be linked with kismet node
   3:                         //actual command we want to run in kismet
   4:     fscommand("loadmap","open " + levelNames[this.id]);
   5:  };


This method can additionally have a string of parameters that can be parsed/used in kismet to avoid necessity to creating separate kismet nodes for generic tasks (e.g. open level1, open level2, ... open level37). If you're curious how to react on such a command on unreal side, utilize kismet event node FsCommand (New Event/Gfx UI/FsCommand). This node has an optional argument that can be sent to any other kismet action (e.g. Console Command for opening levels).




FsCommand node requires its parameter fsCommand to be set to string that links it with actual fscommand sent from action script.

So in our case for example for opening levels we send fscommand from scaleform with argument (easier to compose it in actionscript than in kismet) that is the actual command to run in kismet and in kismet we just link this string argument and use it in another kismet action. Nevertheless we are sufficient with simple kismet node setup without the necessity to create a separate scheme (and devise separate command names) for each new level to load/resolution to set, etc.

Monday, October 8, 2012

Cookbook: Prefabs

Ever wondering how to compose some complex set of meshes with animations, sound effects, particles into one object with ability of easy instancing? Well, in this case Prefabs are just what you are looking for!

You can create them easily in UnrealEd and reuse wherever you need them without the need to painfully copy kismet schemes, setting all the different parameters, etc. And of course you can decompose your prefab, change a few things and create another version for later reuse.

Let's say we want to have doors that are opened by a button/lever (that requires at least button actor, door interpactor, matinee for doors and kismet assemble). Quite a lot to handle repeatedly if you can just instance one composed prefab instead ;). Here is an example how to create given prefab in editor:


  • insert individual meshes/archetypes for both button and door



  • prepare kismet setup and simple matinee with movement track for door InterpActor



  • with all individual parts set and selected, right click and choose Create Prefab... option. Choose package name, etc. and select Yes for prompt to found kismet sequence (to make it part of prefab) and replacing individual actors in scene with prefab. From now on you can insert another instances of this prefab setup from your Content Browser (and of course position/rotate them differently to work appropriately in your level).



  • in case you need to change some parts of prefab, select its instance and right click, Convert PrefabInstance To Normal Actors, update, create different version of prefab, etc.




Project demo (installer)

In case you'd like to try my current very early version of the project, grab installer from this site: http://tinyurl.com/9pkgq8t.

Basically you'll get stuff covered in this video:


It can be played on keyboard or using X360 gamepad. All controls are shown on HUD, I hope gameplay itself is rather self explanatory, goal of each level is to collect given number of coins. Stored local leaderboards let you replay the level and try to achieve better time, or fewer steps, etc.

Demo contains 3 levels with differing gameplay, it's a bit shaky and physics tends to be very fragile but maybe you will find it interesting and can definitely share some ideas, what you did like, what not, etc. Any comments are appreciated!

Friday, October 5, 2012

Cookbook: Sidescroller-like first person view

"I want to make a game like a Sidescroller but in first-person view. So you can only walk forward and backward and jump. No strafe to the left or right."

Based on this question in epicgames forums, I've taken some time to create a simple solution  (not superb, partially hardcoded, but you can continue from that) for anybody interested :).

Here we go:

I'll base all code changes on this cool tutorial for Sidescroller: http://udn.epicgames.com/Three/DevelopmentKitGemsPlatformerStarterKit.html

What we need to do is:
  • Update camera behavior so it is positioned in front of pawn and points in direction of positive Y axis
    • first part can be done in archetyped CameraProperties directly in Editor:
Experiment with StarterPlatformGameContent package (Content browser in editor) and change CameraProperties.CameraOffset vector:
FPS like view (X=0,Y=10,Z=50) -> camera slightly in front of pawn model, only weapon visible
over the arm camera (X=-20,Y=-20,Z=50) -> head, arms and weapon visible
    • second part requires simple code change (SPG_Camera.uc):

   1:  function UpdateViewTarget(out TViewTarget OutVT, float DeltaTime)
   2:  {
   3:     ...
   4:   
   5:     // Make the camera point towards the target's location
   6:     //REPLACE THIS:
   7:     //OutVT.POV.Rotation = Rotator(OutVT.Target.Location - OutVT.POV.Location);
   8:   
   9:     //WITH THIS:
  10:     //camera rotated to point in positive Y axis direction
  11:     OutVT.POV.Rotation = Rotator(vect(0,100,0));
  12:  }

  • update player input computation method to react on forward/backward keys (SPG_PlayerController.uc):

   1:  function PlayerMove(float DeltaTime)
   2:  {
   3:     ...
   4:    
   5:     //CHANGE THIS:
   6:     NewAccel = PlayerInput.aStrafe * Y;
   7:   
   8:     //INTO THIS:
   9:     //aBaseY input is moving forward/backward, we want pawn to move along Y axis
  10:     NewAccel = PlayerInput.aBaseY * vect(0,1,0);
  11:   
  12:     ...
  13:  }


  • Compile, run, experiment :)!




Enjoy!

Cookbook: Utilizing UDK states

State mechanics in UDK is very useful and makes it easier to organize the code into more readable form and have multiple behaviors ready and running at different times (states). Let's say you want to have your custom camera, that is by default sidescroller 3rd person and can be switched to overhead camera with a key input. Additionally you have a pause mode in your game, where it only slowly rotates around player character...

It's all easy to achieve with state machine in UDK. Let's see some basic syntax:


   1:  //switches given Object into new state
   2:  function GotoState (optional name NewState, ...)
   3:   
   4:  //////////////////////////////////////////////////////////////////////////
   5:  //state basic example
   6:  state ExploreLevel
   7:  {
   8:      //these functions are not processed in this state!
   9:      ignores SeePlayer, HearNoise, Bump, ...; 
  10:      
  11:      //this function has overriden behaviour in this state
  12:      function PlayerMove( float DeltaTime )
  13:      {
  14:          if (explorationKeyPressed)
  15:          {
  16:             BallPuzzlerCamera(PlayerCamera).Explore(DeltaTime);
  17:          else 
  18:          {
  19:             //no key pressed, use the global version of method!
  20:             global.PlayerMove(DeltaTime);
  21:          }
  22:      }
  23:      
  24:      Begin: //do something immediately after switching to this state!
  25:       BallPuzzlerCamera(PlayerCamera).SetBallActor(Ball);
  26:  }

Inside state code, you can utilize these useful keywords:

  • ignores - given methods are not processed while in this state
  • global.FunctionName -  calls default version of method
  • Begin: - called immediately after switching to this state (you can init some data)

Let's get back to our example. Some simple skeleton of what we want to achieve may look like this:


   1:  class BallPuzzlerCamera extends Camera;
   2:   
   3:  ...
   4:   
   5:  //state where we act as 3rd person sidescroller camera
   6:  state SideScroller
   7:  {
   8:    function UpdateViewTarget(out TViewTarget OutVT, float DeltaTime)
   9:    {
  10:      //sidescroller specific behavior
  11:    }
  12:  }
  13:   
  14:  //state where we place camera overhead
  15:  state Overhead
  16:  {
  17:    function UpdateViewTarget(out TViewTarget OutVT, float DeltaTime)
  18:    {
  19:      //overhead specific behavior
  20:    }
  21:  }
  22:   
  23:  //state where camera is rotation around level
  24:  state ExploreLevel
  25:  {
  26:      function UpdateViewTarget(out TViewTarget OutVT, float DeltaTime)
  27:      {
  28:          //level exploration behavior (rotate around level)
  29:      }
  30:   
  31:      Begin: //some init
  32:          ResetExploration();
  33:  }
  34:   
  35:  /////////////////////////////////////////////////////////////
  36:  //+ in controller class:
  37:  /////////////////////////////////////////////////////////////
  38:  enum E_CameraMode 
  39:  {
  40:      E_CM_Sidescroller,
  41:      E_CM_Overhead,
  42:      E_CM_Exploration
  43:  };
  44:   
  45:  var byte CurrentCameraMode;
  46:   
  47:  exec function ToggleCameraMode() //change camera mode with key binding
  48:  {
  49:     switch (CurrentCameraMode) //move to next state!
  50:     {
  51:        case E_CM_Sidescroller:
  52:           BallPuzzlerCamera(PlayerCamera).GotoState('Overhead'); break;
  53:        case E_CM_Overhead:
  54:           BallPuzzlerCamera(PlayerCamera).GotoState('ExploreLevel'); break;
  55:        case E_CM_Exploration:
  56:           BallPuzzlerCamera(PlayerCamera).GotoState('SideScroller'); break;
  57:     }
  58:   
  59:     //move variable to next state
  60:     CurrentCameraMode = 
  61:        CurrentCameraMode >= E_CM_Exploration ?
  62:        E_CM_Sidescroller : CurrentCameraMode + 1;
  63:  }

Thursday, October 4, 2012

Cookbook: Moving actors in UDK using physics

Imagine you have your ball actor and you want to control it with input keys. You want it to roll in some direction if the key is pressed. Very easy way to achieve this on rigid bodies is by utilizing physics.

You only need to have your actor PrimitiveComponent in PHYS_RigidBody state:


   1:  //========================================================================
   2:  defaultProperties
   3:  {   
   4:      Begin Object Name=StaticMeshComponent0
   5:          StaticMesh=StaticMesh'BallPuzzlerGame.Actors.PlayerBall'
   6:          bNotifyRigidBodyCollision=false
   7:          CastShadow=true
   8:          BlockRigidBody=true
   9:          bCastDynamicShadow=true
  10:          HiddenGame=false
  11:          LightEnvironment=MyLightEnvironment
  12:      End Object
  13:      Components.Add(StaticMeshComponent0)
  14:      
  15:      Physics=PHYS_RigidBody //set physics!
  16:  }

Then there are multiple possibilities how to move it using impulses/force, etc. (check PrimitiveComponent documentation for other possibilities):


   1:  native final function AddImpulse(vector Impulse, ...);
   2:   
   3:  native final function AddForce(vector Force, ...);

And of course, teleporting (useful for resetting to some initial position):


   1:  native final function SetRBPosition(vector NewPos, ...);

Let's see it in some example. I'm moving my ball-like actor using AddImpulse, applying custom gravity using AddForce and can interact (pick up, move, put down, throw) using SetRBPosition (overriding original one, while being held) and AddImpulse when throwing:

   1:  // Use the player's input to move character
   2:  simulated function AddInputForce(float DeltaTime, vector MovementDir)
   3:  {
   4:      StaticMeshComponent.AddImpulse(MovementDir * DeltaTime * Properties.Speed);
   5:  }
   6:   
   7:  //apply gravity in custom direction
   8:  simulated function GravityForce( float DeltaTime )
   9:  {
  10:       StaticMeshComponent.AddForce(GravityVector*Properties.Gravity);
  11:  }
  12:   
  13:  //handle being locked
  14:  simulated event Tick(Float DT)
  15:  {
  16:      //we are locked, follow owner, override default behaviour
  17:      if (lockInstigator != none)
  18:      {
  19:          StaticMeshComponent.SetRBPosition(lockInstigator.Location + lockTranslation);
  20:      }
  21:      else
  22:      {
  23:          super.Tick(DT); //basic behavior
  24:      }
  25:  }

Here is a video showing all this in motion:


Wednesday, October 3, 2012

Cookbook: UDK set of objects instead of a Pawn

Normally, UDK is mainly a framework for first/third person shooter games. Many things are hardcoded, like necessity to have a Pawn as you main character (or references to UT3 in DefaultEngine.ini). For smaller (indie) projects that is many times not desired. What if you want to be able to control a simple KActor or some set of objects (like chess pieces)? That is not a problem!

insert instances of desired objects into scene (I'm controlling one actor):



collect references to your objects in some early phase:


   1:  var MyActorClass MyActor
   2:   
   3:  simulated event PostBeginPlay()
   4:  {
   5:      super.PostBeginPlay(); //call parent
   6:      
   7:      //iterate through all actors of given class and store them!
   8:      foreach WorldInfo.DynamicActors(class'MyActorClass', MyActor)
   9:      {
  10:          //some additional init?
  11:          Init();
  12:          break; //if interested only in first one
  13:      }
  14:  }

override Pawn dependent behavior in your custom classes to work with your actors (example from custom 3rd person camera):


   1:  class MyCamera extends Camera;
   2:   
   3:  //override, use your actor as the point of interest for camera
   4:  function UpdateViewTarget(out TViewTarget OutVT, float DeltaTime)
   5:  {
   6:      super.UpdateViewTarget(OutVT,DeltaTime);
   7:   
   8:      //add some offset to the target's for 3rd person camera
   9:      OutVT.POV.Location = MyActor.Location + Properties.CamOffset;
  10:   
  11:      // Make the camera point towards the target's location
  12:      OutVT.POV.Rotation = Rotator(MyActor.Location - OutVT.POV.Location);
  13:  }



Cookbook: UDK timers

Timers in UDK are very useful if you want to call a postponed method (e.g. in 5seconds) or call something regularly (e.g. doing some statistics update each 10 seconds).

Syntax is very simple:


   1:  //set timer: (time to trigger,
   2:  //            true - repeated/false - once only,
   3:  //            method name to call in '')
   4:  SetTimer(2.0,,'MyTimerName');
   5:   
   6:  //stops timer execution
   7:  ClearTimer('MyTimerName');

Let's take a look at a simple example. Let's say we want to have a button that resets itself after given amount of time and additionally updates HUD with time left regularly (for HUD messaging see previous tutorial Cookbook: UDK cascading HUD messages, for kismet events see previous tutorial Cookbook: Triggering events, uscript -> kismet ).


   1:  class ButtonActorTimer extends ButtonActor;
   2:   
   3:  /** time for button to stay activated (then reset) */
   4:  var(Game) float fTimeToReset;
   5:   
   6:  /** time for tick (display message) */
   7:  var(Game) float fTimeToTick;
   8:   
   9:  var float fTimeLeft;
  10:   
  11:  //========================================================================
  12:  function TimeOut()
  13:  {
  14:      //trigger event with myself as instigator
  15:      self.TriggerEventClass(class'SeqEvent_ButtonReset', self);
  16:      Reset();
  17:  }
  18:   
  19:  //========================================================================
  20:  function TimeTick()
  21:  {
  22:      fTimeLeft -= fTimeToTick; //update time
  23:      Controller.StringToHUD(fTimeLeft$"..."); //show HUD message
  24:  }
  25:   
  26:  //========================================================================
  27:  function Set()
  28:  {
  29:      SetTimer(fTimeToReset,,'TimeOut'); //set new reset timer (called once)
  30:      fTimeLeft = fTimeToReset;
  31:      SetTimer(fTimeToTick,true,'TimeTick'); //ticking message (repeatedly)
  32:  }
  33:   
  34:  //========================================================================
  35:  function Reset()
  36:  {
  37:      ClearTimer('TimeOut'); //reset timer!
  38:      ClearTimer('TimeTick');
  39:  }

Button has two independent timers, one for reset (re-enable button, and send reset event to kismet) after time is up (door closes, etc.), second timer is for HUD update and sends time left message onto HUD.

Here is some ingame screenshot:


Tuesday, October 2, 2012

Cookbook: UDK cascading HUD messages

Many games have some messaging system on their HUDs (player picked up some power-up, have taken some damage, timer is ticking away, etc.). Using just the simple extension of HUD class, you can achieve similar results.

We'll use a simple structure to represent our message:


   1:  //message struct define
   2:  struct HUDMessage
   3:  {
   4:      var string sMessage;
   5:      var float fMessageTimer;
   6:  };

Simple method to display string on HUD (based on great vectorlab tutorial):


   1:  //========================================================================
   2:   function DrawString(string text, int X, int Y, int R, int G, int B, int A)
   3:   {
   4:      Canvas.SetPos(X, Y);
   5:      Canvas.SetDrawColor(R, G, B, A);
   6:      Canvas.Font = class'Engine'.static.GetMediumFont();    
   7:      Canvas.DrawText(text);
   8:   }

All messages are stored in a simple dynamic array and updated/displayed/removed each frame:


   1:  var array<HUDMessage> aMessages;
   2:   
   3:  //public method to be called from anywhere in game (your actors, etc.)
   4:  //========================================================================
   5:  function StringToHUD(string message, float timer = 0)
   6:  {
   7:      local HUDMessage newMessage;
   8:   
   9:      newMessage.sMessage = message;
  10:      newMessage.fMessageTimer = -timer; //make it appear longer, optional
  11:      
  12:      aMessages.InsertItem(0,newMessage); //insert at the beginning!
  13:  }
  14:   
  15:  //========================================================================
  16:  simulated event Tick(float DeltaTime)
  17:  {
  18:      local int i;
  19:   
  20:      //update message array
  21:      for (i = 0; i < aMessages.length; ++i)
  22:      {
  23:          aMessages[i].fMessageTimer += DeltaTime;
  24:      }
  25:  }
  26:   
  27:  //draw routine to display cascaded messages
  28:  //========================================================================
  29:  function DrawCustomMessage()
  30:  {
  31:      local HUDMessage message;
  32:      local offsetY = 200;
  33:          
  34:      foreach aMessages(message) //display all messages
  35:      {
  36:                  //message is still to be displayed
  37:          if (message.fMessageTimer < 2.0f)
  38:          {                                    
  39:              DrawString(message.sMessage,0,offsetY,255,255,255,255,true);
  40:              offsetY += 20; //update next message position
  41:          }
  42:          else //expired, remove
  43:          {
  44:              aMessages.RemoveItem(message);
  45:          }
  46:     }
  47:
  48:  }
  49:   
  50:  //========================================================================
  51:  function DrawHUD()
  52:  {
  53:      super.DrawHUD(); //don't forget to call parent method!
  54:      
  55:      DrawCustomMessage(); //our messaging routine
  56:   }

And here is an example screenshot directly from game:


Cookbook: UDK artist editable properties

Sooner or late in your development you'll come into phase when you have some game skeleton with a lot of parameters (camera, health, etc.). But how to tweak them without the necessity to update unrealscript (defaultproperties) and recompiling?

There are two approaches you can use. Let's take a closer look:

Instanced objects/actors

Each of your actors (buttons, movable/breakable objects, custom lights) will probably need some variables that are preferably tweakable by artist. Additionally each of there instances needs possibility to have differing values of parameters (imagine your ButtonActor with blue light and specific mesh vs other instance of ButtonActor with no light and different mesh).

This is easily achievable using named variables in unrealscript, syntax is really simple:


   1:  class ButtonActor extends Actor
   2:      ClassGroup(BallPuzzler)
   3:      placeable;
   4:   
   5:  // /** */ specifies comment visible for artist in editor
   6:  /** enables actor movement upon activation */
   7:  //(Game) specifies category for parameter in unreal editor
   8:  var(Game) bool bMove;
   9:   
  10:  /** movement offset from base position */
  11:  var(Game) vector vMoveOffset;
  12:   
  13:  /** sound to play upon activation */
  14:  var (Game) SoundCue activationSound;
  15:   
  16:  var(Light) const LightComponent    LightComponent;

This setup results in parameters being categorized in unreal editor into specified groups (F4 on selected actor):


I recommend to create archetype also for instanced objects to create subtypes (for example blue button, red button, healing button) and then use them to create instances (and edit few parameters per instance if necessary).

Not placeable objects


Ok, above mentioned steps work fine for instanced object that are being placed into game level. But what about objects without physical representation in editor (e.g. camera, controller, HUD, etc.)? Here we can create specific Properties object, that can be archetyped and it's parameters updated in content browser.


   1:  class BallPuzzlerProperties extends Object
   2:      HideCategories(Object);
   3:   
   4:  /** min distance from camera */
   5:  var(Camera) vector CamOffsetNear;
   6:   
   7:  /** max distance for camera */
   8:  var(Camera) vector CamOffsetFar;
   9:   
  10:  /** focus inner radius when in exploration mode */
  11:  var(PostProcess)   float fFocusRadiusExploration;
  12:   
  13:  /** movement speed */
  14:  var(Movement)   float Speed;
  15:   
  16:  /** jump force */
  17:  var(Movement)   float Jump;
  18:   
  19:  /** how much energy to drain at once */
  20:  var(Other)   float EnergyDrainAmount;
  21:   
  22:  /** distance to moveable object allowing its pickup */
  23:  var(Manipulate)   float PickupDistance;

Creating and archetype is really simple. Open your Content Browser, click on Actor classes tab, uncheck all checkboxes (as this is not placeable, nor actor) and find your properties object. Right click, create an archetype, specify your package and some cool name (like Properties ;) ) and there you go! From now on, all your global parameters are accessible via properties of this archetype (F4)




To have an access to properties archetype in unrealscript, just reference it in variables and default properties. After that you can access it as any default structure.


   1:  class BallPuzzlerCamera extends Camera;
   2:   
   3:  var const archetype BallPuzzlerProperties Properties; //declare variable
   4:   
   5:  ...
   6:   
   7:  //========================================================================
   8:  function ComputeCameraRotation(float DT)
   9:  {
  10:      local float partAngle;
  11:      
  12:      //use it!
  13:      partAngle = Properties.CamRotDelta * DT;
  14:   
  15:  ...
  16:   
  17:  defaultproperties
  18:  {
  19:      //define it as external from package
  20:      Properties=BallPuzzlerProperties'BallPuzzlerGame.Archetypes.Properties'
  21:  }

Monday, October 1, 2012

Cookbook: Triggering events, uscript -> kismet

Imagine you want to have a custom unrealscript actor (e.g. button). Obviously you want that button to introduce some interactivity to your scene/level. Let's say you want it to trigger some event for kismet (universal event that you want to be able to hook to any action available - play a matinee movie, toggle light, etc.)

What do we need?

1. create simple Seq_Event

All we need is a super simple event without any internal functionality. It's a good habit to organize it into some category (ObjCategory).


   1:  class SeqEvent_ButtonSet extends SequenceEvent;
   2:   
   3:  defaultproperties
   4:  {
   5:      ObjName="ButtonSet"       //kismet event name
   6:      ObjCategory="MyGame" //kismet event menu category
   7:      bPlayerOnly = false       //only pawn based actor can trigger?
   8:  }


2. trigger it from script

In our ButtonActor we need to trigger the given event somewhere. In this example it is triggered whenever touch event occurs (it'd be better to have some checks whether it's triggered by our pawn, some specific actor, etc.). To make our life easier, event is added to SupportedEvents in defaultproperties (this way it'll show in kismet right click menu when buttonActor is selected in scene).



   1:  class ButtonActor extends Actor
   2:      ClassGroup(MyGame) //group for actor classes menu (content browser)
   3:      placeable;
   4:   
   5:  ...
   6:   
   7:  //========================================================================
   8:  event Touch( Actor Other, PrimitiveComponent OtherComp, vector HitLocation, vector HitNormal )
   9:  {
  10:      //trigger event with myself as instigator
  11:      TriggerEventClass(class'SeqEvent_ButtonSet', self);
  12:  }
  13:   
  14:  ...
  15:   
  16:  defaultproperties
  17:  {  
  18:      SupportedEvents.Add(class'SeqEvent_ButtonSet') //to see it in kismet (selected actor, add event using actor...)
  19:  }

3. connect it to some kismet action

Here we need to insert an instance of our button into scene and (with button selected) in kismet right click Add event using actor -> you'll see our new event in submenu, add it! After that, all that is left is to connect it to whatever action you want. Example image shows button that plays open the door animation and turns matching color lights connected to door and button off.




Friday, September 28, 2012

Design ideas

Ok, so I have a sandbox testing playground of a game. But what to do with it next? Here are some of my ideas.



Settings:

  • post-apocalyptic settings
    • broken technology everywhere
    • placement in space (old space station? stars visible through windows?)
      • still partially functional
      • main goal is to repair station (collecting necessary spare parts while moving through levels)
      • levels are not fully accessible at start, you need to push correct buttons, levers to open some previously inaccessible corridors
    • main character is a small robot (or robots?)
      • body is basically a rotating sphere with some levitating head/arms
      • cute stylisation as in contrast to bleak world

Gameplay:

  • navigate through maze of corridors, get to the exit, fix given engine part, etc.
  • use abilities, solve puzzles to unlock inaccessible level parts
  • interactive environment: buttons, levers, inverse gravity fields, doors, elevators
  • with level progress growing set of abilities (pushing buttons, controlling gravity, controlling elevators, moving objects, etc.)
  • isometric top down camera?
  • co-op gameplay:
    • two robots with differing set of abilities
      • one can push buttons (opens door for other robot)
      • other robot can jump, move object (cover the hole in ground for other robot to cross)
      • ...
    • need to cooperate to unlock the path for other robot
    • good for singleplayer (switching between robots) as well as for multiplayer (each player one robot)