UDN
Search public documentation:

CLIKChatBox
日本語訳
中国翻译
한국어

Interested in the Unreal Engine?
Visit the Unreal Technology site.

Looking for jobs and company info?
Check out the Epic games site.

Questions about support via UDN?
Contact the UDN Staff

UE3 Home > User Interfaces & HUDs > Scaleform GFx > How to create a simple chat box

How to create a simple chat box


Last tested Sept UDK, 2011

Overview


This intermediate to advanced level tutorial will cover the steps needed for a rudimentary multiplayer multi-line chat window that works during game play, capturing all keyboard entry, and disallowing the game from capturing keyboard entry while it has focus. It will provide two ways to access the chat input - mouse click and keyboard command.

This tutorial assumes you are already very familiar with setting up and using Scaleform and CLIK widgets, and that you have a working mouse cursor in a Scaleform based HUD. The tutorial also required a good knowledge of replication.

ALERT! Important: This tutorial also requires the toggle-able mouse tutorial.

Flash Setup


Text Input Box

  • Drop a CLIK TextInput widget onto your HUD. (C:\UDK\UDK-2011-09\Development\Flash\CLIK\components\TextInput.FLA )
  • Give it an instance name of chatInput.
  • Open the Component Inspector (CS4) or the Component Parameters rollout (CS5) and enable 'actAsButton'.

Send Button

  • Next drop a CLIK Button widget next to the TextInput widget. (C:\UDK\UDK-2011-09\Development\Flash\CLIK\components\Button.FLA)
  • Give it an instance name of chatSendBtn.
  • Open the Component Inspector (CS4) or the Component Parameters rollout (CS5) and enter 'Send' in the label field of the button.

Multi-line Scrollable Chat Log

  • Drop a CLIK Text Area widget above the TextInput widget. (C:\UDK\UDK-2011-09\Development\Flash\CLIK\components\TextArea.FLA)
  • Give it an instance name of chatLog.
  • Open the Component Inspector (CS4) or the Component Parameters rollout (CS5) and disable 'editable'.
  • Drop a CLIK Scroll Bar widget to the right of the TextInput widget. (C:\UDK\UDK-2011-09\Development\Flash\CLIK\components\Scrollbar.FLA )
  • Give it an instance name of chatScrollBar.
  • Select the Text Area, and open the Component Inspector (CS4) or the Component Parameters rollout (CS5) and set the scrollBar field of the Text Area to chatScrollBar.

Chat form

  • Align the four widgets on stage so they are all near each other, forming a box. You can stretch (non-uniform scale) the widgets as needed.
  • Select all four widgets on the stage, right click, and choose Convert to Symbol.
  • Set the Name to chatForm
  • Set the Type to Movie Clip.
  • Enable Export for ActionScript & Export in frame 1.
  • Set the Identifier to chatForm
  • Set the Class to gfx.core.UIComponent
  • Press OK.
  • Delete the chatForm movie clip form the stage, leaving it in the library.

Chat window

  • Copy the file \Development\Flash\CLIK\demos\com\Scaleform\Window .as to \Development\Flash\CLIK\gfx\controls\Window.as
  • Open this class file and change line 7 (the class declaration line) to this:

ActionScript
class gfx.controls.Window extends UIComponent {

