close

常常看到手機遊戲都有Joystick 圖示來控制角色移動,按鈕控制角色: 跳躍,攻擊.....等等的功能,大概花時間研究了一下,可以用UnityUI的屬性方式來進行。

操作之前,我們可以理解成介面都是由圖片方式來進行與操作者互動。

GitHub 專案

 

例如:

  • 角色攻擊,玩家就會去點擊攻擊的指令,那個指令就可以當成是一個按鈕方式來進行觸發。
  • 按鈕圖示可以換成攻擊圖片與做出點擊按鈕震動動畫效果與玩家進行人機互動方式呈現。

Joystick 圖示

以上圖示Joystick 圖示按鈕

結果:

 

 

 

 

 

 

 

 

以下藉由Unity.EventSystems interface 方式來進行撰寫功能。

Joystick -- C# 腳本

using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;

public class Joystick : MonoBehaviour, IDragHandler, IPointerUpHandler, IPointerDownHandler
{
    // Init
    protected Image container;
    protected Image joystick;
    protected Vector3 InputDirection = Vector3.zero;

    public void OnDrag(PointerEventData ped)
    {
        Vector2 position = Vector2.zero;

        // Get InputDirection
        RectTransformUtility.ScreenPointToLocalPointInRectangle(
            container.rectTransform,
            ped.position,
            ped.pressEventCamera,
            out position
        );

        float x = (position.x / container.rectTransform.sizeDelta.x);
        float y = (position.y / container.rectTransform.sizeDelta.y);

        InputDirection = new Vector3(x, y, 0);
        InputDirection = (InputDirection.magnitude > 1) ? InputDirection.normalized : InputDirection;

        // Define the area in which joystick can move around
        joystick.rectTransform.anchoredPosition = new Vector3(
            InputDirection.x * container.rectTransform.sizeDelta.x / 3,
            InputDirection.y * container.rectTransform.sizeDelta.y / 3
        );
    }

    public void OnPointerDown(PointerEventData ped)
    {
        OnDrag(ped);
    }

    public void OnPointerUp(PointerEventData ped)
    {
        InputDirection = Vector3.zero;
        joystick.rectTransform.anchoredPosition = Vector3.zero;
    }
}

InterfaceOBJ -- C# 腳本

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.Events;

public class InterfaceOBJ
{
    private Image imageObj;
    private Button buttonObj;
    private interfaceObj interfaceObj;

    public InterfaceOBJ(Image imag, interfaceObj interfaceObj)
    {
        this.imageObj = imag;
        this.interfaceObj = interfaceObj;
    }

    public InterfaceOBJ(Button button, interfaceObj interfaceObj)
    {
        this.buttonObj = button;
        this.interfaceObj = interfaceObj;
    }

    // image
    public void image(float pointX, float pointY, float sizeX, float sizeY)
    {
        interfaceObj.image(imageObj, pointX, pointY, sizeX, sizeY);
    }

    // button
    public void button(float pointX, float pointY, float sizeX, float sizeY, UnityAction onClick)
    {
        interfaceObj.button(buttonObj, pointX, pointY, sizeX, sizeY, onClick);
    }
}

public interface interfaceObj
{
    void image(Image image, float pointX, float pointY, float sizeX, float sizeY);
    void button(Button button, float pointX, float pointY, float sizeX, float sizeY, UnityAction onClick);
}

InterfaceObj -- C# 腳本

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UI;

public class InterfaceObj : interfaceObj
{
    public void button(Button button, float pointX, float pointY, float sizeX, float sizeY, UnityAction onClick)
    {
        try
        {
            button.transform.position = new Vector2(Screen.width / 2 * pointX, Screen.height / 2 * pointY);
            button.image.rectTransform.sizeDelta = new Vector2(Screen.width / 2 * sizeX, sizeY);
            button.onClick.AddListener(onClick);
        }
        catch { }
    }

    public void image(Image image, float pointX, float pointY, float sizeX, float sizeY)
    {
        try
        {
            image.rectTransform.position = new Vector2(Screen.width / 2 * pointX, Screen.height / 2 * pointY);
            image.rectTransform.sizeDelta = new Vector2(Screen.width / 2 * sizeX, Screen.height / 2 * sizeY);
        }
        catch { }
    }
}

