Lab 6 - Advanced Canvas, Basic Picking

Summary

You will implement a more advanced hud utilizing screen textures as well as basic cursor selection.

Learning Outcomes

  • Ability to use Canvas in a more advanced way
  • Familiarity with basic picking techniques

Files to Implement

  • L7Game.uc
  • L7HUD.uc
  • L7Pawn.uc
  • L7Player.uc
  • L7PlayerInput.uc
  • L7Selectable.uc
  • L7-Map.udk

Submission Requirements

Show your completed lab to your instructor(s). Your end result should look something like this:

Neutral (nothing selected, cursor control inactive)

Neutral

Selecting (cursor control active)

Selecting

Neutral, After Selecting (pawn selected, cursor control inactive)

After Selecting

Instructions

Download the file L7Content.upk and place it in UDKGame/Content. You may add it to your repository.

Lab7 Package

Create and set up a new development package, name it Lab7. The following code should reside in the Lab7 package.

L7Game

  • Create the class L7Game extending UTGame
  • Set up the default properties as follows:
    • Set the hud type for this game to be the class L7HUD
    • Set bUseClassicHUD to true
    • Set element 0 for MapPrefixes array to "L7"
    • Set the default player controller class to L7Player
    • Set the default pawn class to the class L7Pawn (variable name: DefaultPawnClass)

In order for this class to compile successfully at this point in the lab, you will need to create stub versions of the referenced classes (L7Pawn will extend UTPawn).

L7-Map.udk

After successfully compiling the above (create the required stubs), create the map L7-Map.udk and save it in UDKGame/Content/Maps.

Add a few player starts to the map before saving it, this will make bots spawn more evenly. Make sure that you rebuild map paths after you do this.

L7Selectable

  • Create the interface L7Selectable
  • This interface doesn't necessarily need any functions but you may have it prototype a function named GetLocation3D which returns a vector and accepts nothing

L7Pawn

  • Create the class L7Pawn, it should extend UTPawn and implement L7Selectable
  • If you wrote L7Selectable to have the function GetLocation3D then implement that function and have it return the actor's current location
    • Otherwise, you're done for this class

L7PlayerInput

  • Create the class L7PlayerInput which extends UTPlayerInput
  • This class should have 3 member variables:
    • Variable of type IntPoint named MousePosition
    • Variable of type bool named bControllingCursor
    • Variable of type bool named bAttemptSelect
  • Create the exec function ToggleControllingCursor
    • It should invert the current value of bControllingCursor ie set it to false if it is true and set it to true if it is false
  • Create the exec function StartAttemptSelect
    • If cursor control (bControllingCursor) is currently true, it should set bAttemptSelect to true
    • Otherwise, it should do nothing
  • Override the function PlayerInput which accepts a float deltatime, and returns nothing
    • This function should first call its super version
    • Then, if cursor control is active:
      • It should update the values in the MousePosition variable with the values in aMouseX and aMouseY
        • Take care that MousePosition's members do not exceed the size of the screen or go below 0
          • You can use the Clamp function for this (look it up in Object.uc)
        • Take care that aMouseY is subtracted as opposed to added to MousePosition.Y as the values are the inverse of how you would expect a mouse to behave
        • The values in aMouseX and aMouseY are likely too large, multiply them by a suitable factor before addition, for example 0.1

L7Player

  • Create the class L7Player, it should extend UTPlayerController
  • In default properties, set the InputClass member to class'L7PlayerInput'
  • Override the UpdateRotation function, which accepts a float deltatime, and returns nothing
    • This function should check if cursor control is currently active
      • If it is NOT, it should call the super version of this function
      • Otherwise, it should do nothing
  • Override the exec function StartFire, which accepts an optional byte FireModeNum, and returns nothing
    • This function should check if cursor control currently active
      • If it is NOT, it should call the super version of this function
      • Otherwise it should do nothing

L7HUD

  • Have this class extend HUD
  • Add a class member typed Actor and named Selected
  • Create the function DrawCenteredTextureOnCanvas, returning a Vector2D, and accepting two arguments:
    • A Texture2D named tex
    • A float named screenScale
  • This function will:
    • Store the current canvas position in a local variable
    • Update the current canvas position such that the texture that was passed in is drawn centered around the current coordinates (Canvas.DrawTexture interprets the current screen position as the top left corner of the texture)
    • Use the function Canvas.DrawTexture which accepts a Texture2D and a scale, calculating a scale such that:
      • The texture occupies the proportion of vertical screen space passed in through screenScale
      • You will find the scale by finding how many pixels the texture should take by multiplying the passed in scale by the vertical height of the screen (the SizeX member in HUD) then dividing that result by the vertical size of the texture
    • Restore the current canvas position before returning
    • Return the size of the drawn texture in on-screen pixels, stored in a Vector2D (Vector2D objects have X and Y members but no Z)
  • Create the function DrawHUD, returning nothing and accepting nothing
    • This function should iterate over all L7Selectable interface Actors in the scene, drawing a selectable square texture on the screen position of each of these actors
      • The screen scale of the selection square should be 0.1
      • If cursor control is currently off, the selection rectangles should be drawn white
        • Otherwise, they should be drawn red or pink
      • Use the DrawCenteredTextureOnCanvas function defined above to do this
      • Use the Canvas projection function to find the on-screen position of an actor
        • While you may use Actor's Location member to find the current 3D location of actors in question, the slightly cleaner approach would be to use the GetLocation3D function we defined above (if you defined it) since we know that every actor that we are iterating over implements L7Selectable
        • You can cast an Actor to an interface like you can cast anything else
      • Your function should not draw a selectable rect for the player's pawn
      • Your function should not draw a selectable rect for actors whose screen coords x or y members are less than 0 or greater than the screen's SizeX and SizeY, respectively
      • Your function should not draw a selectable rect for actors whose screen coords z member is less than or equal to 0
      • The currently selected actor should have the texture L7Content.Selected drawn on it
        • All other selectable actors should have the texture L7Content.Selectable
    • This function should draw a targeting reticle at the current mouse coords
      • The screen scale of the targeting reticle should 0.1
      • If the reticle's center is within the bounds of a selectable rectangle, the reticle should use the L7Content.ReticlePicking texture
      • Otherwise, the L7Content.Reticle texture should be used
      • If cursor control is currently off, the reticle should be white
        • Otherwise, it should be green
    • This function should update the selection state if the player input's bAttemptSelect variable is true
      • If the player input's bAttemptSelect variable is true, this class should attempt to select something then after the attempt, bAttemptSelect should be set to false
      • To attempt selection, the list of actors implementing the L7Selectable interface should be iterated over
        • The player's own pawn should not be considered for selection
      • The closest selectable actor to the screen whose selectable rectangle overlaps the center of the reticle should be set as selected
        • This is indicated by setting the Selected member variable equal to it
      • Finding the closest actor to the screen can be found by finding the actor with the smallest Z member when its location is projected using canvas
      • If no suitable actors are found, Selected should be set to None

DefaultInput.ini

  • Bind the Z key to the command ToggleControllingCursor
  • Bind the left mouse button to the commands GBA_Fire and StartAttemptSelect