1
0
KF2-Dev-Scripts/GameFramework/Classes/MobilePlayerInput.uc

1036 lines
29 KiB
Ucode
Raw Normal View History

2020-12-13 15:01:13 +00:00
/**
* MobilePlayerInput
*
* This is the base class for processing input for mobile devices while in the game
*
* Copyright 1998-2013 Epic Games, Inc. All Rights Reserved.
*/
class MobilePlayerInput extends PlayerInput within GamePlayerController
native
DependsOn(MobileInputZone)
config(Game);
/**
* This structure contains data for individual touch events queued for a specific touch handle
*/
struct native TouchDataEvent
{
/** Holds the type of event */
var ETouchType EventType;
/** What touchpad this came from */
var byte TouchpadIndex;
/** Holds the current location of the touch */
var vector2D Location;
/** Holds the device timestamp of when this event occurred */
var double DeviceTime;
};
/**
* the MPI keeps track of all touches coming from a device. When the status of a touch changes, it tracks it and then passes it along to
* the associated MobileInputZone.
*/
struct native TouchData
{
/** Holds the ID of the current touch */
var int Handle;
/** What touchpad this came from */
var byte TouchpadIndex;
/** Holds the current location of the touch */
var vector2D Location;
/** Total distance that the finger moved since it initially touched down */
var float TotalMoveDistance;
/** Holds the device timestamp of when the original touch occurred */
var double InitialDeviceTime;
/** How long this touch has been active */
var float TouchDuration;
/** Device timestamp of most recent event */
var double MoveEventDeviceTime;
/** Time delta between the movement events the last time this touch moved */
var float MoveDeltaTime;
/** If true, this touch entry is in use, otherwise feel free to use it for touches */
var bool bInUse;
/** Holds the zone that is currently processing this touch */
var MobileInputZone Zone;
/** Holds the current state of the touch */
var ETouchType State;
/** Events queued up for this touch. Because we may receive several touch movement events per tick,
we store a list of events and process them in order when we can. */
var array<TouchDataEvent> Events;
/** Holds the last active time (via TimeSeconds()) that will be used to timeout a zone */
var float LastActiveTime;
};
/**
* This enum contains the orientations of the interface (not the device)
* The order of this currently matches the IPhone and changing it will break that device unless you fix those references
*/
enum EUIOrientation
{
UI_Unknown,
UI_Portait,
UI_PortaitUpsideDown,
UI_LandscapeRight,
UI_LandscapeLeft,
};
/** Keeps track of all of the touches currently active on a device */
const NumTouchDataEntries = 5;
var (Input) TouchData Touches[NumTouchDataEntries];
/**
* The object that the user is currently interacting with.
* e.g. When a user presses on the button, this button is the
* interactive object until the user raises her finger and causes
* an UnTouch event.
*/
var MobileMenuObject InteractiveObject;
/** Last time interactive object process input */
var double InteractiveObjectLastTime;
/** Defines a mobile input group */
struct native MobileInputGroup
{
/** The name of this group */
var string GroupName;
/** The List of zones associated with this group */
var editinline array<MobileInputZone> AssociatedZones;
};
/** Holds a list of available groups */
var (Input) EditInline array<MobileInputGroup> MobileInputGroups;
/** Holds the index of the current group */
var (Input) int CurrentMobileGroup;
/** Holds a list of mobile input zones. */
var (Input) editinline array<MobileInputZone> MobileInputZones;
/** Record of each MobileInputZone class (and subclasses) instances */
struct native MobileInputZoneClassMap
{
/* Name of the instance */
var string Name;
/* Class type of the instance */
var class<MobileInputZone> ClassType;
};
/** Classes that inherit from MobileInputZone - filled in by NativeInitializeInputSystem() */
var array<MobileInputZoneClassMap> MobileInputZoneClasses;
/** Holds the current Tilt value for mobile devices */
var (Input) float MobilePitch;
/** Holds the center value for the pitch. */
var (Input) float MobilePitchCenter;
/** Pitch sensitivity */
var (Input) float MobilePitchMultiplier;
/** Holds the current Yaw value for mobile devices */
var (Input) float MobileYaw;
/** Holds the center value for the Yaw. */
var (Input) float MobileYawCenter;
/** Pitch sensitivity */
var (Input) float MobileYawMultiplier;
/** How much of a dead zone should the pitch have */
var (input) config float MobilePitchDeadzoneSize;
/** How much of a dead zone should the yaw have */
var (input) config float MobileYawDeadzoneSize;
/** Used to determine if a touch is a double tap */
var (input) config float MobileDoubleTapTime;
/** You have to hold down a tap at least this long to register it as a tap */
var (input) config float MobileMinHoldForTap;
/** Used to determine how quickly to send repeat events for touch+held */
var (input) config float MobileTapRepeatTime;
/** If true, we want to allow input to occur during a cinematic */
var (input) bool bAllowTouchesInCinematic;
/** If set to true, then touches will be ignored */
var (input) bool bDisableTouchInput;
/** if set pass absolute touch locations instead of relative to the viewport location
* (i.e. if this is true don't subtract MobileViewportOffset from touch locations)
*/
var (input) config bool bAbsoluteTouchLocations;
/** Holds the amount of time that a zone can go without input before being consider timed out */
var (input) config float ZoneTimeout;
/** If true this will collapse similar mobile inputs so that they won't get processed */
var (input) config bool bCollapseTouchInput;
// **********************************************************************************
// The MobilePlayerInput is also the hub for the mobile menu system.
// **********************************************************************************
/** This is the menu stack. */
var (menus) array<MobileMenuScene> MobileMenuStack;
/** Used for debugging native code */
var (debug) string NativeDebugString;
/** This will be set in NativeInitializeInputZones if -SimMobile is on the command line. */
var (debug) bool bFakeMobileTouches;
// Holds the amount of time the view port has been inactive
var (Current) float MobileInactiveTime;
// Ability to disable rendering of scenes.
var (debug) bool bDisableSceneRender;
// **********************************************************************************
// Motion support
// **********************************************************************************
/**
* A General note about the DeviceMotion* variables. The engine will attempt to use any motion sensing system
* built in to the device to fill out these values. For values not supported by the device, we will attempt to generate
* values given the capibilites. but so values may not be available / reliable
*/
/** Holds a list of handlers looking to listen in on Motion events */
var (Current) array<SeqEvent_MobileBase> MobileSeqEventHandlers;
/** Holds a list of handlers looking to listen in on raw touch events */
var (Current) array<SeqEvent_MobileRawInput> MobileRawInputSeqEventHandlers;
// @DEBUG - Remove if you wish to see all touch events
//var array<string> TouchDebug;
/** Store the current adjusted viewport size so we can adjust mobile input zones */
var vector2D MobileViewportOffset;
var vector2D MobileViewportSize;
/**
* Process Mobile Input, handles mobile user input
* Should be called regardless of game state.
*/
native function ProcessMobileInput( float DeltaTime );
/**
* Function to cancel all mobile input before a Scaleform movie confuses the state
*/
native function CancelMobileInput();
/**
* Overload the super PlayerInput event
*/
event PlayerInput( float DeltaTime )
{
// Process the mobile input, this method is explicitly called regardless
// of whether the game is paused so as to allow the mobile touch info
// to be updated even when paused.
ProcessMobileInput( DeltaTime );
// update any other player input info.
Super.PlayerInput( DeltaTime );
}
cpptext
{
/**
* Takes a touch and looks up the InputZone that would handle it.
*
* @param TouchLocation Where the touch occurred
* @param TouchpadIndex The index of the touchpad this touch came from
* @returns the zone that will be managing this touch
*/
UMobileInputZone* HitTest(FVector2D TouchLocation, UINT TouchpadIndex);
/**
* Process an input key event received from the viewport.
*
* @param Viewport the viewport the input event was received from
* @param ControllerId gamepad/controller that generated this input event
* @param Key the name of the key which an event occured for (KEY_Up, KEY_Down, etc.)
* @param EventType the type of event which occured (pressed, released, etc.)
* @param AmountDepressed (analog keys only) the depression percent.
* @param bGamepad - input came from gamepad (ie xbox controller)
*
* @return TRUE to consume the key event, FALSE to pass it on.
*/
virtual UBOOL InputKey(INT ControllerId,FName Key,EInputEvent Event,FLOAT AmountDepressed=1.f,UBOOL bGamepad=FALSE);
/**
* Process an input axis (joystick, thumbstick, or mouse) event received from the viewport.
*
* @param Viewport the viewport the input event was received from
* @param ControllerId the controller that generated this input axis event
* @param Key the name of the axis that moved (KEY_MouseX, KEY_XboxTypeS_LeftX, etc.)
* @param Delta the movement delta for the axis
* @param DeltaTime the time (in seconds) since the last axis update.
*
* @return TRUE to consume the axis event, FALSE to pass it on.
*/
virtual UBOOL InputAxis(INT ControllerId,FName Key,FLOAT Delta,FLOAT DeltaTime, UBOOL bGamepad=FALSE);
/**
* Handle a touch event coming from the device.
*
* NOTE: no processing of the touch happens here. This just tracks the touch in the Touches stack. Processing
* happens each tick
*
* @param Handle the id of the touch
* @param Type What type of event is this
* @param TouchLocation Where the touch occurred
* @param DeviceTimestamp Input event timestamp from the device
* @param TouchpadIndex The index of the touchpad this touch came from
*/
virtual UBOOL InputTouch(INT ControllerId, UINT Handle, ETouchType Type, FVector2D TouchLocation, DOUBLE DeviceTimestamp, UINT TouchpadIndex=0);
/**
* Update active touches, etc
*
* @param DeltaTime Much time has elapsed since the last processing
*/
virtual void Tick(FLOAT DeltaTime);
/**
* When input comes in to the player input, the first thing we need to do is process it for
* the menus.
*
* @param TouchHandle A unique id for the touch
* @param TouchpadIndex The index of the touchpad this touch came from
* @param EventType What type of event is this
* @param TouchLocation Where the touch occurred
* @param DeviceTimestamp Time this event happened.
*
* @returns true if the menu system swallowed the input
*/
UBOOL ProcessMenuInput(UINT TouchHandle, UINT TouchpadIndex, ETouchType EventType, FVector2D TouchLocation, DOUBLE DeviceTimestamp);
/**
* This function will iterate over the MobileSeqEventHandles array and cause them to be updated.
* It get's called once per frame.
*/
void UpdateListeners();
/**
* Returns the Global Scaling values
*
* @return a FVector2 containing the global scale values
*/
FVector2D GetGlobalScale();
/**
* Swap around components of a vector (with rotational values) based on an orientation.
* This will swap pitch and roll when a mobile device is rotated 90 degrees, etc
*
* @param Vec [in/out] Vector to modify
* @param Orientation Orientation for which the values were generated in
* @param bIsRotation TRUE if the vector represents rotation, not a directional vector
*/
static void ModifyVectorByOrientation(FVector& Vec, EUIOrientation Orientation, UBOOL bIsRotation)
{
switch (Orientation)
{
case UI_Portait:
// this is the base orientation, so nothing to do
break;
case UI_PortaitUpsideDown:
if (bIsRotation)
{
// negate roll and pitch
Vec.X = -Vec.X;
Vec.Z = -Vec.Z;
}
else
{
// negate x/y
Vec.X = -Vec.X;
Vec.Y = -Vec.Y;
}
break;
case UI_LandscapeRight:
if (bIsRotation)
{
// swap and negate (as needed) roll and pitch
FLOAT Temp = Vec.X;
Vec.X = -Vec.Z;
Vec.Z = Temp;
}
else
{
// swap and negate (as needed) x and y
FLOAT Temp = Vec.X;
Vec.X = -Vec.Y;
Vec.Y = Temp;
}
break;
case UI_LandscapeLeft:
if (bIsRotation)
{
// swap and negate (as needed) roll and pitch
FLOAT Temp = Vec.X;
Vec.X = Vec.Z;
Vec.Z = -Temp;
}
else
{
// swap and negate (as needed) x and y
FLOAT Temp = Vec.X;
Vec.X = Vec.Y;
Vec.Y = -Temp;
}
break;
}
}
public:
/**
* Determine the size of the current interactive canvas
*
* @param ViewportSize Size of the canvas
*/
void GetInteractiveViewportSize(FVector2D& ViewportSize);
/**
* Initialize, or reinitialize a zone
*
* @param Zone The Zone to initialize
* @param ViewportSize Size of the canvas
* @param bIsFirstInitialize TRUE if this is the first time the zone is initialized (use FALSE when canvas was resized)
*/
void NativeInitializeZone(UMobileInputZone* Zone, const FVector2D& ViewportSize, UBOOL bIsFirstInitialize);
};
/**
* Invoked when the mobile menus did not process an Touch_Began.
*/
delegate OnTouchNotHandledInMenu();
/**
* PreviewTouch X,Y - screenspace coordinates; true/false for handled/not handled.
*/
delegate bool OnPreviewTouch(float X, float Y, int TouchpadIndex);
/**
* OnInputTouch is a low level handler for getting the actual touch data
*/
delegate OnInputTouch(int Handle, ETouchType Type, Vector2D TouchLocation, float DeviceTimestamp, int TouchpadIndex);
/**
* Perform any native initialization of the subsystem
*/
native function NativeInitializeInputSystem();
/**
* Iterates over the zones and pre-calculates the actual bounds based on the current device resolution
*/
native function NativeInitializeInputZones(bool bIsFirstInitialize);
/**
* Update the mobile touch zones if the viewport aspect ratio changes
*/
native function ConditionalUpdateInputZones(int NewViewportX, int NewViewportY, int NewViewportSizeX, int NewViewportSizeY);
/**
* Allows the game to send a InputKey event though the viewport.
*
* @param Key the new of the key we are sending
* @param Event the Type of event
* @param AmountDepressed the strength of the event
*/
native function SendInputKey(name Key, EInputEvent Event, float AmountDepressed);
/**
* Allows the game to send an InputAxis event through the viewport
*
* @param Key the key we are sending
* @param Delta the movement delta for the axis
* @param DeltaTime the time (in seconds) since the last axis update.
*/
native function SendInputAxis(name Key, FLOAT Delta, FLOAT DeltaTime);
/**
* Handle touch events in the 3D world. To use this assign the OnTapDelegate in a MobileInputZone to this function.
*
* @param Zone The mobile Input zone that triggered the delegate
* @param EventType The type of input event that occurred
* @param TouchLocation The screen location of the touch event
*
* @return true if the world actor swallows the input
*/
native function bool ProcessWorldTouch(MobileInputZone Zone, ETouchType EventType, Vector2D TouchLocation);
/**
* The player controller will call this function directly after creating the input system
*/
function InitInputSystem()
{
super.InitInputSystem();
InitTouchSystem();
}
/**
* When the client inits the input system, initialize it's touch system
*/
function ClientInitInputSystem()
{
super.ClientInitInputSystem();
InitTouchSystem();
}
function InitTouchSystem()
{
NativeInitializeInputSystem();
// We only want to initialize the
if (bFakeMobileTouches || WorldInfo.IsConsoleBuild(CONSOLE_Mobile))
{
InitializeInputZones();
}
}
/**
* Initializes the input zones
*/
function InitializeInputZones()
{
local int i,j;
local MobileInputZone Zone;
local class<FrameworkGame> FrameworkGameClass;
// In a MP game, this function gets called twice - and that caused the zone
// to be initialized twice making its pos/size wrong.
if (MobileInputGroups.Length > 0)
{
return;
}
FrameworkGameClass = Class<FrameworkGame>(WorldInfo.GRI.GameClass);
//`log("Initializing Input zones");
if (FrameworkGameClass != none)
{
//`log("No of Config Groups:"@FrameworkGameClass.Default.RequiredMobileInputConfigs.Length);
// Allocate Space
MobileInputGroups.Length = FrameworkGameClass.Default.RequiredMobileInputConfigs.Length;
for(i=0;i<FrameworkGameClass.Default.RequiredMobileInputConfigs.Length;i++)
{
// Add a Group for this config.
//`log("Building Group"@FrameworkGameClass.Default.RequiredMobileInputConfigs[i].GroupName);
// Attempt to add a game-defined, optional "DebugZone" if not final release script
// `if(`notdefined(FINAL_RELEASE))
// Zone = FindOrAddZone("DebugZone");
// if (Zone != none)
// {
// //`log(" Adding special DebugZone");
// MobileInputGroups[i].AssociatedZones.AddItem(Zone);
// }
// `endif
MobileInputGroups[i].GroupName = FrameworkGameClass.Default.RequiredMobileInputConfigs[i].GroupName;
for (j=0;j < FrameworkGameClass.Default.RequiredMobileInputConfigs[i].RequireZoneNames.Length;j++)
{
Zone = FindOrAddZone(FrameworkGameClass.Default.RequiredMobileInputConfigs[i].RequireZoneNames[j]);
MobileInputGroups[i].AssociatedZones.AddItem(Zone);
}
}
// Initialize the stored viewport size
LocalPlayer(Outer.Player).ViewportClient.GetViewportSize(MobileViewportSize);
// Perform the native initialization for them
NativeInitializeInputZones(true);
RefreshKismetLinks();
}
}
/**
* Search for zone in the list and return it if found
*
*/
function SwapZoneOwners()
{
local int i;
for (i=0;i<MobileInputZones.Length;i++)
{
MobileInputZones[i].InputOwner = self;
}
}
/**
* The SeqEvent's from the level's kismet will have their RegisterEvent function called before the inputzones are
* configured. So just this once, have all of them try again.
*/
event RefreshKismetLinks()
{
local array<SequenceObject> MobileInputSeqEvents;
local Sequence GameSeq;
local int i;
GameSeq = WorldInfo.GetGameSequence();
if (GameSeq != None)
{
// Find all SeqEvent_MobileInput objects anywhere and call RegisterEvent on them
GameSeq.FindSeqObjectsByClass(class'SeqEvent_MobileBase', TRUE, MobileInputSeqEvents);
for (i=0;i< MobileInputSeqEvents.Length; i++)
{
SeqEvent_MobileBase(MobileInputSeqEvents[i]).RegisterEvent();
}
// Find all SeqEvent_MobileRawInput objects anywhere and call RegisterEvent on them
MobileInputSeqEvents.length = 0;
GameSeq.FindSeqObjectsByClass(class'SeqEvent_MobileRawInput', TRUE, MobileInputSeqEvents);
for (i=0;i< MobileInputSeqEvents.Length; i++)
{
SeqEvent_MobileRawInput(MobileInputSeqEvents[i]).RegisterEvent();
}
}
}
/**
* Adds a listen to the mobile handler list.
*
* @param Handler the MobileMotion sequence event to add to the handler list
*/
function AddKismetEventHandler(SeqEvent_MobileBase NewHandler)
{
local int i;
//`log("Adding Mobile Kismet handler " @ NewHandler.Name);
// More sure this event handler isn't already in the array
for (i=0;i<MobileSeqEventHandlers.Length;i++)
{
if (MobileSeqEventHandlers[i] == NewHandler)
{
return; // Already Registered
}
}
// Look though the array and see if there is an empty sport. These empty sports
// can occur when a kismet sequence is streamed out.
for (i=0;i<MobileSeqEventHandlers.Length;i++)
{
if (MobileSeqEventHandlers[i] == none)
{
MobileSeqEventHandlers[i] = NewHandler;
return;
}
}
MobileSeqEventHandlers.AddItem(NewHandler);
}
/**
* Adds a raw listen to the mobile handler list.
*
* @param Handler the MobileMotion sequence event to add to the handler list
*/
function AddKismetRawInputEventHandler(SeqEvent_MobileRawInput NewHandler)
{
local int i;
//`log("ZONE: Adding Mobile Kismet Raw input handler " @ NewHandler.Name);
// More sure this event handler isn't already in the array
for (i=0;i<MobileRawInputSeqEventHandlers.Length;i++)
{
if (MobileRawInputSeqEventHandlers[i] == NewHandler)
{
return; // Already Registered
}
}
// Look though the array and see if there is an empty sport. These empty sports
// can occur when a kismet sequence is streamed out.
for (i=0;i<MobileRawInputSeqEventHandlers.Length;i++)
{
if (MobileRawInputSeqEventHandlers[i] == none)
{
MobileRawInputSeqEventHandlers[i] = NewHandler;
return;
}
}
MobileRawInputSeqEventHandlers.AddItem(NewHandler);
}
/**
* Search for zone in the list and return it if found
*
* @param ZoneName - The name of the Mobile Input Zone we are looking for
* @returns a zone.
*/
function MobileInputzone FindZone(string ZoneName)
{
local int i;
for (i=0;i<MobileInputZones.Length;i++)
{
if (MobileInputZones[i].Name == Name(ZoneName))
{
return MobileInputZones[i];
}
}
return none;
}
/**
* Searchings the zone array for a zone and returns it if found. Otherwise add it and return the new zone
*
* @param ZoneName - The name of the Mobile Input Zone we are looking for
* @returns a zone.
*/
function MobileInputZone FindorAddZone(string ZoneName)
{
local MobileInputZone Zone;
local class<MobileInputZone> ClassType;
local int ClassIndex;
Zone = FindZone(ZoneName);
if (Zone == None)
{
ClassType = class'MobileInputZone';
// Search for the class type that is associated with ZoneName in the ini file.
for (ClassIndex = 0; ClassIndex < MobileInputZoneClasses.length; ClassIndex++)
{
if (ZoneName == MobileInputZoneClasses[ClassIndex].Name)
{
ClassType = MobileInputZoneClasses[ClassIndex].ClassType;
break;
}
}
Zone = new(none,ZoneName) ClassType;
Zone.InputOwner = self;
MobileInputZones.AddItem(Zone);
}
return Zone;
}
function bool HasZones()
{
return (MobileInputGroups.Length>0 && CurrentMobileGroup < MobileInputGroups.Length);
}
function array<MobileInputZone> GetCurrentZones()
{
return MobileInputGroups[CurrentMobileGroup].AssociatedZones;
}
exec function ActivateInputGroup(string GroupName)
{
local int i;
for (i=0;i<MobileInputGroups.Length;i++)
{
if (MobileInputGroups[i].GroupName == GroupName)
{
CurrentMobileGroup = i;
return;
}
}
`log("Attempted to activate a mobile input group" @ GroupName @ "that did not exist.");
}
/**
* Switch to the input config with the specified group name
*/
exec function SetMobileInputConfig(string GroupName)
{
local int NewConfig;
for( NewConfig=0; NewConfig<MobileInputGroups.Length; NewConfig++ )
{
if( MobileInputGroups[NewConfig].GroupName ~= GroupName )
break;
}
if( NewConfig < MobileInputGroups.Length )
{
CurrentMobileGroup = NewConfig;
//`Log("MobileInputConfig="$CurrentMobileGroup);
}
else
{
`Warn("Could not find a MobileInputGroup called" @ GroupName);
}
}
// **********************************************************************************
// Menu System
// **********************************************************************************
/**
* Call this function to open a menu scene.
*
* @param SceneClass - The class of the menu scene to open.
* @param Mode - Optional string that lets the opener pass extra information to the scene
*/
event MobileMenuScene OpenMenuScene(class<MobileMenuScene> SceneClass, optional string Mode)
{
local MobileMenuScene Scene;
local Vector2D ViewportSize;
if (SceneClass != none)
{
// We have the menu scene, create it.
Scene = new(outer) SceneClass;
if (Scene != none)
{
//`log("### OpenMenuScene "@SceneClass);
LocalPlayer(Outer.Player).ViewportClient.GetViewportSize(ViewportSize);
Scene.InitMenuScene(self, ViewportSize.X, ViewportSize.Y,true);
MobileMenuStack.InsertItem(0,Scene);
Scene.Opened(Mode);
Scene.MadeTopMenu();
return Scene;
}
else
{
`log("Could not create menu scene " $ SceneClass);
}
}
return none;
}
/**
* Call this function to close a menu scene. Remove it from the stack and notify the scene/etc.
*
* @param SceneToClose - The actual scene to close.
*/
event CloseMenuScene(MobileMenuScene SceneToClose)
{
local int i,idx;
local bool bClosedTopMenu;
// Check to make sure the Scene wants to let itself close
if (SceneToClose.Closing())
{
idx = -1;
// Find the scene in the stack
for (i=0;i<MobileMenuStack.Length;i++)
{
if (MobileMenuStack[i] == SceneToClose)
{
idx = i;
break;
}
}
if (idx>=0)
{
// did we just remove the top menu?
bClosedTopMenu = (idx == 0);
MobileMenuStack.Remove(idx,1);
SceneToClose.Closed();
// if we closed the top menu, send a MadeTopMenu to the new top menu
if (bClosedTopMenu)
{
if (MobileMenuStack.length > 0)
{
MobileMenuStack[0].MadeTopMenu();
}
}
}
}
}
/**
* Call this function to close all menus, used to "restart" the stack
*/
event CloseAllMenus()
{
while (MobileMenuStack.length > 0)
{
CloseMenuScene(MobileMenuStack[MobileMenuStack.length -1]);
}
}
/**
* Start the rendering chain for the UI Scenes
*
* @param Canvas - The canvas for drawing
*/
event RenderMenus(Canvas Canvas,float RenderDelta)
{
local int i;
Canvas.Reset();
if (bDisableSceneRender)
{
return;
}
for (i = MobileMenuStack.Length-1; i >= 0; i--)
{
MobileMenuStack[i].RenderScene(Canvas,RenderDelta);
}
}
/**
* We need a PreClientTravel to clean up the menu system.
*/
function PreClientTravel( string PendingURL, ETravelType TravelType, bool bIsSeamlessTravel)
{
local int i;
Super.PreClientTravel(PendingURL, TravelType, bIsSeamlessTravel);
for (i = MobileMenuStack.Length-1; i >= 0; i--)
{
MobileMenuStack[i].Closed();
}
}
exec function SceneRenderToggle()
{
bDisableSceneRender = !bDisableSceneRender;
}
exec function MobileMenuCommand(string MenuCommand)
{
local int i;
for (i = 0; i < MobileMenuStack.Length; i++)
{
if (MobileMenuStack[i].MobileMenuCommand(MenuCommand))
{
return;
}
}
}
/**
* Opens a menu by class
*
* @Param MenuClassName - the name of the class to open
*/
exec function MobileMenuScene OpenMobileMenu(string MenuClassName)
{
local class<MobileMenuScene> MenuClass;
MenuClass = class<MobileMenuScene>(DynamicLoadObject(MenuClassName,class'class'));
if (MenuClass != none)
{
return OpenMenuScene(MenuClass);
}
return none;
}
/**
* Opens a menu by class and passes extra info to the scene
*
* @Param MenuClassName - the name of the class to open - REQUIRES QUOTES!
* @Param Mode - the extra mode information to pass to the scene (two strings in OpenMobileMenu above breaks a.b for class names!)
*/
exec function MobileMenuScene OpenMobileMenuMode(string MenuClassName, string Mode)
{
local class<MobileMenuScene> MenuClass;
MenuClass = class<MobileMenuScene>(DynamicLoadObject(MenuClassName,class'class'));
if (MenuClass != none)
{
return OpenMenuScene(MenuClass, Mode);
}
return none;
}
// @DEBUG - Remove if you wish to see all touch events
/*
event AddTouchDebug(int Handle, TouchDataEvent Event)
{
local string s;
if (Event.EventType == Touch_Ended && Event.Location.Y > 400)
{
TouchDebug.Remove(0,TouchDebug.Length);
return;
}
if (Event.EventType == Touch_Moved)
{
return;
}
s = "TOUCH: Hander="@Handle @ "Event=" @ Event.EventType @ Event.Location.X @ Event.Location.Y;
AddTouchDebugMsg(s);
}
event AddTouchDebugMsg(string s)
{
local int i;
i = TouchDebug.Length;
TouchDebug.Length = i+1;
TouchDebug[i] = s;
if (TouchDebug.Length>20)
{
TouchDebug.Remove(0,1);
}
}
function DrawTouchDebug(canvas Canvas)
{
local int i;
local int y;
y = 80;
for (i=0;i<TouchDebug.Length;i++)
{
DrawDebugString(Canvas, TouchDebug[i],y);
y+=18;
}
}
function DrawDebugString(Canvas Canvas, string Msg, float y)
{
Canvas.SetPos(0,Y);
Canvas.SetDrawColor(0,0,0,255);
Canvas.DrawText(Msg);
Canvas.SetPos(1,Y+1);
Canvas.SetDrawColor(255,255,255,255);
Canvas.DrawText(Msg);
}
*/