2019年12月3日 星期二

【自製小遊戲】水平思考猜謎(海龜湯)


海龜湯的玩法是由出題者提出一個難以理解的事件,參與猜題者可以提出任何問題以試圖縮小範圍並找出事件背後真正的原因。但出題者僅能以「是」、「不是」或「沒有關係」來回答問題。

本遊戲蒐集各種論壇、平台的42個題目,提供給想玩海龜湯卻愁找不到題目的你們。
決定好一位出題者,就可以在聚會、活動和排隊等待種種狀況下與眾人同樂。


2019年8月15日 星期四

【Unity官方教學分享】移動和旋轉(Translate and Rotate)

網頁連結

如何使用transform下的兩個函式;Translate和Rotate去影響一個非剛體物件的位置和角度。

在以下的範例,我們可以看到移動Translate的引數是一個vector3,而數值為Z軸1,X及Y為0。
另外這個範例在Unity執行時的一個frame都會運作,因為它是寫在Unpate中。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class TransformFunctions : MonoBehaviour
{
    void Start()
    {
        
    }

    void Update()
    {
        transform.Translate(new Vector3(0, 0, 1));
    }
}

2019年8月9日 星期五

【Unity官方教學分享】啟動物件(Activating GameObjects)

網頁連結

如何使用SetActive改變場景中物件Active狀態,並分辨activeSelf /activeInHierarchy確認物件Active狀態時的差別

要在腳本中設定物件的Active狀態,你可以使用SetActive函式。
SetActive函式可以在場景中切換物件的Activate狀態,在以下的範例裡,我們在Start函式下寫一條簡單的程式碼gameObject.SetActive(false)。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class ActiveObjects : MonoBehaviour
{
    void Awake()
    {
        gameObject.SetActive(false);
    }
}
接著執行Unity時,你可以看到表示物件Active狀態的打勾被取消,場景物件消失,Hierarchy視窗下字體顯示也變淡了,表示此物件處於一個未被啟動的狀態。

2019年6月24日 星期一

【Unity】自製重力

Unity中的自製重力,以下是程式碼:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class MyKinematic : MonoBehaviour {
    public float gravity = 9.8f;//重力
    public Vector3 velocity = Vector3.zero;//速率
    public Vector3 deltaMove = Vector3.zero;//每偵位移量

    public float halfBoundHeight;//物體的一半高度
    public BoxCollider myCollider;//物體的Collider

    public Vector3 addForce = Vector3.zero;//跳躍施力
    // Use this for initialization
    void Start ()
    {
        myCollider = GetComponent<BoxCollider>();
        halfBoundHeight = (myCollider.size.y * 0.5f) * transform.localScale.y;
    }
 
 // Update is called once per frame
    void Update ()
    {
        HandleKeyInput();//按鍵輸入函式
    }

    void LateUpdate()
    {
        float deltatime = Time.deltaTime;
        UpdateGravity(deltatime);//重力
        UpdateMovement(deltatime);//落下
    }

    void UpdateGravity(float deltatime)
    {
        velocity.y -= gravity * deltatime; ;
    }

    void UpdateMovement(float deltatime)
    {
        //落下
        deltaMove = velocity * Time.deltaTime;

        //碰撞判定
        Vector3 raystart = transform.position + myCollider.center * transform.localScale.y;//射線起點
        float updown = 1;//方向判定
        if (velocity.y < 0)
            updown = -1;
        Vector3 raydir = Vector3.up * updown;

        float rayLength = Mathf.Abs(deltaMove.y) + halfBoundHeight;

        RaycastHit rhf = new RaycastHit();//射線
        if (Physics.Raycast(raystart, raydir, out rhf, rayLength))
        {

            if (rhf.collider != null && rhf.collider.gameObject.tag == "ground")//地板判定
            {
                deltaMove.y = rhf.point.y - raystart.y + halfBoundHeight * -updown;
                velocity = deltaMove / deltatime;
            }
        }
        transform.Translate(deltaMove, Space.World);//物體移動
    }

    void AddForce(Vector3 force)
    {
        velocity += force;
    }

    void HandleKeyInput()
    {
        if (Input.GetKeyDown(KeyCode.W))
            AddForce(addForce);

    }
}
至於重力為什麼要重新製作,一方面是為了對整套重力系統重新做理解,另一方面則是Unity物理擬真程度的問題,有些時候其實不需要那麼真實的物理效果,而自製的物理可以簡化掉一些不需要的結果。
以下是參考的網站:
設計我們的遊戲物理-簡易重力篇

