Announcement

Collapse
No announcement yet.

[RTS Style UI] Mouse Clicking on Buttons in the HUD During Gameplay

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

    [RTS Style UI] Mouse Clicking on Buttons in the HUD During Gameplay

    This tutorial demonstrates one possible solution to having working UI buttons, etc. and a working mouse cursor in the HUD, while still playing the game. (The cursor and buttons are always visible and usable)

    Without built in hit detection in the backend of the Scaleform GFx integration into UDK, it's a bit of a challenge to pull this off. But, here is a rough solution I worked out for allowing the player to play the game, and use a mouse cursor to click on buttons in the HUD using FilterButtonInput. It's a bit of a hack, and I'm sure it could use some clean up. This might work well for an RTS style game, where the mouse cursor is always visible. I'm sure other UDK teams have figured out other ways to achieve a similar result.

    NOTE: We will very likely work with Epic to incorporate proper hit detection for GFx in a future build of UDK.


    HUD Wrapper Class (UTGFxHudWrapper.uc)

    The HUD Wrapper's primary job is to instantiate the HUD and Mouse. It contains the following code:

    Code:
    class UTGFxHudWrapper extends UTHUDBase;
    
    var GFxMinimapHud    HudMovie;
    
    var class<GFxMinimapHUD> MinimapHUDClass;
    
    simulated function PostBeginPlay()
    {
        super.PostBeginPlay();
    
        CreateHUDMovie();
    }
    
    function CreateHUDMovie()
    {
        HudMovie = new MinimapHUDClass;
        HudMovie.SetTimingMode(TM_Real);
        HudMovie.SetViewScaleMode( SM_NoScale );
        HudMovie.SetAlignment( Align_BottomCenter );
        HudMovie.Init(class'Engine'.static.GetEngine().GamePlayers[HudMovie.LocalPlayerOwnerIndex]);
    }
    
    event PostRender()
    {  
        super.PostRender();
    
        if (HudMovie != none)
    	HudMovie.TickHud(0);
    }
    
    defaultproperties
    {
        bEnableActorOverlays = true
        MinimapHUDClass = class'GFxMinimapHUD'
    }

    HUD Class (GFxMinimapHud.uc)


    This is the actual HUD Class. It updates the HUD, initializes any interactive buttons on the HUD, filters input when the player mouses over a button, and handles player interaction with those buttons. It contains the following code:

    Code:
    class GFxMinimapHud extends GFxMoviePlayer;
    
    var bool bRollOver; // is the mouse cursor over a button?
    var string focusedButton; // what is the name of that button?
    var GFxClikWidget MyHudButton; // reference to a CLIK button in the HUD
    
    function Init(optional LocalPlayer player)
    {	
        super.Init(player);
    
        Start();
        Advance(0);
    }
    Next we tell UDK to setup rollOver and rollOut event listeners for each CLIK button (or UI element) in the HUD when they are initialized. In the case of this tutorial, we only have one CLIK button (myHudButton).

    Code:
    event bool WidgetInitialized(name WidgetName, name WidgetPath, GFxObject Widget)
    {    
        switch(WidgetName)
        {                 
            case ('myHudButton'): // myHudButton is the instance name of the CLIK button in Flash.
                MyHudButton = GFxClikWidget(Widget);
    	    MyHudButton.AddEventListener('CLIK_rollOver', OnRollOver);
    	    MyHudButton.AddEventListener('CLIK_rollOut', OnRollOut);			
                break;
            default:
                break;
        }
        return true;
    }
    The onRollOver functions fires off when the user's mouse is over the button. It sets the bRollOver boolean to true and sets focusedButton to have the name of the button currently rolled over.

    Code:
    function onRollOver(GFxClikWidget.EventData ev) 
    {
        `log("###### Button rolled over! ");
        bRollOver = true;
        focusedButton = ev.target.GetString("_name");
    }
    The onRollOut functions returns bRollOver to false, since the user is no longer over the button, and clears the focusedButton name.

    Code:
    function onRollOut(GFxClikWidget.EventData ev) 
    {
        `log("###### Button rolled out! ");
        bRollOver = false;
        focusedButton = "";
    }
    
    function TickHud(float DeltaTime)
    {
        // Do all HUD updates here...
    }
    This next function is fired off when the user presses a button. It first tests to see if bRollOver is true, and whether or not the button pressed was the left mouse button.

    Code:
    event bool FilterButtonInput(int ControllerId, name ButtonName, EInputEvent InputEvent)
    {
        if (self.bRollOver == true && ButtonName == 'LeftMouseButton')
        {
    If both conditions are true, it then tests to see if the event received is a pressed event or a released event.

    Code:
    	if (InputEvent == IE_Pressed)
    	{
    If pressed, it then runs through the list of potential buttons clicked on using the information stored in focusedButton. If myHudButton is the focused button, then it tells Flash to goto the down state of that button, and fires off the myHudButtonPressed function.

    Code:
    	    switch (focusedButton)
    	    {
    		case ("myHudButton"):
    		    `log ("Focused Button Pressed: "@focusedButton);
    		    MyHudButton.gotoAndPlay("down");
                        myHudButtonPressed();
    		    break;
    		default:
    		    break;
    	    }
    	}
    	else if (InputEvent == IE_Released)
    	{
    	    switch (focusedButton)
    	    {
    		case ("myHudButton"):
                        `log ("Focused Button Released: "@focusedButton);
    		    MyHudButton.gotoAndPlay("over");
    		    break;
    		default:
    		    break;
    	    }
    	}
    	return true;
        }
        return false;
    }
    This function is where you would code the result of pressing myHudButton.

    Code:
    myHudButtonPressed()
    {
        // Do cool stuff...
    }
    
    defaultproperties
    {
        WidgetBindings.Add((WidgetName="myHudButton",WidgetClass=class'GFxClikWidget'))  
        MovieInfo = SwfMovie'UDKTutorial.myHUD.myHUD'
        bIgnoreMouseInput = false
        bDisplayWithHudOff = false
        bEnableGammaCorrection = false
        bPauseGameWhileActive = false
        bCaptureInput = false
    }

    The HUD SWF (myHUD.SWF)


    The HUD SWF file contains a single CLIK button, with an instance name of 'myHudButton'. It also contains a cursor graphic with an instance name of 'my_cursor'. It is saved under: \Flash\UDKTutorial\myHUD\myHUD.SWF.

    The file contains the following ActionScript on frame 1 as well:

    ActionScript 2.0 Code

    Code:
    import flash.external.ExternalInterface;
    _global.gfxExtensions = true;
    
    Mouse.hide();
    
    var mouseListener:Object = new Object();
    
    mouseListener.onMouseMove = function ()
    {
        my_cursor._x = _root._xmouse;
        my_cursor._y = _root._ymouse;
    };
    
    Mouse.addListener(mouseListener);
    
    stop();

    #2
    Matt, thank you for your posts on the forum here as well as those getting started videos on youtube. They are very clear and to the point and have definitely helped me get started.

    I'm building a game that is very menu driven, and very little direct input needs to go the game. I suppose, when looking at it, the question is: what is the benefit of using the HUD class instead of just loading the menu movies as needed? I've already created a simple top level frame with a mouse cursor based on the manager movie included with the demo assets in the UDK, and I'm using kismet to load that on the level load, using your youtube videos as a guide.

    I figure that way, the proper menus can be loaded into that manager object as needed based on the portion of the game you are in. Should I be using the HUD for this instead?

    Comment


      #3
      I don't know that there is a benefit. I'd say do what works best for you.

      Comment


        #4
        Thanks Matt.

        Comment


          #5
          Thanks very much, this is the most straightforward method that I have seen so far for implementing an RTS Style HUD with flash.

          Comment


            #6
            Are there any changes in the latest builds? I find it hard to believe that something THAT fundamental hasn't been fixed yet...

            Comment

            Working...
            X