Layout_Main -- C# 腳本

public class Layout_Main : Joystick
{
    public Image fixedJoystick_image, handle_image;
    public Button jump_btn;

    InterfaceOBJ fixedJoystick, jump;

    public static Vector3 DIRCTION;
    public static bool JUMP_SW;

    // 計時器
    private float timeCount;
    private float timeCD = 1f;

    public static bool JUMP_ACTIVE;

    private void Start()
    {
        base.container = fixedJoystick_image;
        base.joystick = handle_image;

        fixedJoystick = new InterfaceOBJ(fixedJoystick_image, new InterfaceObj());
        fixedJoystick.image(0.23f, 0.4f, 0.2f, 0.35f);

        jump = new InterfaceOBJ(jump_btn, new InterfaceObj());
        jump.button(1.68f, 0.42f, 0.2f, 80, jump_onClkck);
    }

    private void Update()
    {
        DIRCTION = base.InputDirection;
        JUMP_ACTIVE = jumpCd();
    }

    void jump_onClkck()
    {
        if (JUMP_ACTIVE == true)
        {
            JUMP_SW = true;
            timeCount = timeCD;
        }
    }

    // 跳躍冷卻時間
    public bool jumpCd()
    {
        return ((timeCount -= Time.deltaTime) <= 0) ? true : false;
    }
}

Player -- C# 腳本

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Player : MonoBehaviour
{
    Rigidbody rigidbody;

   
    private float gravity = 10.0f, maxVelocityChange = 50f, jumpHeight = 1f;

    public float speed;

    void Start()
    {       
        rigidbody = GetComponent<Rigidbody>();
        rigidbody.freezeRotation = true;
        rigidbody.useGravity = false;
    }

    private void FixedUpdate()
    {
        if(Layout_Main.DIRCTION.magnitude != 1)
        {
            Vector3 position = new Vector3(Layout_Main.DIRCTION.x * speed, 0,
                Layout_Main.DIRCTION.y * speed);

            position = transform.TransformDirection(position);

            Vector3 velocity = rigidbody.velocity;
            Vector3 velocityChange = (position - velocity);

            velocityChange.x = Mathf.Clamp(velocityChange.x, -maxVelocityChange, maxVelocityChange);
            velocityChange.z = Mathf.Clamp(velocityChange.z, -maxVelocityChange, maxVelocityChange);
            velocityChange.y = 0;
            rigidbody.AddForce(velocityChange, ForceMode.VelocityChange);

            if (Layout_Main.JUMP_SW)         
                rigidbody.velocity = new Vector3(velocity.x, CalculateJumpVerticalSpeed(), velocity.z);

            if (Layout_Main.JUMP_ACTIVE == false)
                Layout_Main.JUMP_SW = false;

        }

        rigidbody.AddForce(new Vector3(0, -gravity * rigidbody.mass, 0));
    }

    // Jump
    float CalculateJumpVerticalSpeed()
    {
        return Mathf.Sqrt(2 * jumpHeight * gravity);
    }
}

Unity 介面設計:

  • Canvas - Unity UI(一定要)
  • FixedJoystick - Unity UI (Image)
    • Handle - Unity UI (Image) - 當FixedJoystick子物件
      • Handle 設定Width: 50, Height: 50
  • Jump_Btn - Unity UI (Image)
  • EventSystem - Unity UI (一定要)
  • Player - 3D物件(本文使用Unity內建物件)
  • Plane - 3D物件(本文使用內建物件)

image

Canvas 物件: 

  • 插入Layout_Main腳本

螢幕擷取畫面 2021-05-19 045114

Player 物件:

  • 插入Player腳本

image

arrow
arrow
    文章標籤
    unity教學
    全站熱搜
    創作者介紹
    創作者 Xauxas 的頭像
    Xauxas

    Xauxas 筆記

    Xauxas 發表在 痞客邦 留言(0) 人氣()