2019年5月20日 星期一

使用google雲端硬碟分享html

今天要分享的是使用google雲端硬碟分享html檔案的方法。
首先開啟google雲端硬碟,在"我的雲端硬碟"下右鍵新增資料夾。

2019年4月10日 星期三

【舊專案整理兼筆記】仿2048

2048遊戲實作。
成品下載連結:
透過手指滑動螢幕,組合數字,產生出2048吧!

2019/04/15追記:
手指滑動功能完成
手機版本完成and上架

2019/04/11追記:
1)上述第1, 2點bug修正。
2)追加數字產生動畫,新增標題、背景等UI。
3)新增重新開始按鈕。
4)新增遊戲結束和過關的字樣。


待修正的問題及功能:
1)沒有數字移動時還是會生成新的數字,這點和原版本不同。
2)在盤面上沒有空格時,若玩家按下無法合併數字的方向,會直接判斷為遊戲結束。
3)追加動畫,美化介面。
4)重新開始遊戲鈕。
5)手機板按鈕(或滑動。


2018年5月3日 星期四

【Unity官方教學分享】遊戲物件和元件

網頁連結

在Unity場景中被建立的物件稱為遊戲物件(Game Object),任何存在於場景中的東西都被視為Game Object,而一個Game Object是由多個元件(Component)所組成。

2018年5月2日 星期三

【Unity】非固定式虛擬方向鍵製作Part.2

上一篇中我們完成了滑鼠按下及拖曳時的回饋圖示,接下來要把拖曳中滑鼠位置的數值,帶入角色圖中完成移動的效果。

首先我們直覺一點來考慮移動這件事,目前我們已經有了開始位置startPos和當前位置nowPos,那只要把這兩點距離算出來,就有一個數值可以作為移動量值。
開啟Controller腳本,在dragState = true;後加入以下程式碼:
float dis = Vector2.Distance(nowPos, startPos);
Vector2 dir = (nowPos - startPos).normalized;
actor.Translate(new Vector2(dis * dir.x, dis * dir.y) * speed);
Debug.Log(new Vector2(dis * dir.x, dis * dir.y) * speed);
float變數dis為nowPos到startPos的距離,接著用兩點距離的normalized數值作為方向並帶入變數dir,最後將 dis * dir * speed的數值帶入actor.Translate就完成目前的移動,可以用Debug.Log看看目前移動的數值。(這裡的speed是一個全域float變數,數值0.1f)

2018年5月1日 星期二

【Unity官方教學分享】簡單的多人連線遊戲概要

網頁連結

在一整個多人連線系列的教學中,我們把握了大部分基本概念,以及多人連線遊戲中所需的元件。

我們同時也知道如何使用HLAPI建置一個專案,了解到當使用HLAPI 伺服器和所有用戶端,是在同一時間對同一物件的腳本執行同一段程式碼,接著我們討論使用HLAPI去檢查伺服器、 LocalPlayer、用戶端時,如何去控制當中的邏輯流程。

我們學習到HLAPI中的RPCs變數;Commands和ClientRpc’s,Commands是由用戶端呼叫伺服器執行,而ClientRpc’s則是由伺服器呼叫用戶端執行。

接著是SyncVars和SyncVar hooks,使用[SyncVar]變數可以讓數值保持同步,而且再使用SyncVar hooks的話,可以在該數值變化時,呼叫某個函式。

使用NetworkIdentity和NetworkTransform元件,可以讓多人連線中物件的Transforms數值保持同步。

我們學到許多關於網路的內建元件;NetworkManager、NetworkManagerHUD 和NetworkStartPosition,當然關於網路的內建元件還有許多,但它們更加專業而且也不常使用,我以我們會在其他章節中介紹。

我們希望本教學是製作多人連線遊戲的好起點,同時這個範例展現了在Unity中,製作多人遊戲是非常方便的。

上一篇:生成和重生

建立一個簡單的多人連線範例

2018年4月30日 星期一

【Unity官方教學分享】生成和重生

網頁連結

設定玩家生成的初始位置
目前玩家物件在遊戲中,生成及重生的位置為原點;也就是(0, 0, 0)的位置。每次遊戲開始,除非玩家移動過自己的玩家物件,否則當其他玩家進入遊戲,這些物件會重疊在同一個位置。
在理想狀況下,這些玩家物件應該要生成在不同的地方。NetworkStartPosition元件可以做到這點,因為它內建生成位置處理的功能。

接下來我們要新增兩個生成位置,首先要新增兩個帶有NetworkStartPosition元件的新物件。

  • 新增一個空物件並命名為SpawnPosition1
  • 選擇SpawnPosition1,並且...
  • 加上Network->NetworkStartPosition元件
  • 設定Position數值為(3, 0, 0)
  • 複製貼上一個SpawnPosition1,並重新命名為SpawnPosition2
  • 將SpawnPosition2的位置設為(-3, 0, 0)
  • 選擇Hierarchy視窗下的NetworkManager
  • 將 Spawn Info屬性展開
  • 將Player Spawn Method改為Round Robin
因為這兩個SpawnPosition物件下有NetworkStartPosition元件,所以NetworkManager會自動去尋找SpawnPosition,接著使用SpawnPosition的位置作為玩家連上伺服器時,物件生成的起始點。

2018年4月29日 星期日

【Unity官方教學分享】銷毀敵人物件

網頁連結

雖然敵人物件可以被子彈攻擊並且造成傷害,但是當敵人的血量歸零時,該物件應該要被銷毀。
要做到這件事,我們需要調整Health腳本,最簡單的方法是使用一個布林變數DestroyOnDeath,來調整該物件是否在死亡時銷毀。

開啟Health腳本,修改以下內容,新增布林變數DestroyOnDeath,接著用if (destroyOnDeath)判斷是否要銷毀該物件
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.Networking;
using System.Collections;

public class Health : NetworkBehaviour {

    public const int maxHealth = 100;

    public bool destroyOnDeath;

    [SyncVar(hook = "OnChangeHealth")]
    public int currentHealth = maxHealth;

    public RectTransform healthBar;

    public void TakeDamage(int amount)
    {
        if (!isServer)
            return;
        
        currentHealth -= amount;
        if (currentHealth &lt;= 0)
        {
            if (destroyOnDeath)
            {
                Destroy(gameObject);
            } 
            else
            {
                currentHealth = maxHealth;

                // called on the Server, will be invoked on the Clients
                RpcRespawn();
            }
        }
    }

    void OnChangeHealth (int currentHealth)
    {
        healthBar.sizeDelta = new Vector2(currentHealth, healthBar.sizeDelta.y);
    }

    [ClientRpc]
    void RpcRespawn()
    {        if (isLocalPlayer)
        {
            // Set the player’s position to origin
            transform.position = Vector3.zero;
        }
    }
}

【Unity官方教學分享】處理非玩家角色物件

網頁連結

目前我們的範例主要都集中在玩家物件上,但是大部分的遊戲會有非玩家物件存在於遊戲世界中。這次我們忽略環境物件,先集中在非玩家角色物件上。
玩家物件會在用戶端連上伺服器時生成,但敵人物件需要由伺服器主動生成。

在本次教學中,我們會新增一個敵人生成器(Enemy Spawner),用來創建可以被玩家攻擊的敵人物件。

  • 新增空物件命名為EnemySpawner,並在EnemySpawner上...
  • 新增Network->NetworkIdentity元件
  • 將NetworkIdentity中的Server Only設為true
將Server Only設為true,可以防止EnemySpawner發送給用戶端。

2018年4月28日 星期六

【Unity官方教學分享】死亡和重生

網頁連結

目前當玩家血量歸零時,除了在console視窗中顯示文字外,不會發生任何事,現在我們要將此範例修改的更像遊戲,當玩家的血量歸零,將會被傳送到起始位置並恢復血量。

接下來我們會使用[ClientRpc]屬性,這是另一個狀態同步工具。
加上ClientRpc的函式會從;帶有NetworkIdentity元件,並且是從伺服器生成的任意物件執行,即使在伺服器上呼叫帶有ClientRpc的函式,它也會在用戶端上執行。
先前提過的Command和ClientRpc相反,Command是在用戶端上呼叫,伺服器上執行。

要在一個函式前加上ClientRpc,要使用 [ClientRpc]變數,而且函式名稱前必須加上Rpc。此函數會在伺服器呼叫它時,於用戶端上執行。任何需要的變數會自動傳送給用戶端,更多關於[ClientRpc]變數的資訊,可以參考這裡

2018年4月27日 星期五

【Unity官方教學分享】連線時的玩家血量

網頁連結

玩家的血量狀態在伺服器上做變化,之後再讓這些更動給所有用戶端,這稱作伺服器權限(Server Authority),更多關於伺服器權限的資訊可以點這裡
為了讓我們的目前血量和傷害系統能夠在伺服器權限下運作,需要使用SyncVars這個特殊變數,讓各個數值可以同步於網路環境。此變數在腳本中寫做[SyncVar],更多關於SyncVars的資訊可以點這裡

首先開啟Health腳本,修改成以下內容,新增命名空間UnityEngine.Networking,把繼承改成NetworkBehaviour,在currentHealth前加上[SyncVar],最後增加if (!isServer)判斷式讓TakeDamage函式只會在伺服器上執行:
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.Networking;
using System.Collections;

public class Health : NetworkBehaviour 
{

    public const int maxHealth = 100;

    [SyncVar]
    public int currentHealth = maxHealth;
    public RectTransform healthBar;

    public void TakeDamage(int amount)
    {
        if (!isServer)
        {
            return;
        }
        
        currentHealth -= amount;
        if (currentHealth &lt;= 0)
        {
            currentHealth = 0;
            Debug.Log("Dead!");
        }

        healthBar.sizeDelta = new Vector2(currentHealth, healthBar.sizeDelta.y);
    }
}
編譯後可以進行測試,測試連線時結果的方法點我

2018年4月26日 星期四

【Unity官方教學分享】玩家血量(單機)

網頁連結

同步玩家狀態是多人連線中一個重要的概念。
這次的教學中,我們將在子彈碰撞到玩家物件時,讓玩家的血量數值減少,而當前血量也屬於玩家狀態之一,所以我們也要對血量數值做同步。

新增子彈碰撞
讓子彈能影響目標物的第一步是新增能處理碰撞的元件,在本範例中,我們會在子彈碰到其他碰撞體時,將子彈銷毀。
  • 在Bullet物件下新增名為Bullet的腳本
  • 開啟此腳本,並刪除所有內容
  • 新增碰撞時的處理函式,內容是碰到其他碰撞體時,將自己銷毀
using UnityEngine;
using System.Collections;

public class Bullet : MonoBehaviour 
{
    
    void OnCollisionEnter()
    {
        Destroy(gameObject);
    }
}
編譯過Bullet腳本後,可以做第一次的測試,測試連線時結果的方法點我
現在當子彈會在碰撞時銷毀,而且子彈被NetworkManager管理,當子彈在伺服器中被銷毀時,所有用戶端看到的那顆子彈也會被銷毀。

2018年4月25日 星期三

【工具分享】Excel轉JSON

今天在研究Unity如何讀取Excel時不小心找到的工具;Excel轉JSON的程式,雖然跟一開始的目的不同,但感覺之後會用的到,就當作分享順便做個紀錄。
以下是原作者使用教學+下載連結:
https://neil3d.github.io/app/excel2json.html
最新版本是v1.1.1,點擊excel2json-111.zip連結下載,解壓縮後執行excel2json.exe就可以使用,介面如下:
※5月3日補充:
Export Type:輸出類型,有Array和Dict Object
Encoding:輸出JSON檔的文字編碼
Low case:是否要轉換小寫
Header:留空行數,預設最小是2。(鍵值名稱固定第一行,變數類型固定第二行)

2018年4月24日 星期二

【Unity官方教學分享】新增多人連線時的射擊功能

網頁連結

在本教學中將在子彈物件上新增網路功能,我們必須對Bullet prefab及腳本做更新。
首先,Bullet prefab需要NetworkIdentity元件讓網路系統能辨識它,接著需要NetworkTransform同步移動和旋轉,最後必須在NetworkManager的Spawnable Prefab上註冊。
  • 在project視窗下點擊Bullet prefab
  • 新增元件Network->NetworkIdentity
  • 新增元件Network->Network Transform
  • 將Network Transform下的Network Send Rate設為0
子彈在射出後並不會改變方向或速度,所以不需要做移動資訊的更新,每個用戶端可以確實地計算出子彈位置,透過將Network Send Rate設為0,可以讓網路資料流量變少以達到提高效能的結果。

2018年4月21日 星期六

【Unity官方教學分享】射擊(單機)

網頁連結


多人連線遊戲的一個常見特徵是玩家可以發射子彈,並且讓這些子彈在遊戲中的每一個用戶端上執行。
本次的教學將會增加射擊功能,但是會先製作單機版本,非連線模式,下一篇的教學才會包含網路環境下的射擊。

  • 新增一個Sphere物件
  • 將它重新命名為Bullet
  • 選擇Bullet物件,修改scale數值為(0.2, 0.2, 0.2)
  • 在Bullet下新增元件Physics->Rigidbody
  • 將Rigidbody下的Use Gravity設為false
  • 拖曳Bullet至Project視窗下的prefab資料夾,將Bullet設為prefab物件
  • 刪除場經中的Bullet

PlayerController腳本先在需要新增射擊功能,此腳本需要參考Bullet prefab,並由一段程式碼完成射擊功能。
添加Bullet prefab的GameObject變數:
public GameObject bulletPrefab;
添加Bullet生成位置變數:
public Transform bulletSpawn;
在Update中添加以下的判斷式:
if (Input.GetKeyDown(KeyCode.Space))
{
    Fire();
}
新增一個Fire函式來發射子彈:
void Fire()
{
    // Create the Bullet from the Bullet Prefab
    GameObject bullet = (GameObject)Instantiate (
        bulletPrefab,
        bulletSpawn.position,
        bulletSpawn.rotation);

    // Add velocity to the bullet
    bullet.GetComponent<Rigidbody>().velocity = bullet.transform.forward * 6;

    // Destroy the bullet after 2 seconds
    Destroy(bullet, 2.0f);
}

【Unity官方教學分享】識別本地玩家物件

網頁連結

目前各個玩家物件看起來是相同的,這會讓玩家無法辨識哪個角色是自己的,為了讓玩家可以辨識自己的角色,我們將玩家所屬的物件變為藍色。

  • 開啟PlayerController腳本
  • 新增OnStartLocalPlayer函式來改變玩家物件的顏色
using UnityEngine;
using UnityEngine.Networking;

public class PlayerController : NetworkBehaviour
{
    void Update()
    {
        if (!isLocalPlayer)
        {
            return;
        }

        float x = Input.GetAxis("Horizontal") * Time.deltaTime * 150.0f;
        float z = Input.GetAxis("Vertical") * Time.deltaTime * 3.0f;

        transform.Rotate(0, x, 0);
        transform.Translate(0, 0, z);
    }

    public override void OnStartLocalPlayer()
    {
        GetComponent<MeshRenderer>().material.color = Color.blue;
    }
}
這個函式只能由用戶端上的LocalPlayer呼叫,所以只會看到自己的玩家物件變成藍色,如果某功能只適用於本機,那麼OnStartLocalPlayer函式是做初始化的好地方,如攝影機設定或各種輸入等等。NetworkBehaviour類別中還有許多有用的虛擬函式,更多資訊可以參考這裡這裡

完成後像上一篇教學一樣啟動兩邊的實例測試結果,我們可以看到由本機控制的角色變為藍色,而另一個角色則保持白色


上一篇:測試多人連線的移動
下一篇:射擊(單機)

建立一個簡單的多人連線範例

【自製小遊戲】水平思考猜謎(海龜湯)

遊戲連結 海龜湯的玩法是由出題者提出一個難以理解的事件,參與猜題者可以提出任何問題以試圖縮小範圍並找出事件背後真正的原因。但出題者僅能以「是」、「不是」或「沒有關係」來回答問題。 本遊戲蒐集各種論壇、平台的42個題目,提供給想玩海龜湯卻愁找不到題目的你們。 ...