❤❤Fungus新課程即將發布,快寫問卷拿優惠❤❤
顯示具有 遊戲製作 標籤的文章。 顯示所有文章
顯示具有 遊戲製作 標籤的文章。 顯示所有文章

2017年7月4日 星期二

Unity 打磚塊 2D 教學(下) 過關機制


下載完整可執行遊戲的專案 二合一(台幣約60元)

Player.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Player : MonoBehaviour
{

    [Header("水平移動速度")]
    public float speedX;
    Rigidbody2D playerRigidbody2D;

    void Start()
    {
        playerRigidbody2D = GetComponent<Rigidbody2D>();
    }

    void Update()
    {
        moveLeftOrRight();
    }

    float LeftOrRight()
    {
        return Input.GetAxis("Horizontal");
    }

    void moveLeftOrRight()
    {
        playerRigidbody2D.velocity = LeftOrRight() * new Vector2(speedX, 0);
    }
}
Ball.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class Ball : MonoBehaviour
{
    public Text scoreText;
    int score;

    Rigidbody2D ballRigidbody2D;
    CircleCollider2D ballCircleCollider2D;

    [Header("水平速度")]
    public float speedX;

    [Header("垂直速度")]
    public float speedY;

    #region 教學理解用 可不寫
    [Header("實際水平速度")]
    public float velocityX;

    [Header("實際垂直速度")]
    public float velocityY;
    #endregion



    void Start()
    {
        ballRigidbody2D = GetComponent<Rigidbody2D>();
        ballCircleCollider2D = GetComponent<CircleCollider2D>();

        //切換成Kinematic模式
        //Uity 2018版以後不加這行的話 發球之前球會無法跟著球拍移動
        ballRigidbody2D.bodyType = RigidbodyType2D.Kinematic;

        scoreText.text = "目前分數:";
        Invoke("ballStart", 3);
    }

    void Update()
    {
        #region 教學理解用 可不寫
        velocityX = ballRigidbody2D.velocity.x;
        velocityY = ballRigidbody2D.velocity.y;
        #endregion

        if (Input.GetKey(KeyCode.Space))
        {
            ballStart();
        }
    }

    void ballStart()
    {
        if (isStop())
        {
            ballCircleCollider2D.enabled = true;
            transform.SetParent(null);
            ballRigidbody2D.velocity = new Vector2(speedX, speedY);
            
            //Unity 2018以後的版本需要加下面這行:
            //改回預設的Dynamic,使用Unity內建的物理運動規則
            ballRigidbody2D.bodyType = RigidbodyType2D.Dynamic;
        }
    }

    bool isStop()
    {
        return ballRigidbody2D.velocity == Vector2.zero;
    }

    void OnCollisionEnter2D(Collision2D other)
    {
        lockSpeed();
        if (other.gameObject.CompareTag(tags.磚塊.ToString()))
        {
            GameManager.brickCount--;
            Debug.Log("目前磚塊數量: "+GameManager.brickCount);
            GameManager.checLevelClearOrNot();
            other.gameObject.SetActive(false);
            score += 10;
            scoreText.text = "目前分數:" + score;
        }
    }

    void lockSpeed()
    {
        Vector2 lockSpeed = new Vector2(resetSpeedX(), resetSpeedY());
        ballRigidbody2D.velocity = lockSpeed;
    }

    float resetSpeedX()
    {
        float currentSpeedX = ballRigidbody2D.velocity.x;
        if (currentSpeedX < 0)
        {
            return -speedX;
        }
        else
        {
            return speedX;
        }
    }

    float resetSpeedY()
    {
        float currentSpeedY = ballRigidbody2D.velocity.y;
        if (currentSpeedY < 0)
        {
            return -speedY;
        }
        else
        {
            return speedY;
        }
    }
}
Trap.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Trap : MonoBehaviour {
    [Header("被撞到時候的位移")]
    public Vector3 offset;

    public int life;

    private void OnCollisionEnter2D(Collision2D other)
    {
        if (other.gameObject.CompareTag(tags.球.ToString()))
        {
            life--;
            gameObject.transform.position += offset;
        }
        if (life<=0&&!GameManager.LevelClear)
        {
            GameManager.ReloadThisScene();
        }

    }

}
GameManager.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;

