my space

Unity | เปลี่ยนรูป Cursor ตาม GameObject ที่ Cursor ชี้

unityunity-fundamental

March 24, 2020

Blog นี้เป็น lector ที่จดกันลืมมาจาก Course ของ Unity Learn Premium (ช่วง Covid-19 ระบาด Unity เปิดให้เรียนได้ฟรี 2 เดือน https://learn.unity.com/course/unity-beginner-fundamentals)

Demo

จากตัวอย่างในรูปข้างบนนี้ จำลองว่าพื้นผิวทั่วไปให้แสดง cursor แบบนึง (วงกลม) และเมื่อเลื่อนไปที่แท่งด้านหน้า (จำลองว่าเป็นประตู) ให้แสดง cursor อีกแบบนึง

หลักการคือ เราสร้าง GameObject ที่ต้องการ interact กับ cursor เหล่านี้ขึ้นมาก่อน โดย ณ​ ที่นี้คือ Floor และ Door โดยตามรูปด้านล่างนี้ คือ GameObject ที่เลือกและมีขอบสีส้มนั่นเอง โดยพื้นคือ Floor และแท่งตรงกลางจอคือ Door

GameObject

กำหนด Layer ของ 2 GameObjects นี้ให้อยู่ใน Layer ใหม่ โดยในที่นี้จะตั้งชื่อว่า Clickable และใน Door ก็สร้าง Tag ของมันขึ้นมาชื่อ Doorway

GameObject

หลังจากนั้นสร้าง script MouseManager ขึ้นมาแปะใน Empty GameObject ที่ชื่อเดียวกัน หลักการของ Script คือเรามี properties 2 กลุ่ม

  • กลุ่มแรกคือ LayerMask โดยเรากำหนดบอก Unity เข้าไปว่าเราสนใจ Layer อะไร ในที่นี้คือ Clickable layer ที่เรา assign ให้กับ Door และ Floor
  • กลุ่มที่สองคือ Texture2D ซึ่งแทนรูปภาพ Cursor ในแต่ละสถานการณ์

ในตอน Update เราจะใช้ Physics.Raycast ไปเช็คในจุดที่ mouse เราอยู่ (Input.mousePosition) และดูว่ามันอยู่บน LayerMask ที่กำหนดไหม (เราหา Clickable layer) ถ้าใช่ก็ไปเช็คต่อว่าจุดที่ mouse ชี้ (ได้มาจาก out hit) นั้นเป็น GameObject ที่แปะ tag Doorway หรือไม่ ถ้าใช่ก็ display cursor doorway แต่ถ้าไม่ใช่ก็ display cursor target

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

public class MouseManager : MonoBehaviour
{
    // Know what objects are clickable
    public LayerMask clickableLayer;

    // Swap Cursors per objects
    public Texture2D pointer;// Normal Pointer
    public Texture2D target; // Cursor for clickable objects like the world
    public Texture2D doorway; // Cursor for doorways

    // Update is called once per frame
    void Update()
    {
        RaycastHit hit;
        if (Physics.Raycast(Camera.main.ScreenPointToRay(Input.mousePosition), out hit, 50, clickableLayer.value))
        {
            bool door = false;
            if (hit.collider.gameObject.tag == "Doorway")
            {
                Cursor.SetCursor(doorway, new Vector2(16, 16), CursorMode.Auto);
                door = true;
            }
            else
            {
                Cursor.SetCursor(target, new Vector2(16, 16), CursorMode.Auto);
            }
        }
        else
        {
            Cursor.SetCursor(pointer, new Vector2(16, 16), CursorMode.Auto);
        }
    }
}

gie

Written by gie who lives and works in Bangkok. Build things by code.
my twitter | github