Unity經典游戲教程之:合金彈頭


版權聲明:

  • 本文原創發布於博客園"優夢創客"的博客空間(網址:http://www.cnblogs.com/raymondking123/)以及微信公眾號“優夢創客”(微信號:unitymaker)
  • 您可以自由轉載,但必須加入完整的版權聲明!

場景搭建

  1. 將第一關的3張背景圖片收尾相接

按住V鍵可以選中4個角進行拖拽和拼接
image
image
image

  1. 給它們一個共同的碰撞器作為地面
  2. 給場景中的石頭添加碰撞器
  3. 給木頭平台添加平台效果器

image

預制體的制作

  1. 木桶預制體

    1. 設置碰撞器,剛體設置為靜態
    2. 添加腳本和動畫控制器

    image
    3. 制作動畫

    當木桶碰到子彈則修改木桶的sprite

    木桶有兩滴血,當血量等於0的時候,播放閃爍的動畫
    image

  2. 敵人預制體

    1. 設置碰撞器和剛體
    2. 添加腳本和動畫控制器

    image
    3. 制作動畫

    image

    敵人碰到子彈后會播放死亡動畫

    敵人每隔5秒之后會向前移動一段距離,如果碰到玩家則會發起攻擊,如果沒有碰到則再過5秒之后繼續移動

    敵人只有出現在Camera內的時候才會移動,否則不進行移動計時

  3. 老人預制體

    1. 設置碰撞器、觸發器和剛體
    2. 添加腳本和動畫控制器

    image
    3. 制作動畫

    image
    image
    image
    image
    當老人在被綁住的時候碰到子彈,則被釋放,播放釋放動畫

    當老人在被綁住的時候碰到玩家,玩家可以穿過它

    當老人被釋放后碰到玩家,則會給玩家一個禮物,玩家吃掉禮物后會改變自身子彈的sprite

    當老人給完禮物后會穿過玩家跑走

  4. 敵機預制體

    1. 設置碰撞器和剛體
    2. 添加腳本和動畫控制器

    image
    3. 制作動畫

    image

    敵機在玩家走到某個位置時才會顯示,並且追蹤玩家的位置

    當與玩家的位置小於0.5時,會向下投放炸彈,若玩家被炸彈擊中則游戲結束

    敵機有10滴血,若血量降到0,則播放爆炸動畫,動畫播放完成銷毀敵機

  5. 子彈預制體

    1. 設置碰撞器和剛體
    2. 添加腳本和動畫控制器

    image

    利用對象池,在游戲開始的時候就創建10個子彈,每當玩家發出子彈則改變對象池中的某個子彈的位置

    當子彈位置離開玩家5個單位以上則會重置到開始位置

    若子彈碰到碰撞體之后子彈會被重置

  6. 炸彈預制體

    1. 設置碰撞器和剛體
    2. 添加腳本和動畫控制器

    image

Player的制作

  1. 將Body和Foot進行拼接,放在一個空節點下
  2. 創建一個空節點作為子彈的發出位置,並作為玩家的子節點
  3. 在Player腳下的碰撞器之外創建兩個空節點作為射線檢測的開始和結束位置用於檢測是否落地

image

image
4. Player動畫控制器的制作

image
5. Player移動的腳本實現

玩家的轉身是通過旋轉Y軸180°實現的

通過獲取按鍵的數值,改變對象Y軸的旋轉

Y軸的速度不能為0,不然跳不起來

Y軸的在空中或地上都要判斷,而X軸的移動只能在地上才能取得

只有在地上的時候才能播放walk動畫

跳躍的時候要將Walk的條件置為非,否則動畫會在Jump和Walk之間來回切換

在下一幀才播放shoot動畫,但子彈卻在這一幀出現,有點違和

解決方法:將子彈出現的位置延后 並且將渲染關掉,當子彈的X軸位置大於人物X軸位置+1時,開啟渲染

當蹲下射擊的時候子彈的位置為player的位置(player的位置比bulletLeftRight靠下一點,剛好滿足下蹲發射降低高度的需求)

void FixedUpdate()
    {
        if (!GameControl.instance.isGameOver)
        {
            x = Input.GetAxis("Horizontal");
            y = Input.GetAxis("Vertical");
            absx = Mathf.Abs(x);

            ground = Physics2D.Linecast(hitlinestart.position, hitlineend.position, 1 << this.gameObject.layer);

            //通過獲取按鍵的數值,改變對象Y軸的旋轉,除去0 是為了讓player保持之前一個方向
            if (x > 0 && ground)
                transform.eulerAngles = new Vector3(0, 180, 0);
            else if (x < 0 && ground)
                transform.eulerAngles = Vector3.zero;


            playerDir = transform.eulerAngles.y == 0 ? -1 : 1;//判斷人物方向有沒有改變,取得子彈的方向

            GetComponent<Rigidbody2D>().velocity = new Vector2(x * xspeed, GetComponent<Rigidbody2D>().velocity.y);//Y軸的速度不能為0,不然跳不起來

            GetComponent<Animator>().SetFloat("DirY", y);//Y軸的在空中或地上都要判斷,而X軸的移動只能在地上才能取得

            if (ground)//只有在地上的時候才能播放walk動畫
            {
                GetComponent<Animator>().SetFloat("DirX", absx);
                //GetComponent<Animator>().SetFloat("DirY", y);
                GetComponent<Animator>().SetBool("Jump", false);

                if (Input.GetKeyDown(KeyCode.K))//按了空格且在地上
                {
                    GetComponent<Rigidbody2D>().AddForce(new Vector2(0, yspeed));
                    GetComponent<Animator>().SetBool("Jump", true);
                    GetComponent<Animator>().SetFloat("DirX", 0);//跳躍的時候要將Walk的條件置為非,否則動畫會在Jump和Walk之間來回切換
                }
            }


            if (Input.GetKeyDown(KeyCode.J) && ground)//播放射擊動畫的邏輯
            {
                GetComponent<Animator>().SetBool("Shoot", true); //在下一幀才播放shoot動畫,但子彈卻在這一幀出現,有點違和
                //解決方法:將子彈出現的位置延后  ,並且將渲染關掉,當子彈的X軸位置大於人物X軸位置+1時,開啟渲染

                bullets[bulletIndex].GetComponent<SpriteRenderer>().enabled = false;


                bullets[bulletIndex].transform.position = bulletLeftRight.position; //子彈的出現位置
                bullets[bulletIndex].transform.rotation = transform.rotation;//子彈的旋轉跟人物的旋轉一致
                bullets[bulletIndex].GetComponent<Rigidbody2D>().velocity = new Vector2(playerDir * bulletSpeed, 0);//默認子彈的朝向跟人物一致,Y軸速度為0

                if (Input.GetKey(KeyCode.W)) //按住上的同時按下J,向上射擊
                {
                    bullets[bulletIndex].transform.position = transform.position + Vector3.up + playerDir * Vector3.right;//修改子彈出現的位置
                    bullets[bulletIndex].transform.eulerAngles = new Vector3(0, 0, -90f);//旋轉子彈的角度
                    bullets[bulletIndex].GetComponent<Rigidbody2D>().velocity = new Vector2(0, bulletSpeed);//給子彈一個向上的速度
                }
                else if (Input.GetKey(KeyCode.S)) //按住下的同時按下J,蹲下射擊
                {
                    bullets[bulletIndex].transform.position = transform.position;//子彈的位置為player的位置(player的位置比bulletLeftRight靠下一點,剛好滿足下蹲發射降低高度的需求)
                }


                bulletIndex++;
                bulletIndex %= bullets.Length;
            }
            else if (!ground && Input.GetKeyDown(KeyCode.J) && Input.GetKey(KeyCode.W))//禁止玩家在空中左右射擊
            {
                GetComponent<Animator>().SetBool("Shoot", true); //在下一幀才播放shoot動畫,但子彈卻在這一幀出現,有點違和
                //解決方法:將子彈出現的位置延后,並且將渲染關掉,當子彈的X軸位置大於人物X軸位置+1時,開啟渲染

                bullets[bulletIndex].GetComponent<SpriteRenderer>().enabled = false;

                bullets[bulletIndex].transform.position = transform.position + Vector3.up + playerDir * Vector3.right;//修改子彈出現的位置
                bullets[bulletIndex].transform.eulerAngles = new Vector3(0, 0, -90f);//旋轉子彈的角度
                bullets[bulletIndex].GetComponent<Rigidbody2D>().velocity = new Vector2(0, bulletSpeed);//給子彈一個向上的速度

                bulletIndex++;
                bulletIndex %= bullets.Length;
            }
            //將射擊動畫改為idel動畫的條件,是子彈的位置跟人物位置距離超過5
            if (bulletIndex >= 1)
            {
                if (Mathf.Abs(bullets[bulletIndex - 1].transform.position.x - transform.position.x) > 2)
                    GetComponent<Animator>().SetBool("Shoot", false);
            }
            else
            {
                if (Mathf.Abs(bullets[bullets.Length - 1].transform.position.x - transform.position.x) > 2)
                    GetComponent<Animator>().SetBool("Shoot", false);
            }
        }
       

    }

Car的制作

  1. 將圖片按照順序進行拼接
  2. 將拼接好的車子放到一個空節點,給這個空節點一個剛體用於給它速度
    image
    image

GameOver和Win的顯示

  1. 添加兩個Text的UI組件,Text的內容分別為GameOver和You Win
  2. 在玩家死亡或者勝利的時候enable對應的Text
    image
    image

攝像機移動的腳本實現

  1. 將攝像機的X軸控制在它自身到35之內,並隨着玩家位置改變(保證攝像機不能往回走)
 camerax = Mathf.Clamp(player.transform.position.x, camerax > 0 ? camerax : 0, 35.5f*level);

 playerx = Mathf.Clamp(player.transform.position.x, camerax - 8f, camerax + 8f);//將玩家位置控制在攝像機范圍之內(保證玩家不能往回走)

 player.transform.position = new Vector3(playerx, player.transform.position.y, player.transform.position.z);

 mainCamera.transform.position = new Vector3(camerax, mainCamera.transform.position.y, -10);

開場動畫的實現

  1. 通過時間來控制Car的移動和停止
  2. 通過MovePosition來讓玩家有一個從車上跳出的效果,且在站定之后轉向
    private void JumpOutOfCar()//開場動畫
    {
        if (car.position.x >= -0.01)
        {
            player.SetActive(true);
            time += Time.fixedDeltaTime;
            if (time < 0.4f)
            {
                player.GetComponent<Rigidbody2D>().MovePosition(Vector2.MoveTowards(player.transform.position, new Vector2(-3f, 0f), 3.5f * Time.fixedDeltaTime));//人物跳起移動
            }
            else if (time > 0.4f && time < 1f)
            {
                player.GetComponent<Rigidbody2D>().MovePosition(Vector2.MoveTowards(player.transform.position, new Vector2(-4f, -1.65f), 3.5f * Time.fixedDeltaTime));//人物下落移動
            }
            else if (time > 1.5f)
            {
                player.transform.rotation = new Quaternion(0, 180, 0, 0);//人物轉向
            }
        }

    }

敵機追蹤玩家的腳本實現

  1. 判斷玩家的位置是在Jet的左邊還是右邊,且向玩家位置移動
  2. 當與玩家位置小於0.5則扔炸彈
  3. 若血量為0 ,則在播放完成爆炸后銷毀Jet
    void FixedUpdate()
    {
        trax = Mathf.Clamp(transform.position.x,29f,42f);
        transform.position = new Vector3(trax, transform.position.y, 0);

        if (GameControl.instance.mainCamera.transform.position.x > 35)//攝像機的位置控制直升機的出現
            GetComponent<SpriteRenderer>().enabled = true;
        if(GetComponent<SpriteRenderer>().enabled == true&&hp>0)
        {
            if(transform.position.x > GameControl.instance.player.transform.position.x+0.5)
            {
                transform.eulerAngles = new Vector3(0, 0, 0);
                GetComponent<Rigidbody2D>().velocity = 2*Vector2.left;
            }
            else if(transform.position.x < GameControl.instance.player.transform.position.x-0.5)
            {
                transform.eulerAngles = new Vector3(0, 180, 0);
                GetComponent<Rigidbody2D>().velocity = 2 * Vector2.right;
            }
            else
            {
                GetComponent<Rigidbody2D>().velocity = Vector2.zero;
                if(!boomAlive)
                {
                    Instantiate(jetBullet, transform.position + Vector3.down, Quaternion.identity);
                    boomAlive = true;
                }
            }
        }
        else
            GetComponent<Rigidbody2D>().velocity = Vector2.zero;

        if (hp == 0)
        {
            GetComponent<Animator>().SetBool("Explosion", true);
            Invoke("DestroyThis", 3f);
            Invoke("SetGameWin",3f);
        }


    }

Older給禮物和被釋放的腳本實現

  1. 老人被釋放后如果不持續施加速度,那么速度會因為摩擦力而衰減,最后導致速度為0
  2. 在沒被釋放之前,把older的碰撞器改為觸發器,使玩家可以穿過older
  3. 在沒被釋放之前,玩家可以穿過older,玩家離開碰撞器后還把該碰撞器改回去
    void FixedUpdate()
    {
        if(isRelease)
        {
           
            time += Time.fixedDeltaTime;
            if (time >= 1f && time <=6f&&!isGiving)
            {
                GetComponent<Animator>().SetBool("run", true);
                GetComponent<Rigidbody2D>().velocity = new Vector2(-4f, GetComponent<Rigidbody2D>().velocity.y);
            }
            
            else if (time > 6)
                Destroy(this.gameObject);
        }
    }

    public void OnTriggerEnter2D(Collider2D collision)
    {
        if (collision.gameObject.tag == "Bullet")
        {
            isRelease = true;
            GetComponent<Rigidbody2D>().bodyType = RigidbodyType2D.Dynamic;
            GetComponent<Animator>().SetBool("release", true);
        }
        if (collision.gameObject.tag == "Player" && !isGift&&isRelease)
        {
            isGift = true;//防止多次給禮物
            isGiving = true;//防止給禮物時還在移動
            GetComponent<Rigidbody2D>().velocity = Vector2.zero;
            GetComponent<Rigidbody2D>().bodyType = RigidbodyType2D.Kinematic;
            collision.gameObject.GetComponent<Rigidbody2D>().bodyType = RigidbodyType2D.Kinematic;
            GetComponent<Animator>().SetBool("give", true);

            Invoke("GiveOver", 1f);
        }
        else if (collision.gameObject.tag == "Player"&& !isRelease)
        {//
            GetComponent<BoxCollider2D>().isTrigger = true;
        }
    }
    public void OnTriggerExit2D(Collider2D collision)
    {

        if (collision.gameObject.tag == "Player")
        {
            if (isRelease)
            {
                GetComponent<Rigidbody2D>().bodyType = RigidbodyType2D.Dynamic;
                collision.gameObject.GetComponent<Rigidbody2D>().bodyType = RigidbodyType2D.Dynamic;
            }
            else
            {//
                GetComponent<BoxCollider2D>().isTrigger = false ;
            }
            
            
        }
    }

    private void GiveOver()
    {
        isGiving = false;
        GetComponent<Animator>().SetBool("give", false);
       
        Instantiate(gift, transform.position + Vector3.right, Quaternion.identity);
    }


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM