- Home /
Mobile Virtual Joysticks / Keyboard Script Conversion
Hi all,
New unity user who is a scripting noob. Looking to see if someone can help me work something out.
I am using the SGSK (Space Game Starter Kit) from the asset store. It includes a great ship prefab, but it uses its own keyboard controls for roll, forward/reverse/shoot.
I am trying to get those controls to work with the Mobile Dual Joysticks included (I believe) with standard mobile pack (or at least the penelope demo). So left would control forward, reverse, roll - right would be camera/shoot or some variant.
It seems like an easy task since all the building blocks are there.
Anyone script experts want to help me out mapping ship controls to virtual joysticks?
Script for ship:
using UnityEngine;
using System.Collections.Generic;
[RequireComponent(typeof(Spaceship))]
[AddComponentMenu("Game/Spaceship Controller")]
public class SpaceshipController : MonoBehaviour
{
public enum InputType
{
Mouse,
Controller,
Touchpad,
}
public bool movement = true;
public bool weapons = true;
Spaceship mShip;
Vector3 mDelta;
int mSteeringTouch = -1;
float mNextPrimary = 0f;
float mNextSecondary = 0f;
List<Weapon> mPrimary = new List<Weapon>();
List<Weapon> mSecondary = new List<Weapon>();
/// <summary>
/// Determine whether we own this ship, input type, and ensure we have a network observer.
/// </summary>
void Start()
{
// If we don't control the ship, this script isn't needed
if (NetworkManager.isConnected && !NetworkManager.IsMine(this))
{
Destroy(this);
return;
}
// We need to know the ship we're controlling.
mShip = GetComponent<Spaceship>();
// Find all weapons
Weapon[] weapons = GetComponentsInChildren<Weapon>();
foreach (Weapon w in weapons)
{
if (w.group == Weapon.Group.Primary) mPrimary.Add(w);
if (w.group == Weapon.Group.Secondary) mSecondary.Add(w);
}
}
/// <summary>
/// Process input if we're controlling this ship.
/// </summary>
void Update()
{
Vector3 turn = mShip.turningInput;
Vector3 move = mShip.moveInput;
if (ControlScheme.uiMode)
{
// UI mode -- ignore input
mDelta = Vector2.zero;
}
else
{
// Get the movement axes
if (ControlScheme.current == ControlScheme.InputSource.Touchpad)
{
Vector3 touchMove = Vector3.zero;
Vector3 touchTurn = Vector3.zero;
foreach (Touch touch in Input.touches)
{
// Ignore the touch used to steer
if (mSteeringTouch == touch.fingerId)
{
if (touch.phase == TouchPhase.Moved)
{
mDelta.x += touch.deltaPosition.x;
mDelta.y += touch.deltaPosition.y;
}
else if (touch.phase == TouchPhase.Ended ||
touch.phase == TouchPhase.Canceled)
{
mDelta = Vector2.zero;
mSteeringTouch = -1;
}
}
else if (touch.position.x < Screen.width * 0.25f)
{
// Bottom part of the screen
if (touch.position.y < Screen.height * 0.25f)
{
// Bottom-left corner -- slow down
touchMove.z = -1f;
}
else if (touch.position.y > Screen.height * 0.75f)
{
// Top-left corner -- accelerate
touchMove.z = 1f;
}
else
{
// Left side -- roll left
touchTurn.z = -1f;
}
}
else if (touch.position.x > Screen.width * 0.75f)
{
if (touch.position.y < Screen.height * 0.25f)
{
// Bottom right corner -- shoot primary weapon
if (weapons && mPrimary.Count > 0 && mNextPrimary < Time.time)
{
mNextPrimary = Fire(mPrimary);
}
}
else if (touch.position.y > Screen.height * 0.75f)
{
// Top right corner -- shoot secondary weapon
if (weapons && mSecondary.Count > 0 && mNextSecondary < Time.time)
{
mNextSecondary = Fire(mSecondary);
}
}
else
{
// Right side -- roll right
touchTurn.z = 1f;
}
}
else if (touch.position.x > Screen.width * 0.25f &&
touch.position.x < Screen.width * 0.75f &&
touch.position.y > Screen.width * 0.25f &&
touch.position.y < Screen.width * 0.75f)
{
// Central part of the screen
if (touch.phase == TouchPhase.Began)
{
mSteeringTouch = touch.fingerId;
}
}
}
float maxDist = 1.0f / Mathf.Min(Screen.width * 0.4f, Screen.height * 0.4f);
touchTurn.x = Mathf.Clamp(mDelta.y * maxDist, -1f, 1f);
touchTurn.y = Mathf.Clamp(mDelta.x * maxDist, -1f, 1f);
move = touchMove;
turn = touchTurn;
}
else
{
if (movement)
{
move.x = Input.GetAxis("Right");
move.y = Input.GetAxis("Up");
move.z = Input.GetAxis("Forward");
// Record the roll rotation
turn.z = Input.GetAxis("Roll");
if (ControlScheme.current == ControlScheme.InputSource.Controller)
{
if (!Application.isEditor) Screen.lockCursor = false;
// Joystick-based control
turn.x = Input.GetAxis("Look Up");
turn.y = Input.GetAxis("Look Right");
mDelta = Vector2.zero;
}
else
{
if (!Application.isEditor) Screen.lockCursor = true;
// Mouse-based control
mDelta.x += Input.GetAxis("Mouse X");
mDelta.y += Input.GetAxis("Mouse Y");
float maxDist = 2.0f / Mathf.Min(Screen.width, Screen.height);
turn.x = Mathf.Clamp(mDelta.y * maxDist, -1f, 1f);
turn.y = Mathf.Clamp(mDelta.x * maxDist, -1f, 1f);
}
}
// Fire the primary weapon
if (weapons)
{
if (mPrimary.Count > 0 && (Input.GetMouseButton(0) || Input.GetKey(KeyCode.JoystickButton4)))
{
if (mNextPrimary < Time.time)
{
mNextPrimary = Fire(mPrimary);
}
}
// Fire the secondary weapon
if (mSecondary.Count > 0 && (Input.GetMouseButton(1) || Input.GetKey(KeyCode.JoystickButton5)))
{
if (mNextSecondary < Time.time)
{
mNextSecondary = Fire(mSecondary);
}
}
}
}
}
// Backwards movement should act as an anchor and should negate all other movement
if (move.z < 0f)
{
// Drain power while the "brake" button is held
if (mShip.powerGenerator != null)
{
float mult = Time.deltaTime * 30f;
move.z = -1.0f + mShip.powerGenerator.DrainPower(-move.z * mult) / mult;
}
move.x *= 1f + move.z;
move.y *= 1f + move.z;
}
// Ensure the vector is unit length
float mag = move.magnitude;
if (mag > 1f) move *= 1.0f / mag;
// Ensure the vector is unit length
mag = turn.magnitude;
if (mag > 1f)
{
turn *= 1.0f / mag;
mag = 1f;
}
// Sensitivity tweak to make it easier to snipe-aim
turn *= Tools.Ramp(mag, 0.35f);
// Set the ship's values
mShip.turningInput = turn;
mShip.moveInput = move;
}
/// <summary>
/// Helper function used above. Fires a weapon from the specified list and returns the next time we'll be able to fire.
/// </summary>
static float Fire (List<Weapon> list)
{
foreach (Weapon wp in list)
{
if (wp.canFire)
{
wp.Fire();
return Time.time + wp.firedObject.firingFrequency / (float)list.Count;
}
}
return Time.time;
}
}
Script for joystick:
////////////////////////////////////////////////////////////// // Joystick.js // Penelope iPhone Tutorial // // Joystick creates a movable joystick (via GUITexture) that // handles touch input, taps, and phases. Dead zones can control // where the joystick input gets picked up and can be normalized. // // Optionally, you can enable the touchPad property from the editor // to treat this Joystick as a TouchPad. A TouchPad allows the finger // to touch down at any point and it tracks the movement relatively // without moving the graphic //////////////////////////////////////////////////////////////
#pragma strict
@script RequireComponent( GUITexture )
// A simple class for bounding how far the GUITexture will move
class Boundary
{
var min : Vector2 = Vector2.zero;
var max : Vector2 = Vector2.zero;
}
static private var joysticks : Joystick[]; // A
static collection of all joysticks static private var enumeratedJoysticks : boolean = false; static private var tapTimeDelta : float = 0.3; // Time allowed between taps
var touchPad : boolean; // Is this a TouchPad?
var touchZone : Rect;
var deadZone : Vector2 = Vector2.zero; //
Control when position is output var normalize : boolean = false; // Normalize output after the dead-zone? var position : Vector2; // [-1, 1] in x,y var tapCount : int; // Current tap count
private var lastFingerId = -1; // Finger last used for this joystick
private var tapTimeWindow : float; // How much time there is left for a
tap to occur private var fingerDownPos : Vector2; private var fingerDownTime : float; private var firstDeltaTime : float = 0.5;
private var gui : GUITexture; // Joystick graphic
private var defaultRect : Rect; // Default position / extents of the
joystick graphic private var guiBoundary : Boundary = Boundary(); // Boundary for joystick graphic private var guiTouchOffset : Vector2; // Offset to apply to touch input private var guiCenter : Vector2; // Center of joystick
function Start()
{
// Cache this component at startup instead of looking up every
frame
gui = GetComponent( GUITexture );// Store the default rect for the gui, so we can snap back to it
defaultRect = gui.pixelInset;
defaultRect.x += transform.position.x * Screen.width;//
gui.pixelInset.x; // - Screen.width 0.5; defaultRect.y += transform.position.y Screen.height;// - Screen.height * 0.5;
transform.position.x = 0.0;
transform.position.y = 0.0;
if ( touchPad )
{
// If a texture has been assigned, then use the rect ferom the
gui as our touchZone if ( gui.texture ) touchZone = defaultRect; } else {
// This is an offset for touch input to match with the top left // corner of the GUI guiTouchOffset.x = defaultRect.width 0.5; guiTouchOffset.y = defaultRect.height 0.5;// Cache the center of the GUI, since it doesn't change
guiCenter.x = defaultRect.x + guiTouchOffset.x;
guiCenter.y = defaultRect.y + guiTouchOffset.y;
// Let's build the GUI boundary, so we can clamp joystick
movement guiBoundary.min.x = defaultRect.x - guiTouchOffset.x; guiBoundary.max.x = defaultRect.x + guiTouchOffset.x; guiBoundary.min.y = defaultRect.y - guiTouchOffset.y; guiBoundary.max.y = defaultRect.y + guiTouchOffset.y; } }
function Disable()
{
gameObject.active = false;
enumeratedJoysticks = false;
}
function ResetJoystick()
{
// Release the finger control and set the joystick back to the
default position gui.pixelInset = defaultRect; lastFingerId = -1; position = Vector2.zero; fingerDownPos = Vector2.zero;
if ( touchPad )
gui.color.a = 0.025;
}
function IsFingerDown() : boolean
{
return (lastFingerId != -1);
}
function LatchedFinger( fingerId : int )
{
// If another joystick has latched this finger, then we must
release it if ( lastFingerId == fingerId ) ResetJoystick(); }
function Update()
{
if ( !enumeratedJoysticks )
{
// Collect all joysticks in the game, so we can relay finger
latching messages joysticks = FindObjectsOfType( Joystick ) as Joystick[]; enumeratedJoysticks = true; }
var count = Input.touchCount;
// Adjust the tap time window while it still available
if ( tapTimeWindow > 0 )
tapTimeWindow -= Time.deltaTime;
else
tapCount = 0;
if ( count == 0 )
ResetJoystick();
else
{
for(var i : int = 0;i < count; i++)
{
var touch : Touch = Input.GetTouch(i);
var guiTouchPos : Vector2 = touch.position -
guiTouchOffset;
var shouldLatchFinger = false;
if ( touchPad )
{
if ( touchZone.Contains( touch.position ) )
shouldLatchFinger = true;
}
else if ( gui.HitTest( touch.position ) )
{
shouldLatchFinger = true;
}
// Latch the finger if this is a new touch
if ( shouldLatchFinger && ( lastFingerId == -1 ||
lastFingerId != touch.fingerId ) ) {
if ( touchPad )
{
gui.color.a = 0.15;
lastFingerId = touch.fingerId;
fingerDownPos = touch.position;
fingerDownTime = Time.time;
}
lastFingerId = touch.fingerId;
// Accumulate taps if it is within the time window
if ( tapTimeWindow > 0 )
tapCount++;
else
{
tapCount = 1;
tapTimeWindow = tapTimeDelta;
}
// Tell other joysticks we've latched this finger
for ( var j : Joystick in joysticks )
{
if ( j != this )
j.LatchedFinger( touch.fingerId );
}
}
if ( lastFingerId == touch.fingerId )
{
// Override the tap count with what the iPhone SDK
reports if it is greater // This is a workaround, since the iPhone SDK does not currently track taps // for multiple touches if ( touch.tapCount > tapCount ) tapCount = touch.tapCount;
if ( touchPad )
{
// For a touchpad, let's just set the position
directly based on distance from initial touchdown position.x = Mathf.Clamp( ( touch.position.x - fingerDownPos.x ) / ( touchZone.width / 2 ), -1, 1 ); position.y = Mathf.Clamp( ( touch.position.y - fingerDownPos.y ) / ( touchZone.height / 2 ), -1, 1 ); } else {
// Change the location of the joystick graphic to match where the touch is gui.pixelInset.x = Mathf.Clamp( guiTouchPos.x, guiBoundary.min.x, guiBoundary.max.x ); gui.pixelInset.y = Mathf.Clamp( guiTouchPos.y, guiBoundary.min.y, guiBoundary.max.y );
}if ( touch.phase == TouchPhase.Ended || touch.phase == TouchPhase.Canceled )
ResetJoystick();
}
}
}
if ( !touchPad )
{
// Get a value between -1 and 1 based on the joystick graphic
location position.x = ( gui.pixelInset.x + guiTouchOffset.x - guiCenter.x ) / guiTouchOffset.x; position.y = ( gui.pixelInset.y + guiTouchOffset.y - guiCenter.y ) / guiTouchOffset.y; }
// Adjust for dead zone
var absoluteX = Mathf.Abs( position.x );
var absoluteY = Mathf.Abs( position.y );
if ( absoluteX < deadZone.x )
{
// Report the joystick as being at the center if it is within
the dead zone position.x = 0; } else if ( normalize ) { // Rescale the output after taking the dead zone into account position.x = Mathf.Sign( position.x ) * ( absoluteX - deadZone.x ) / ( 1 - deadZone.x ); }
if ( absoluteY < deadZone.y )
{
// Report the joystick as being at the center if it is within
the dead zone position.y = 0; } else if ( normalize ) { // Rescale the output after taking the dead zone into account position.y = Mathf.Sign( position.y ) * ( absoluteY - deadZone.y ) / ( 1 - deadZone.y ); } }
Your answer
Follow this Question
Related Questions
The name 'Joystick' does not denote a valid type ('not found') 2 Answers
Mobile Keyboards -- Highlighting all text by default when keyboard is opened (iOS vs. Android) 0 Answers
Mobile player controller assistance 1 Answer
Why isn't my joystick code working? 1 Answer
Joystick pack from unity assets not following the finger movement 1 Answer