public class GameManager : MonoBehaviour
{
    [Header("可打破的磚塊初始數量")]
    public static int brickCount;

    static GameObject nextLevelButton;

    public static void ReloadThisScene() {
        Scene current = SceneManager.GetActiveScene();
        SceneManager.LoadScene(current.name);
    }

    public static bool LevelClear {
        get {

            if (brickCount<=0)
            {
                return true;
            }
            return false;
        }
    }
    public static void checLevelClearOrNot() {
        if (LevelClear)
        {
            showNextLevelButton();
        }
    }
    public void GotoScene(string next) {
        SceneManager.LoadScene(next);
    }


    void Start()
    {
        nextLevelButton = GameObject.FindGameObjectWithTag(tags.下一關按鈕.ToString());
        nextLevelButton.SetActive(false);

        brickCount = GameObject.FindGameObjectsWithTag(tags.磚塊.ToString()).Length;
        Debug.Log("一開始有 "+brickCount+" 個可打破的磚塊");
    }

    static void showNextLevelButton() {
        nextLevelButton.SetActive(true);
    }

    // Update is called once per frame
    void Update()
    {

    }
}

enum tags
{
    磚塊, 背景, 球拍, 球, 下一關按鈕
}
上集的程式碼與教學
http://www.morningfungame.com/2017/01/Unity-Arkanoid-breakout-tutorial-2D.html

2017年1月25日 星期三

Unity 打磚塊 2D 教學 (上)


下載完整可執行遊戲的專案 二合一(台幣約60元)

Player.cs

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

public class Player : MonoBehaviour {

    [Header("水平移動速度")]
    public float speedX;
    Rigidbody2D playerRigidbody2D;

    void Start () {
        playerRigidbody2D = GetComponent<Rigidbody2D> ( );
 }
 
 void Update () {
        moveLeftOrRight ( );
    }

    float LeftOrRight ( ) {
        return Input.GetAxis ( "Horizontal");
        }

    void moveLeftOrRight ( ) {
        playerRigidbody2D.velocity = LeftOrRight() * new Vector2 (speedX,0 );
        }
}


Ball.cs

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

public class Ball : MonoBehaviour
    {
    public Text scoreText;
    int score;

    Rigidbody2D ballRigidbody2D;
    CircleCollider2D ballCircleCollider2D;

    [ Header ( "水平速度" )]
    public float speedX;

    [Header ( "垂直速度" )]
    public float speedY;

    #region 教學理解用 可不寫
    [Header ( "實際水平速度" )]
    public float velocityX;

    [Header ( "實際垂直速度" )]
    public float velocityY;
    #endregion

    enum tags
        {
        磚塊,
        背景
        }

    void Start ( )
        {
        ballRigidbody2D = GetComponent<Rigidbody2D> ( );
        ballCircleCollider2D = GetComponent<CircleCollider2D> ( );

        //切換成Kinematic模式
        //Uity 2018版以後不加這行的話 發球之前球會無法跟著球拍移動
        ballRigidbody2D.bodyType = RigidbodyType2D.Kinematic;

        scoreText.text = "目前分數:";
        Invoke ( "ballStart",3 );
        }

    void Update ( )
        {
        #region 教學理解用 可不寫
        velocityX = ballRigidbody2D.velocity.x;
        velocityY = ballRigidbody2D.velocity.y;
        #endregion

        if ( Input.GetKey(KeyCode.Space) )
            {
            ballStart ( );
            }
        }

    void ballStart ( ) {
        if ( isStop ( ) )
            {
            ballCircleCollider2D.enabled = true;
            transform.SetParent ( null );
            ballRigidbody2D.velocity = new Vector2 ( speedX , speedY );
            
            //Unity 2018以後的版本需要加下面這行:
            //改回預設的Dynamic,使用Unity內建的物理運動規則
            ballRigidbody2D.bodyType = RigidbodyType2D.Dynamic;
            }
        }

    bool isStop ( ) {
        return ballRigidbody2D.velocity == Vector2.zero;
        }

    void OnCollisionEnter2D ( Collision2D other )
        {
        lockSpeed ( );
        if ( other.gameObject.CompareTag ( tags.磚塊.ToString ( ) ) )
            {
            other.gameObject.SetActive ( false );
            score += 10;
            scoreText.text = "目前分數:" + score;
            }
        }
    
    void lockSpeed ( )
        {
        Vector2 lockSpeed = new Vector2 ( resetSpeedX ( ) , resetSpeedY ( ) );
        ballRigidbody2D.velocity = lockSpeed;
        }

    float resetSpeedX ( )
        {
        float currentSpeedX = ballRigidbody2D.velocity.x;
        if ( currentSpeedX < 0 )
            {
            return -speedX;
            }
        else
            {
            return speedX;
            }
        }

    float resetSpeedY ( )
        {
        float currentSpeedY = ballRigidbody2D.velocity.y;
        if ( currentSpeedY < 0 )
            {
            return -speedY;
            }
        else
            {
            return speedY;
            }
        }
    }
