Unity3D入門-坦克大戰

2020-10-05 22:00:04

Unity3D入門-坦克大戰

1.基礎

概念1:預製體PreFab

將一個GameObject製作成一個元件模板,用於批次套用

向場景新增一個預製體時,會建立一個它的範例,可在不同場景或同一場景建立多個預製體的範例,當修改預製體的屬性時,這些修改也應用在所有範例上。

概念2:碰撞器Box collider

兩個碰撞的物體身上都要有碰撞器元件,其中至少有一個為剛體Rigidbody(最好是運動的一方)

原理:剛體長時間不運動會休眠以提升程式效能,如果選擇不運動的為剛體,可能互動無效。

其中2D、3D謹防混用,混用則無效

概念3:元件層級Layer

Camera-Sorting Layer-Order In layer

概念4:音訊源Audio Source

屬性說明
Audio Clip設定被播放的音訊檔
Mute靜音播放
Play On Awake喚醒時播放

指令碼結構:

public class XXX:Monobehaviour{ //繼承Unity的Monobehaviour部分方法
    
	void Start(){ //遊戲執行第一幀執行
	
	}
	
	void Update(){ //遊戲每執行一幀執行一次
	
	}
}

2.功能介紹

​ 選單頁通過鍵盤【W】、【S】鍵控制指標選擇單/雙人遊戲,點選空格鍵確認選項並開始遊戲。玩家有三點生命值,在每次生成後的三秒內帶有保護盾,敵方攻擊無效。遊戲開始後生成三架敵方坦克,此後每隔四秒隨機生成敵方坦克,當玩家坦克被擊殺三次或最下方巢穴被敵方炸燬後遊戲失敗,失敗後玩家不可控制坦克移動,三秒後跳轉回選單頁。遊戲頁右側圖示和數位顯示被玩家擊殺的坦克數和玩家剩餘生命值。【ESC】退出遊戲。


3.部分程式碼

玩家指令碼:

public class Player : MonoBehaviour
{
    public float moveSpeed=3;
    private Vector3 bulletEulerAngles;
    private float timeVal;//設定攻擊CD
    private float defendTimeVal=3;
    private bool isDefended=true;

    private SpriteRenderer sr;
    public Sprite[] tankSprite;//依次為上右下左

    public GameObject bulletPrefab;
    public GameObject explosionPrefab;
    public GameObject defendEffectPrefab;//受保護參照
    public AudioSource moveAudio;//音效元件參照,控制音效播放
    public AudioClip[] tankAudio;//音效素材,拿到資源,控制渲染器參照

    public void Awake()//屬性等在awake中賦值,一開始就拿到
    {
        sr = GetComponent<SpriteRenderer>();

    }
    // Start is called before the first frame update
    void Start()
    {
        
    }

    // Update is called once per frame
    void Update()
    {
        //是否處於無敵狀態
        if(isDefended)
        {
            defendEffectPrefab.SetActive(true);
            defendTimeVal -= Time.deltaTime;
            if(defendTimeVal<=0)
            {
                isDefended = false;
                defendEffectPrefab.SetActive(false);
            }

        }
        
    }

    private void FixedUpdate()//固定物理幀,規定佔用時間固定
    {
        if(PlayerManager.Instance.isDefeated)
        {
            return;
        }
        Move();
        if(timeVal>=0.4f)
        {
            Attack();
        }
        else
        {
            timeVal += Time.fixedDeltaTime;
        }
    }