  • Open the file \Development\Flash\CLIK\demos\WindowDemo.FLA.
  • Go to the Library panel of this file.
  • Select the WindowSkinned symbol.
  • Right click the WindowSkinned symbol and select Copy.
  • Return to your HUD FLA file.
  • Right click on the stage and select Paste to paste the Window symbol in place.
  • Align the window near the bottom left of the stage.
  • Give it an instance name of chatWindow.
  • With the chatWindow selected on stage, open the Component Inspector (CS4) or the Component Parameters rollout (CS5).
  • Set the formSource to chatForm.
  • Ensure formType is set to symbol.
  • Set maxHeight & maxWidget to 400.
  • Set minHeight and minWidget to 200.
  • Set offsetBottom to 24, offsetLeft to 20, offsetRight to 20, and offsetTop to 46, or whatever works for you after testing.
  • Set title to Chat.
  • Right click the WindowSkinned symbol in the Library Panel and select Properties.
  • Change the Class field to gfx.controls.Window and press OK.
  • Right click the symbol again and choose Component Definition.
  • Change the Class field to gfx.controls.Window and press OK.
  • Save, Publish, and Import your SWF into UDK as usual. You should now have a draggable chat window on the stage, which contains the chat input, chat area, send button, and scrollbar.

HUD Class UnrealScript


Your HUD Class should extend GFxMoviePlayer. Add these new variables to your UnrealScript HUD Class file:

YourHUD.uc
var WorldInfo ThisWorld;
var SFPlayerController PC;

var array<string> chatMessages; // this will hold all the chat messages
var bool bChatting;

// These are our CLIK widgets for the chat system
var GFxClikWidget MyChatInput, MyChatSendButton, MyChatLog;

Modify your Start()/Init() function as follows (add the red lines):

YourHUD.uc
function Init(optional LocalPlayer player)
{
  super.Init(player);
  ThisWorld = GetPC().WorldInfo;

  Start();
  Advance(0);

  // ... other initialization code here ...

  // Register the HUD with the PlayerController
  PC = SFPlayerController(GetPC());
  PC.registerHUD(self);
}

Modify the ToggleCursor() function (from the Mouse tutorial earlier).

YourHUD.uc
/** Toggles mouse cursor on/off */
function ToggleCursor(bool showCursor, float mx, float my)
{
  if (showCursor)
  {
    MouseContainer = CreateMouseCursor();
    MouseCursor = MouseContainer.GetObject("my_cursor");
    MouseCursor.SetPosition(mx,my);
    MouseContainer.SetBool("topmostLevel", true);
  }
  else
  {
    MouseContainer.Invoke("removeMovieClip", args);
    MouseContainer = none;
  }

  if (!bChatting)
  {
    bCaptureInput = showCursor;
    bIgnoreMouseInput = !showCursor;
  }
  else
  {
    bCaptureInput = true;
    bIgnoreMouseInput = false;
  }
}

Now modify the WidgetInitialized() function of your HUD and set up event listeners for mouse click events on the chat text input field and the chat send button:

YourHUD.uc
event bool WidgetInitialized(name WidgetName, name WidgetPath, GFxObject Widget)
{
  switch(WidgetName)
  {
  case ('chatInput'):
    MyChatInput = GFxClikWidget(Widget);
    MyChatInput.AddEventListener('CLIK_press', OnChat);
    break;

  case ('chatSendBtn'):
    MyChatSendButton = GFxClikWidget(Widget);
    MyChatSendButton.AddEventListener('CLIK_press', OnChatSend);
    break;

  case ('chatLog'):
    MyChatLog = GFxClikWidget(Widget);
    break;

  default:
    break;
  }

  return true;
}

Add the OnChat() event handler.

YourHUD.uc
// Event Handler - handles when the player clicks on the chat box text input field.
function OnChat(GFxClikWidget.EventData ev)
{
  bChatting = true;
}

Add the OnChatSend() function. This function broadcasts the message when the Send button is pressed, and returns control to the game.

YourHUD.uc
function OnChatSend(GFxClikWidget.EventData ev)
{
  local string Msg;

  Msg = MyChatInput.GetString("text");

  if (Msg != "")
  {
    PC.SendTextToServer(PC, Msg);
  }

  MyChatInput.SetString("text", "");
  self.bCaptureInput = false;
  bChatting = false;
}

Now, for the function that updates the chat area, displaying each message received thus far from Broadcast():

YourHUD.uc
function UpdateChatLog(string message)
{
  local string displayMsg;
  local int i;

  chatMessages.AddItem(message);

  displayMsg = "";

  for (i = 0; i < chatMessages.length; i++)
  {
    displayMsg @= chatMessages[i];
    displayMsg @= "\n";
  }

  MyChatLog.SetString("text", displayMsg);
  MyChatLog.SetFloat("position", MyChatLog.GetFloat("maxscroll"));
}

Add the widget bindings and other important variables in your default properties:

YourHUD.uc
defaultproperties
{
    WidgetBindings.Add((WidgetName="chatInput",WidgetClass=class'GFxClikWidget'))
    WidgetBindings.Add((WidgetName="chatSendBtn",WidgetClass=class'GFxClikWidget'))
    WidgetBindings.Add((WidgetName="chatLog",WidgetClass=class'GFxClikWidget'))

    bIgnoreMouseInput = true;
    bCaptureInput = false;
}

GameInfo Class Setup


Open your GameInfo class.

Only add these variables to your game info class, if it does not extend UTGame or a child of UTGame, such as UTDeathmatch. You will get a warning on compile, if these variables are already being declared. If so, remove them from your game info class.

YourGameInfo.uc
var class<BroadcastHandler> BroadcastHandlerClass;
var BroadcastHandler BroadcastHandler;   // handles message (text and localized) broadcasts

Next, add this line to the InitGame() function in your GameInfo class:

YourGameInfo.uc
event InitGame( string Options, out string ErrorMessage )
{
    Super.InitGame(Options, ErrorMessage);
    BroadcastHandler = spawn(BroadcastHandlerClass);
}

Inside our GameInfo class, we'll override the Broadcast event class from \Development\Src\Engine\Classes\GameInfo.uc

YourGameInfo.uc
event Broadcast(Actor Sender, coerce string Msg, optional name Type)
{
  local SFPlayerController PC;
  local PlayerReplicationInfo PRI;

  // This code gets the PlayerReplicationInfo of the sender. We'll use it to get the sender's name with PRI.PlayerName
  if (Pawn(Sender) != None)
  {
    PRI = Pawn(Sender).PlayerReplicationInfo;
  }
  else if (Controller(Sender) != None)
  {
    PRI = Controller(Sender).PlayerReplicationInfo;
  }

  // This line executes a "Say"
  BroadcastHandler.Broadcast(Sender, Msg, Type);

  // This is where we broadcast the received message to all players (PlayerControllers)
  if (WorldInfo != None)
  {
    ForEach WorldInfo.AllControllers(class'SFPlayerController',PC)
    {
      `Log(Self$":: Sending "$PC$" a broadcast message from "$PRI.PlayerName$" which is '"$Msg$"'.");
      PC.ReceiveBroadcast(PRI.PlayerName, Msg);
    }
  }
}

Last of all, add these lines to your GameInfo class' default properties, being sure to modify them with your class names:

YourGameInfo.uc
defaultproperties
{
  PlayerControllerClass=class'SFPlayerController'
  BroadcastHandlerClass=class'Engine.BroadcastHandler'
  HUDType=class'SFTutorial.SFHudWrapper'
  bUseClassicHUD=true
}

PlayerController Class Setup


Create/Open the PlayerController class (in this case: SFPlayerController):

SFPlayerController.uc
class SFPlayerController extends UTPlayerController;

First we'll create a function that registers the HUD inside the PlayerController so we can easily call functions in the HUD from the PlayerController:

SFPlayerController.uc
var SFHud MySFHud;

function registerHUD(SFHud hud)
{
  MySFHud = hud;
}

The next function is used to send a message to the server:

SFPlayerController.uc
exec function SendTextToServer(SFPlayerController PC, String TextToSend)
{
  `Log(Self$":: Client wants to send '"$TextToSend$"' to the server.");
  ServerReceiveText(PC, TextToSend);
}

This function is used to receive a server message and then broadcast it:

SFPlayerController.uc
reliable server function ServerReceiveText(SFPlayerController PC, String ReceivedText)
{
  WorldInfo.Game.Broadcast(PC, ReceivedText, 'Say');
}

Last of all, we need to create a client function that listens for broadcasts from the server, and routes them to the chat window:

SFPlayerController.uc
reliable client function ReceiveBroadcast(String PlayerName, String ReceivedText)
{
    `Log(Self$":: The Server sent me '"$ReceivedText$"' from "$PlayerName$".");
    MySFHud.UpdateChatLog(PlayerName @ ": " @ ReceivedText);
}

Enable Chatting Via Keyboard Command (Pressing Enter)

For this step, we'll use the Enter key to begin chatting, as well as sending (completing) the chat message. You can however use whatever key you want.

Adding the key binding

Open DefaultInput.ini, and add the following line:

.Bindings=(Name="Enter",Command="ChatHandler")

ALERT! Note: You will need to comment out or delete the following line for the pressed key to work for chatting:

.Bindings=(Name="Enter",Command="GBA_Use")

HUDWrapper Class Setup

Open your HUDWrapper. This is the class that instantiates the HUD. Add the function that will be executed on key press.:

YourHUDWrapper.uc
exec function ChatHandler()
{
  HudMovie.ToggleChat(); // Replace HudMovie with the reference name of your HUD movie.
}

HUD Class Setup

Open your HUD class.

First, we need to ensure that our chosen key is never captured as input by our HUD movie. We do this by adding it to the focus ignore key list. Add this line to your Start()/Init() function:

AddFocusIgnoreKey('Enter');

Next, add a function that will enable chatting via keyboard command. This function is called by the HUDWrapper:

function ToggleChat()
{
  if (!bChatting)
  {
    bCaptureInput = true;
    OnChat();
  }
  else
  {
    bCaptureInput = false;
    OnChatSend();
  }
}

Next, modify the OnChat() and OnChatSend() function parameters so that they are optional:

function OnChat(optional GFxClikWidget.EventData ev)
function OnChatSend(optional GFxClikWidget.EventData ev)

Now modify the OnChat() function by adding this line of code:

MyChatInput.SetBool("focused", true);

And finally, modify the OnChatSend() function with this line of code:

MyChatLog.SetBool("focused", true);

Recompile scripts, and test your HUD.

Downloads


  • Download UDK_September2011_ScaleformSandboxFiles.zip.