下集的程式碼:
http://www.morningfungame.com/2017/07/Unity-Arkanoid-breakout-tutorial-2D-2.html

2016年9月2日 星期五

Unity 好用小工具 整合Photoshop 的 Psd Importer 教學

Unity 大約2019版開始有內建官方PSD importer,只要在photoshop裡把檔案轉存為PSB格式,就可以直接拉到Unity裡並保留圖層關係。
注意是PSB格式才有效,不是PSD,雖然它叫做PSD importer...
官方說明 或搜尋 unity package psd importer
https://docs.unity3d.com/Packages/com.unity.2d.psdimporter@4.0/manual/index.html



===以下是舊版文章的備份 僅供參考======



youtube教學影片
https://youtu.be/0FcfV_DLn6c

Unity PSD匯入器  Unity PSD importer

簡介:
可保留Photoshop的PSD檔圖層階層關係並且匯入Unity裡面,省下大量重新排列與對齊圖檔的時間

測試用的PSD檔下載
https://drive.google.com/drive/folders/0B9pF8Hbq-lgVaTByaU0wTmVjVHc


注意:
Photoshop 的PSD檔不能有混合選項或調整圖層之類的附加效果
目前測試可以支援形狀圖層與智慧型圖層

轉換混合選項或圖層樣式為一般圖層:
在Photoshop裡存檔以後點擊影像-->複製,只複製合併圖層不要打勾,按確定, 原版檔案就可以關掉了(避免不小心覆蓋到原始檔案)

按住Ctrl不放可跳著點選想要合併的圖層,再按Ctrl + E 合併圖層
按住Shift不放可連線點選想要合併的圖層,再按Ctrl + E 合併圖層

(此時範例PSD檔裡可以整理愛心與箭頭圖層)


下載 PSD importer
(網路上有另一個同名的插件,為了避免抓錯檔,可以從這裡下載)
下載(ChemiKhazi版)
https://github.com/ChemiKhazi/UnityPsdImporter


安裝 PSD importer
開啟一個新的Unity專案,Assets 裡新建一個Editor資料夾(名稱要一樣),把剛下載好的Unity PSD importer壓縮檔裡,bin資料夾底下的PhotoShopImporter.dll放到Editor資料夾裡
(若無法直接丟進Editor資料夾,可先解縮放到桌面上以後再丟進去)

匯入整理好的PSD:
整理好的PSD先丟到Assets裡,再點滑鼠右鍵,選擇PSD Importer




A.轉換為一般物件
選擇爸爸資料夾,等同於Photoshop PSD檔裡的爸爸群組,點擊 Sprite Creation 裡的 Create 2D Sprites按鈕,爸爸會變成父物件,底下的各個圖層會變成子物件,同時保留位置與階層關係


B.轉換為Canvas UI物件
功能表:GameObject-->UI新建一個Canvas物件,Assets裡在要轉換的PSD檔點滑鼠右鍵,選擇PSD Importer,選擇爸爸資料夾,等同於Photoshop PSD檔裡的爸爸群組,點擊場景裡的Canvas物件,再點擊Sprite Creation裡的Create UI Images按鈕,爸爸群組會變成Canvas底下的物件,同時保留位置與階層關係

