[Unity3D]手機3D遊戲開發:關於自訂Joystick的相關設定和指令碼源碼

來源:互聯網
上載者:User

學習Unity指令碼推薦:Unity3D官網索引


Joystick在手遊開發中非常常見,也就是在手機螢幕上的虛擬操縱杆,但是Unity3D內建的Joystick貼圖比較原始,所以經常有使用自訂貼圖的需求。

下面就來示範一下如何?自訂JoyStick貼圖。

首先匯入貼圖,注意要把預設的Texture改為GUI要不然尺寸會發生改變:


在Inspector面板中點擊Texture選項可以實現簡單的貼圖切換:


選中後便會發現情境中的Joystick已經發生了改變:

同理,可以對右邊的Joystick做同樣的修改:


當然很多時候這樣簡單的修改很難滿足我們的需求。

下面來說說對Joystick的常見調整。

首先是座標的調整,一般把Postition歸零而在GUITexture中調整Pixel Inset:


但是這樣依舊會出問題,全屏的時候因為採用了絕對座標所以會出現這種情況:

所以我們還需要在指令碼中稍作調整。

先來給Joystick加個背景圖片。

建立一個JS指令碼JoystickBackgroundGUI:

@script RequireComponent(Joystick)@script ExecuteInEditMode ()var background = new SwitchGUI();var location = new Location();private var GUIalpha:float = 1;private var joystick : Joystick;joystick = GetComponent (Joystick);var noGuiStyle : GUIStyle;function Update() {if (joystick.IsFingerDown()) {background.up();} else {background.down();}if (background.texture != null){location.updateLocation();}}function OnGUI () {GUI.color.a = GUIalpha;GUI.Box(Rect(location.offset.x + background.offset.x - background.texture.width/2,location.offset.y + background.offset.y - background.texture.height/2,background.texture.width,background.texture.height),background.texture,noGuiStyle);}

joystick是Unity自己封裝好的對象,其中有IsFingerDown等函數有需要的同學可以查閱一下Unity官網的說明文檔。

指令碼中用到了Location和SwitchGUI,這兩個函數在另一個指令碼   _GUIClasses   中定義:

import System.Collections.Generic;// TextureGUI Class: create a basic class for creating and placing GUI elements// texture = the texture to display// offset = pixel offset from top left corner, can be modified for easy positioningclass TextureGUI {var texture:Texture; //useful: texture.width, texture.heightvar offset:Vector2; // .x and .yprivate var originalOffset:Vector2; //store the original to correctly reset anchor pointenum Point { TopLeft, TopRight, BottomLeft, BottomRight, Center} //what part of texture to position around?var anchorPoint = Point.TopLeft; // Unity default is from top left corner of texturefunction setAnchor() { // meant to be run ONCE at Start.originalOffset = offset;if (texture) { // check for null textureswitch(anchorPoint) { //depending on where we want to center our offsetscase anchorPoint.TopLeft: // Unity default, do nothingbreak;case anchorPoint.TopRight: // Take the offset and go to the top right corneroffset.x = originalOffset.x - texture.width;break;case anchorPoint.BottomLeft: // bottom left corner of textureoffset.y = originalOffset.y - texture.height;break;case anchorPoint.BottomRight: //bottom right corner of textureoffset.x = originalOffset.x - texture.width;offset.y = originalOffset.y - texture.height;break;case anchorPoint.Center: //and the center of the texture (useful for screen center textures)offset.x = originalOffset.x - texture.width/2;offset.y = originalOffset.y - texture.height/2;break;}}}}//Timer Class:class TimerGUI extends TextureGUI { // Extend functionality from TextureGUI for a depreciating timer graphicvar textureLEnd:Texture; // left side of full texture (non stretching part)var offsetLEnd:Vector2; // left side of full texture (non stretching part) start positionvar textureCenter:Texture; // center of timer (will be stretched across width)var offsetCenter:Vector2; var textureREnd:Texture;var offsetREnd:Vector2;var timerPerct:float = 1; // percentage (0 to 1) this stretches the centervar desiredWidth:float = 403; // max width of the timer in pixelsfunction setTime(newTime:float) {timerPerct = newTime; // sets the percent based on value}}// SwitchGUI Class: Extends the TextureGUI to be able to load in multiple textures and switch between themclass SwitchGUI extends TextureGUI {var switchableTextures = new List.<Texture>();var currentTexture:int = 0;function Start() {if (switchableTextures.Count > 0) {texture = switchableTextures[currentTexture];}}function changeTexture(switchTo:int) {if (switchTo < switchableTextures.Count && switchTo >= 0) {texture = switchableTextures[switchTo];currentTexture = switchTo;} else {//Debug.Log( this + ": tried to call invalid part of switchTextures array!");}}function up() {if ((currentTexture+1) < switchableTextures.Count) {++currentTexture;texture = switchableTextures[currentTexture];} else {//Debug.Log( this + ": at the top!");}}function nextTexture() {if ((currentTexture+1) < switchableTextures.Count) { // if we are at the end of the array++currentTexture;texture = switchableTextures[currentTexture];} else {// loop to the beginningcurrentTexture = 0;texture = switchableTextures[currentTexture];}}function down() {if ((currentTexture-1) >= 0) {--currentTexture;texture = switchableTextures[currentTexture];} else {//Debug.Log( this + ": at the bottom!");}}}// Location class: class Location {enum Point { TopLeft, TopRight, BottomLeft, BottomRight, Center}var pointLocation = Point.TopLeft;var offset:Vector2;function updateLocation() {switch(pointLocation) {case pointLocation.TopLeft:offset = Vector2(0,0);break;case pointLocation.TopRight:offset = Vector2(Screen.width,0);break;case pointLocation.BottomLeft:offset = Vector2(0,Screen.height);break;case pointLocation.BottomRight:offset = Vector2(Screen.width,Screen.height);break;case pointLocation.Center:offset = Vector2(Screen.width/2,Screen.height/2);break;}}}class TextureAnchor {enum Point { TopLeft, TopRight, BottomLeft, BottomRight, Center}var anchorPoint = Point.TopLeft;var offset:Vector2;function update() {switch(anchorPoint) {case anchorPoint.TopLeft:offset = Vector2(0,0);break;case anchorPoint.TopRight:offset = Vector2(Screen.width,0);break;case anchorPoint.BottomLeft:offset = Vector2(0,Screen.height);break;case anchorPoint.BottomRight:offset = Vector2(Screen.width,Screen.height);break;case anchorPoint.Center:offset = Vector2(Screen.width/2,Screen.height/2);break;}}}