    private void Attack()
    {
        if(Input.GetKeyDown(KeyCode.Space))
        {
            //2D遊戲旋轉方向與3D相反
            Instantiate(bulletPrefab,transform.position,Quaternion.Euler(transform.eulerAngles+bulletEulerAngles));//最後一個引數:尤拉角轉變成四元數
            timeVal = 0;
        }
    }
    //坦克移動
    private void Move()
    {
        float h = Input.GetAxisRaw("Horizontal");//h和v值為1或-1
        transform.Translate(Vector3.right * h * moveSpeed * Time.fixedDeltaTime,Space.World);
        //改變轉向:1.更換不同圖片 2.直接改變圖片轉向
        if(h<0)
        {
            sr.sprite = tankSprite[3];
            bulletEulerAngles =new  Vector3(0,0,90);
        }
        else if(h>0)
        {
            sr.sprite = tankSprite[1];
            bulletEulerAngles =new  Vector3(0,0,-90);
        }

        if(Mathf.Abs(h)>0.05f)
        {
            moveAudio.clip = tankAudio[1];

            if(!moveAudio.isPlaying)
            {
                moveAudio.Play();
            }
        }

        if(h!=0)//設定優先順序,橫向優先
        {
            return;
        }
        float v = Input.GetAxisRaw("Vertical");
        transform.Translate(Vector3.up * v * moveSpeed * Time.fixedDeltaTime,Space.World);
        if(v<0)
        {
            sr.sprite = tankSprite[2];
            bulletEulerAngles =new  Vector3(0,0,180);
        }
        else if(v>0)
        {
            sr.sprite = tankSprite[0];
            bulletEulerAngles =new  Vector3(0,0,0);
        }
        if(Mathf.Abs(v)>0.05f)
        {
            moveAudio.clip = tankAudio[1];

            if(!moveAudio.isPlaying)
            {
                moveAudio.Play();
            }
        }else{
            moveAudio.clip = tankAudio[0];

            if(!moveAudio.isPlaying)
            {
                moveAudio.Play();
            }
        }
    }

    public void Die()
    {
        if(isDefended)
        {
            return;
        }
        PlayerManager.Instance.isDead = true;
        //爆炸特效
        Instantiate(explosionPrefab,transform.position, transform.rotation);
        //坦克死亡
        Destroy(gameObject);
    }


}

炸彈指令碼

public class Bullet : MonoBehaviour
{

    public float moveSpeed=10;
    public bool isPlayerBullet;//不設定預設為false
    public AudioClip hitAudio;
    // Start is called before the first frame update
    void Start()
    {
        
    }

    // Update is called once per frame
    void Update()
    {
        //Translate的第一個引數是沿著世界座標移動時最後一個引數可寫可不寫,預設世界座標
        //沿著自身座標移動時,最後一個引數一定要寫
        transform.Translate(transform.up * moveSpeed * Time.deltaTime, Space.World);
    }

    private void OnTriggerEnter2D(Collider2D collision)
    {
        switch(collision.tag)
        {
            case "Tank":
                if(!isPlayerBullet)
                {
                    collision.SendMessage("Die");
                    Destroy(gameObject);
                }
                
                break;
            case "Heart":
                collision.SendMessage("Die");
                Destroy(gameObject);
                break;
            case "Enemy":
                if(isPlayerBullet)
                {
                    collision.SendMessage("Die");
                    Destroy(gameObject);//銷燬自身
                }
                
                break;
            case "Wall":
                if(isPlayerBullet)
                {
                    PlayAudio();
                }
                Destroy(collision.gameObject);
                Destroy(gameObject);//銷燬牆和炮彈本身
                break;
            case "Barrier":
                if(isPlayerBullet)
                {
                    PlayAudio();
                }
                
                Destroy(gameObject);
                break;
            default:
                break;
        }
    }

    public void PlayAudio()
    {
        AudioSource.PlayClipAtPoint(hitAudio,transform.position);
    }
}


4.展示

首頁面選擇單人/雙人遊戲
Menu


攻擊敵人
Hit


顯示攻擊敵人的數量和剩餘生命值

Count


遊戲失敗
Defeat


5.打包釋出

儲存並命名場景-find-Build Settings-Build-選擇打包到的目錄。

踩坑:

UnityError.BuildPlayerWindow+BuildMaethodException:2 errors

解決方法:

選擇打包目錄時建立一個空資料夾存放。


6.未處理問題

字型顯示模糊