轉成UI之前要新建一個Canvas物件




Kevin MacLeod」創作的「Cold Funk - Funkorama」是根據「Creative Commons Attribution」(https://creativecommons.org/licenses/by/4.0/) 授權使用

Kevin MacLeod」創作的「Hackbeat」是根據「Creative Commons Attribution」(https://creativecommons.org/licenses/by/4.0/) 授權使用
影片縮圖的素材:Designed by Freepik

2016年8月29日 星期一

Unity 免程式 遊戲 製作 教學:《脫逃時光》



下載這個小遊戲:脫逃時光 (PC/Mac)

下載脫逃時光的遊戲素材


使用軟體  Unity 5     配合免費外掛 Fungus

遊戲製作時的其他小工具:

Qdir (這邊有我製作的教學影片)

Psd Importer 教學 Unity 整合 Photoshop 保留圖層關係

Unity C# 教學 自訂檢視器 多個物件啟動關閉或改透明度

第一篇影片教學

第二篇教學











================================


第0篇:腦力激盪與前置作業


一開始的準備工作是這樣的:

遊戲架構發想
先想好需要什麼條件才能破關,比方一道密碼,然後取得這個密碼需要哪些線索或道具,再慢慢推演這些道具或線索要如何取得,主要的架構都確定以後,最後才思考要增加哪些非破關要素,但是可以讓遊戲更好玩的周邊設定。

以脫逃時光為例就是破關需要一道密碼,而密碼需要從網頁裡取得,開啟網頁之前又需要一台可使用的相機才能觸發該功能,接著組裝相機又需要空相機與乾淨鏡頭,乾淨鏡頭由髒鏡頭清潔過後而取得,空相機與清潔劑等又有各自不同的取得方式。接著就是加入流程分支的功能,讓遊戲破關的途徑不只一種。

最後才加入一些有的沒的功能,像是點了箱子以後他會跟你抱怨不要一直點我,這並非破關的要件,但是我覺得會很有趣所以就放進去了


收集遊戲素材與整理
收集圖片材料的時候,考量到遊戲類型屬於密室脫逃的關係,使用到的圖片都是物品為主,而且基本上是現代房間風格,不是古代或科幻房間等很需要考究或創造科技物件的風格,所以素材都使用freepik的免費素材,選擇很多而且都是向量檔。最後才尋找剩下的物品圖片與整間商店圖片,並且使用免費檔案管理軟體Q-Dir來整理檔案,我遊戲做到後來的時候常需要在好幾個資料夾之間做檔案交換,這個能夠四分割畫面的檔案總管軟體可以省下很多時間,而且當你只有下班時間才能進行自已遊戲專案的時候,時間顯得特別寶貴。

音樂音效的話是遊戲幾乎完成的時候才找,在Freesound.org有很多免費音效,YouTube Audio Library裡也一堆分類好的免費音樂

如何激發靈感
至於靈感的來源,我認為靈感跟流星一樣,咻的一下就不見了,可遇不可求,所以平常我就有使用Evernote的習慣,這個筆記軟體有PC版,MAC版,也有Android與iOS版,申請一個帳號就可多裝置通用,常常很多靈感是突然看到什麼東西就想到的,這時候隨身攜帶的手機就可以打字保存成為筆記,或是某張照片,時間不夠或不熟悉打字的話也可以手寫便條拍起來或乾脆錄音,某天有空的時候再統一整理,總之工具跟程式都是死的,如何活用取決於個人,也許對你而言有更好收集靈感的方式,這裡只是提供我的方法給大家參考一下。

在Freepik搜尋關鍵字Room,找了現在遊戲中的主要房間場景,然後這張圖片我就轉到手機桌面做為捷徑,利用等紅綠燈或公車之類瑣碎時間時就打開看一下,多看幾次總會有想到新東西的時候,最好當下就記錄起來。



===== 遊戲官方網頁與免費下載 =====