將指令碼拖拽到Joystick上面並且部署好貼圖,運行可見Joystick的背景貼圖,當然座標還有點問題:

我們在指令碼中將其設定為BottomLeft,並且設定好SwitchTexture:

配置好了之後點擊運行,會發現Joystick 的貼圖出現在了左下角:

通過指令碼中的Pixel設定可以調整兩個紋理貼圖的座標並使他們趨於一致:

調整之後的結果

同時將Joystick的指令碼換成下面的指令碼,可以實現隱藏操縱杆而只在碰到搖杆地區才顯示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 moveclass Boundary {var min : Vector2 = Vector2.zero;var max : Vector2 = Vector2.zero;}static private var joysticks : Joystick[];// A static collection of all joysticksstatic private var enumeratedJoysticks : boolean = false;static private var tapTimeDelta : float = 0.3;// Time allowed between tapsvar touchPad : boolean; // Is this a TouchPad?var touchZone : Rect;var deadZone : Vector2 = Vector2.zero;// Control when position is outputvar normalize : boolean = false; // Normalize output after the dead-zone?var position : Vector2; // [-1, 1] in x,yvar tapCount : int;// Current tap countprivate var lastFingerId = -1;// Finger last used for this joystickprivate var tapTimeWindow : float;// How much time there is left for a tap to occurprivate var fingerDownPos : Vector2;private var fingerDownTime : float;private var firstDeltaTime : float = 0.5;private var gui : GUITexture;// Joystick graphicprivate var defaultRect : Rect;// Default position / extents of the joystick graphicprivate var guiBoundary : Boundary = Boundary();// Boundary for joystick graphicprivate var guiTouchOffset : Vector2;// Offset to apply to touch inputprivate var guiCenter : Vector2;// Center of joystickprivate var alphaOff:float = 0.0;function Start(){// Cache this component at startup instead of looking up every framegui = GetComponent( GUITexture );// Store the default rect for the gui, so we can snap back to itdefaultRect = gui.pixelInset;gui.color.a = alphaOff;        defaultRect.x += transform.position.x * Screen.width; // + gui.pixelInset.x; // -  Screen.width * 0.5;    defaultRect.y += transform.position.y * Screen.height; //+ gui.pixelInset.y; // - 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 touchZoneif ( gui.texture )touchZone = defaultRect;}else{// This is an offset for touch input to match with the top left// corner of the GUIguiTouchOffset.x = defaultRect.width * 0.5;guiTouchOffset.y = defaultRect.height * 0.5;// Cache the center of the GUI, since it doesn't changeguiCenter.x = defaultRect.x + guiTouchOffset.x;guiCenter.y = defaultRect.y + guiTouchOffset.y;// Let's build the GUI boundary, so we can clamp joystick movementguiBoundary.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 positiongui.pixelInset = defaultRect;lastFingerId = -1;position = Vector2.zero;fingerDownPos = Vector2.zero;gui.color.a = alphaOff;}function IsFingerDown() : boolean{return (lastFingerId != -1);}function LatchedFinger( fingerId : int ){// If another joystick has latched this finger, then we must release itif ( lastFingerId == fingerId )ResetJoystick();}function Update(){if ( !enumeratedJoysticks ){// Collect all joysticks in the game, so we can relay finger latching messagesjoysticks = FindObjectsOfType(Joystick) as Joystick[];enumeratedJoysticks = true;}var count = Input.touchCount;// Adjust the tap time window while it still availableif ( tapTimeWindow > 0 )tapTimeWindow -= Time.deltaTime;elsetapCount = 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;gui.color.a = .5;}// Latch the finger if this is a new touchif ( 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 windowif ( tapTimeWindow > 0 )tapCount++;else{tapCount = 1;tapTimeWindow = tapTimeDelta;}// Tell other joysticks we've latched this fingerfor ( 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 touchesif ( touch.tapCount > tapCount )tapCount = touch.tapCount;if ( touchPad ){// For a touchpad, let's just set the position directly based on distance from initial touchdownposition.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 isgui.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 locationposition.x = ( gui.pixelInset.x + guiTouchOffset.x - guiCenter.x ) / guiTouchOffset.x;position.y = ( gui.pixelInset.y + guiTouchOffset.y - guiCenter.y ) / guiTouchOffset.y;}// Adjust for dead zonevar 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 zoneposition.x = 0;}else if ( normalize ){// Rescale the output after taking the dead zone into accountposition.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 zoneposition.y = 0;}else if ( normalize ){// Rescale the output after taking the dead zone into accountposition.y = Mathf.Sign( position.y ) * ( absoluteY - deadZone.y ) / ( 1 - deadZone.y );}}

運行以下項目可以發現Joystick不見了:

但是點擊螢幕就會出現了:


聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.