Unity makes angry birds


Reference Video: [SiKi Academy Unity] Unity Elementary Case - Angry Birds



1. Project preparation

Resource download: http://www.sikiedu.com/course/134

New Construction:

insert image description here

Select 2D, fill in the project name and select the project path:
insert image description here


ImageCopy the and from the resources Musicinto the project folder:

insert image description here
insert image description here



Two, slice

Select the first chapter picture of pigs and birds, change it Sprite Modeto Multipleand Apply:
insert image description here


Slice as shown below:
insert image description here


It is found that the smoke from the four explosions has not been segmented well, so manually segment it:
insert image description here


Apply:
insert image description here


Drag the slingshot and bird into the scene, and set the hierarchical relationship:
insert image description here



3. Realize the dragging and flying of the bird


1. Add and set Spring Joint 2D

Add Spring Joint 2Da component for the bird, and the rigid body component will be added automatically after adding:
insert image description here


At the same time, add a rigid body component to the right part of the slingshot and set it as Static(to prevent it from being affected by gravity):
insert image description here


Drag the rigid body on the right side of the slingshot Spring Joint 2Dto , and set Spring Joint 2Dthe parameters:
insert image description here


2. Implement the movement of the bird following the mouse

Add colliders and Birdscripts:
insert image description here


bird.cs:

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

public class Bird : MonoBehaviour
{
    
    
    private bool isClick = false;


    private void Update()
    {
    
    
        MoveWithMouse();
    }

    private void MoveWithMouse()
    {
    
    
        // 让小鸟跟随鼠标的位置
        if (isClick)
        {
    
    
            transform.position = Camera.main.ScreenToWorldPoint(Input.mousePosition);
            transform.position += new Vector3(0, 0, -Camera.main.transform.position.z);
        }
    }

    // 鼠标按下
    private void OnMouseDown()
    {
    
    
        isClick = true;   
    }

    // 鼠标抬起
    private void OnMouseUp()
    {
    
    
        isClick = false;
    }

}

At this time, when the bird is dragged by the mouse, it will move with the mouse.


3. Limit the maximum dragging distance of the bird


First set a point on the right side of the slingshot as the point around which the bird turns:
insert image description here


Bird.csDeclare the rightPos and maxDis variables in :

    public Transform rightPos;   // 弹弓右部点,即拖拽小鸟时让其跟着转
    public float maxDis;  // 最大推拽距离

Modify MoveWithMouse()as follows:

    private void MoveWithMouse()
    {
    
    
        // 让小鸟跟随鼠标的位置
        if (isClick)
        {
    
    
            transform.position = Camera.main.ScreenToWorldPoint(Input.mousePosition);
            transform.position += new Vector3(0, 0, -Camera.main.transform.position.z);

            // 限定小鸟最大拖拽距离
            if (Vector2.Distance(transform.position, rightPos.position) >= maxDis)
            {
    
    
                transform.position = rightPos.position + (transform.position - rightPos.position).normalized * maxDis;
            }
        }
    }

Drag it into the script in Inspectorthe panel and set it . At this time, the bird is limited to the dragging distance:rightPosbirdmaxDis
insert image description here


4. Realize the bird flying out

On mouse down, the rigid body state is set to dynamic.
On mouseup, dynamics is set to false, and SpringJoint2Dthe component is disabled after a certain amount of time:

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

public class Bird : MonoBehaviour
{
    
    
    private SpringJoint2D springJoint;
    private Rigidbody2D rb;

    public Transform rightPos;   // 弹弓右部点,即拖拽小鸟时让其跟着转
    public float maxDis;  // 最大推拽距离


    private bool isClick = false;


    private void Start()
    {
    
    
        springJoint = GetComponent<SpringJoint2D>();
        rb = GetComponent<Rigidbody2D>();
    }

    private void Update()
    {
    
    
        MoveWithMouse();
    }

    private void MoveWithMouse()
    {
    
    
        // 让小鸟跟随鼠标的位置
        if (isClick)
        {
    
    
            transform.position = Camera.main.ScreenToWorldPoint(Input.mousePosition);
            transform.position += new Vector3(0, 0, -Camera.main.transform.position.z);

            // 限定小鸟最大拖拽距离
            if (Vector2.Distance(transform.position, rightPos.position) >= maxDis)
            {
    
    
                transform.position = rightPos.position + (transform.position - rightPos.position).normalized * maxDis;
            }
        }
    }

    // 鼠标按下
    private void OnMouseDown()
    {
    
    
        isClick = true;
        rb.isKinematic = true;
    }

    // 鼠标抬起
    private void OnMouseUp()
    {
    
    
        isClick = false;
        rb.isKinematic = false;
        Invoke(nameof(Fly), 0.12f);
    }

    private void Fly()
    {
    
    
        springJoint.enabled = false;
    }

}


5. Realize the scribing of the slingshot


Create a point on the slingshot leftPos, at this point leftPosand rightPostwo points to draw the line:
insert image description here


To leftadd Line Renderercomponents:
insert image description here


Set material, color and length:
insert image description here


Copy that component over right:
insert image description here
insert image description here


Write code:
bird.cs:

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

public class Bird : MonoBehaviour
{
    
    
    private SpringJoint2D springJoint;
    private Rigidbody2D rb;

    [Header("弹弓")]
    public Transform rightPos;   // 弹弓右部点,即拖拽小鸟时让其跟着转; 同时画线
    public Transform leftPos;    // 弹弓左部点, 画线
    public LineRenderer leftLine;
    public LineRenderer rightLine;

    [Space]
    public float maxDis;  // 最大推拽距离


    private bool isClick = false;


    private void Start()
    {
    
    
        springJoint = GetComponent<SpringJoint2D>();
        rb = GetComponent<Rigidbody2D>();
    }

    private void Update()
    {
    
    
        MoveWithMouse();
    }

    private void MoveWithMouse()
    {
    
    
        // 让小鸟跟随鼠标的位置
        if (isClick)
        {
    
    
            transform.position = Camera.main.ScreenToWorldPoint(Input.mousePosition);
            transform.position += new Vector3(0, 0, -Camera.main.transform.position.z);

            // 限定小鸟最大拖拽距离
            if (Vector2.Distance(transform.position, rightPos.position) >= maxDis)
            {
    
    
                transform.position = rightPos.position + (transform.position - rightPos.position).normalized * maxDis;
            }

            DrawLine();
        }
    }

    // 鼠标按下
    private void OnMouseDown()
    {
    
    
        isClick = true;
        rb.isKinematic = true;
    }

    // 鼠标抬起
    private void OnMouseUp()
    {
    
    
        isClick = false;
        rb.isKinematic = false;
        DeleteLine();  // 删除弹弓的线
        Invoke(nameof(Fly), 0.12f);
    }

    // 飞出
    private void Fly()
    {
    
    
        springJoint.enabled = false;
    }

    // 画线
    private void DrawLine()
    {
    
    
        // 设置线的两个端点
        leftLine.SetPosition(0, leftPos.position);
        leftLine.SetPosition(1, transform.position);

        rightLine.SetPosition(0, rightPos.position);
        rightLine.SetPosition(1, transform.position);
    }

    // 删除线
    private void DeleteLine()
    {
    
    
        leftLine.SetPosition(1, leftPos.position);
        rightLine.SetPosition(1, rightPos.position);
    }
}

At this time, when dragging the bird, the line can be drawn normally, and the line will disappear when the bird is released.


6. Prevent the bird from dragging repeatedly


At this time, after the bird is dragged and released, press and hold the bird again to return to the slingshot.

To fix this bug, add a bool parameter to the bird:

    private bool flied = false;  // 是否飞过,用以让小鸟不能重复拖拽

After the mouse is lifted, set it to true:

    // 鼠标抬起
    private void OnMouseUp()
    {
    
    
        isClick = false;
        flied = true;
        rb.isKinematic = false;
        DeleteLine();  // 删除弹弓的线
        Invoke(nameof(Fly), 0.12f);
    }

After the mouse is pressed, if it fliedis already true, it has no effect:

    // 鼠标按下
    private void OnMouseDown()
    {
    
    
        if (flied)
            return;
        isClick = true;
        rb.isKinematic = true;
    }

At this point the bird can only be dragged once.



4. Scene construction


Select scene 1 for cutting:
insert image description here


Drag the ground in and add a collider:
insert image description here


Create prefab-related folders and drag them into:
insert image description here


Set the ground:
insert image description here


Similarly, set the sky:
insert image description here



5. Realize the bird attack pig


Add pig, and add related components and set layers:
insert image description here


Set the corner resistance of both the bird and the pig to 2 to prevent them from rolling on the ground without stopping:
insert image description here


1. Injuries and deaths of pigs


Add Pigscript to pig:
insert image description here


Set the relative speed at which the pig should be injured and killed when it is hit by a bird:

    public float hurtSpeed = 5.0f;  // 受伤速度
    public float deadSpeed = 10.0f;  // 死亡速度

Set the picture after the pig is injured:

    // 受伤图片
    public Sprite hurtSprite;

insert image description here


Drag the picture of the corresponding smoke into the scene:
insert image description here

Create booman animation:
insert image description here


Open Animationand adjust accordingly:
insert image description here


At the same time cancel the loop of the animation:
insert image description here


BoomAdd a script for Boom:
insert image description here


Write the code:
Boom.cs:

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

public class Boom : MonoBehaviour
{
    
    
    public void DestorySelf()
    {
    
    
        Destroy(gameObject);
    }
}

Set in Animation, execute this function after playing, that is, destroy itself:
insert image description here

Make Booman object into a prefab:
insert image description here


Pig death logic:

If the relative speed is greater than the death speed: it will die;
if the relative speed is only greater than the injury speed: if the pig is injured at this time, it will die; otherwise, it will be injured

In Pig.cs, realize the injury and death of pigs:

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

public class Pig : MonoBehaviour
{
    
    
    private SpriteRenderer spriteRenderer;

    // 受伤图片
    public Sprite hurtSprite;
    public GameObject boomPrefab;

    [Header("相对速度")]
    public float hurtSpeed = 5.0f;  // 受伤速度
    public float deadSpeed = 10.0f;  // 死亡速度

    private bool isHurt = false;

    private void Start()
    {
    
    
        spriteRenderer = GetComponent<SpriteRenderer>();
    }

    private void OnCollisionEnter2D(Collision2D collision)
    {
    
    
        float relativeV = collision.relativeVelocity.magnitude;
        print(relativeV);
        // 大于死亡速度
        if (relativeV >= deadSpeed)
        {
    
    
            Dead();
        }
        // 大于受伤速度
        else if (relativeV >= hurtSpeed)
        {
    
    
            if (isHurt)
                Dead();
            else
            {
    
    
                isHurt = true;
                spriteRenderer.sprite = hurtSprite;
            }
        }
    }

    // 死亡,生成爆炸动画和分数
    private void Dead()
    {
    
    
        Instantiate(boomPrefab, transform.position, Quaternion.identity);
        Destroy(gameObject);
    }

}

2. Bonus points for pigs

Cut fractional image:
insert image description here


Drag out a score and make it into a prefab:
insert image description here


Write pig.csthe code:

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

public class Pig : MonoBehaviour
{
    
    
    private SpriteRenderer spriteRenderer;

    // 受伤图片
    public Sprite hurtSprite;
    public GameObject boomPrefab;
    public GameObject scorePrefab;

    [Header("相对速度")]
    public float hurtSpeed = 5.0f;  // 受伤速度
    public float deadSpeed = 10.0f;  // 死亡速度

    private bool isHurt = false;

    [Space]
    public float scoreYOffset = 0.65f;  // 分数相对猪的Y位置

    private void Start()
    {
    
    
        spriteRenderer = GetComponent<SpriteRenderer>();
    }

    private void OnCollisionEnter2D(Collision2D collision)
    {
    
    
        float relativeV = collision.relativeVelocity.magnitude;
        print(relativeV);
        // 大于死亡速度
        if (relativeV >= deadSpeed)
        {
    
    
            Dead();
        }
        // 大于受伤速度
        else if (relativeV >= hurtSpeed)
        {
    
    
            if (isHurt)
                Dead();
            else
            {
    
    
                isHurt = true;
                spriteRenderer.sprite = hurtSprite;
            }
        }
    }

    // 死亡,生成爆炸动画和分数
    private void Dead()
    {
    
    
        GameManager.instance.pigs.Remove(this);
        Instantiate(boomPrefab, transform.position, Quaternion.identity);
        GameObject scoreObject = Instantiate(scorePrefab, transform.position + new Vector3(0, scoreYOffset, 0),
            Quaternion.identity);
        Destroy(scoreObject, 1.5f);
        Destroy(gameObject);
    }

}


6. Realize the control of multiple birds

Make the bird as a prefab and make two copies:

insert image description here


Create an Game Managerempty object, create a new one and hang GameManagerthe script:
insert image description here

Use the singleton pattern and store the birds and pigs in lists:

public class GameManager : MonoBehaviour
{
    
    
    public static GameManager instance;

    public List<Bird> birds;
    public List<Pig> pigs;


    private void Awake()
    {
    
    
        instance = this;
    }

}

Write in Bird, let the bird fly out for a few seconds and destroy it, generate an explosion animation, and GameManagerremove it from the list:


    private bool isClick = false;
    private bool flied = false;  // 是否飞过,用以让小鸟不能重复拖拽

    // 飞出
    private void Fly()
    {
    
    
        springJoint.enabled = false;
        Invoke(nameof(DestroySelf), flyTime);
    }
    
    // 飞出5秒后销毁
    private void DestroySelf()
    {
    
    
        GameManager.instance.birds.Remove(this);
        Instantiate(boomPrefab, transform.position, Quaternion.identity);
        Destroy(gameObject);
    }

Similarly, when the pig dies, GameMangerit also needs to be deleted from the list:

    // 死亡,生成爆炸动画和分数
    private void Dead()
    {
    
    
        GameManager.instance.pigs.Remove(this);
        Instantiate(boomPrefab, transform.position, Quaternion.identity);
        GameObject scoreObject = Instantiate(scorePrefab, transform.position + new Vector3(0, scoreYOffset, 0),
            Quaternion.identity);
        Destroy(scoreObject, 1.5f);
        Destroy(gameObject);
    }

In GameManager, initially enable the first bird, disable other bird scripts and SpringJoint, and judge the game state after the bird is destroyed and whether to enable the next bird:
GameManager.cs:

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

public class GameManager : MonoBehaviour
{
    
    
    public static GameManager instance;

    public List<Bird> birds;
    public List<Pig> pigs;

    private Vector3 originBirdPos;  // 小鸟初始位置

    private void Awake()
    {
    
    
        instance = this;
        if (birds.Count > 0)
            originBirdPos = birds[0].transform.position;
        InitBird();
    }

    // 初始化小鸟
    private void InitBird()
    {
    
    
        for(int i = 0; i <birds.Count; i++)
        {
    
    
            if (i == 0)
            {
    
    
                birds[i].transform.position = originBirdPos;
                birds[i].enabled = true;
                birds[i].GetComponent<SpringJoint2D>().enabled = true;
            }
            else
            {
    
    
                birds[i].enabled = false;
                birds[i].GetComponent<SpringJoint2D>().enabled = false;
            }
        }
    }

    // 判断游戏状态 及 是否启用下一只小鸟
    public void Next()
    {
    
    
        if (pigs.Count == 0)
        {
    
    
            // 游戏胜利
        }
        else
        {
    
    
            if (birds.Count == 0)
            {
    
    
                // 游戏失败
            }
            else
            {
    
    
                InitBird();
            }
        }
    }

}

After the bird is destroyed, call `Next()`: `bird.cs`:
    // 飞出5秒后销毁
    private void DestroySelf()
    {
    
    
        GameManager.instance.birds.Remove(this);
        GameManager.instance.Next();
        Instantiate(boomPrefab, transform.position, Quaternion.identity);
        Destroy(gameObject);
    }

Finally, Inspectorafter dragging the birds and pigs in the panel, multiple birds can be controlled normally.



7. Implementation of bird trails

Import the Unity package in the material:
insert image description here

insert image description here

Just add Weapon Trail:
insert image description here


Add Trail Renderercomponents to the bird:
insert image description here


Set the trailing material, duration and width:
insert image description here


Simultaneously load on other prefabs:
insert image description here


Trailing effect:
Please add a picture description



8. Build houses for pigs


cutting:
insert image description here


Take square wood as an example:
insert image description here


Add bool's isPig to Pig.csthe script so that wooden blocks can also be used:

    [Space]
    public bool isPig = false;
    
    // 死亡,生成爆炸动画和分数
    private void Dead()
    {
    
    
        if (isPig)
            GameManager.instance.pigs.Remove(this);
        Instantiate(boomPrefab, transform.position, Quaternion.identity);
        GameObject scoreObject = Instantiate(scorePrefab, transform.position + new Vector3(0, scoreYOffset, 0),
            Quaternion.identity);
        Destroy(scoreObject, 1.5f);
        Destroy(gameObject);
    }

Check the previous pigs isPig:
insert image description here


Mount the script on the wood without checking it isPig, and then set parameters such as hurtSpeed:
insert image description here

Wood needs components: Rigidbody, Collider, Pig script


Similarly, add other items.

A simple scenario to set up is as follows:
insert image description here


running result:
Please add a picture description



9. Game victory and failure interface


1. Display the basic interface of victory and defeat


cutting:

insert image description here


Make UI (refer to Chapter 15 ).

Lose UI:
Please add a picture description


Win UI:
Please add a picture description


When the game wins, judge the number of stars that should be obtained according to the number of remaining birds in the level. GameManager.csPart of the code is as follows:

    [Header("UI")]
    public GameObject winUI;
    public GameObject loseUI;

    [Header("胜利得到星星的数量需要的小鸟存活数")]
    public int birdNumOf3Star;
    public int birdNumOf2Star;

    // 判断游戏状态 及 是否启用下一只小鸟
    public void Next()
    {
    
    
        if (pigs.Count == 0)
        {
    
    
            // 游戏胜利
            winUI.SetActive(true);
        }
        else
        {
    
    
            if (birds.Count == 0)
            {
    
    
                // 游戏失败
                loseUI.SetActive(true);
            }
            else
            {
    
    
                InitBird();
            }
        }
    }

    public void WinLevel()
    {
    
    
        if (birds.Count >= birdNumOf3Star)  // 3颗星星
        {
    
    

        }
        else if (birds.Count >= birdNumOf2Star) // 2颗
        {
    
    

        }
        else // 1颗
        {
    
    

        }
    }

Meanwhile, for a script Win UIthat creates one Win.cs:

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

public class Win : MonoBehaviour
{
    
    
    // 动画播放完(显示UI后) 显示星星
    public void ShowStar()
    {
    
    
        GameManager.instance.WinLevel();
    }
}

Called after the animation ends:
insert image description here


2. Star particle effect


Cutting stars:
insert image description here


Placement of three stars:
insert image description here


Set the particle effect of the stars according to episodes 16 to 18 of https://www.bilibili.com/video/BV1qb411c76x?p=16 .


3. Star display


In GameManager.cs, use the coroutine to display a star every 0.7s:

    public GameObject[] starsUI = new GameObject[3];
    
    public void WinLevel()
    {
    
    
        if (birds.Count >= birdNumOf3Star)  // 3颗星星
        {
    
    
            StartCoroutine("ShowTheStar", 3);
        }
        else if (birds.Count >= birdNumOf2Star) // 2颗
        {
    
    
            StartCoroutine("ShowTheStar", 2);
        }
        else // 1颗
        {
    
    
            StartCoroutine("ShowTheStar", 1);
        }
    }

    // 每隔0.7秒,显示一颗星星
    IEnumerator ShowTheStar(int num)
    {
    
    
        for(int i = 0; i < num; i++)
        {
    
    
            starsUI[i].SetActive(true);
            yield return new WaitForSeconds(0.7f);
        }
    }

InsepctorDrag stars into the panel :
insert image description here


At this time, the stars are displayed normally:

Please add a picture description




10. Pause interface


1. Interface and animation

P20

Pause button:

insert image description here


Pause panel:

insert image description here


Implement pause animation:

insert image description here

Implement the continuation animation:

insert image description here


Both animations are unlooped:

insert image description here


2. Implement pause and resume


AnimatorCreate two parameters in Triggerand connect the two animations:

insert image description here


The connection between Pause animation and Resume:

insert image description here

insert image description here


Create PausePanlea script and put Pause Panel:

insert image description here

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

public class PausePanel : MonoBehaviour
{
    
    
    private Animator anim;

    // Start is called before the first frame update
    void Start()
    {
    
    
        anim = GetComponent<Animator>();
    }


    // 点击继续按钮
    public void Resume()
    {
    
    
        anim.SetTrigger("resume");
    }

    // 继续动画结束后,调用
    public void AfterResume()
    {
    
    
        this.gameObject.SetActive(false);
        anim.SetTrigger("pause");  // 切换回暂停动画,下次active true时则调用暂停动画
    }

}

GameManager.csAdd code in:

    [Space]
    public GameObject pausePanel;

    // 暂停按钮调用函数
    public void PauseGame()
    {
    
    
        pausePanel.SetActive(true);
    }

In Inspectorthe panel, drag in Pause Panel:

insert image description here


To Pause Btnadd a click event, for GameManagerthe pause method:

insert image description here


To Resume Btnadd a click event, for Pause Panelthe Pausemethod:

insert image description here


At Resumethe end of the animation, call AfterResumethe function:

insert image description here


Effect:

Please add a picture description


3. Implement Restart Level


Add the restart level method in GameManager.cs:

using UnityEngine.SceneManagement;

    // 重启关卡
    public void RestartLevel()
    {
    
    
        SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex);
    }

Called in each restart button:
insert image description here
insert image description here
insert image description here


running result:
Please add a picture description



11. Camera follow


1. Follow the first bird

open Package Manager:
insert image description here


download Cinemachine:
insert image description here


Add a 2D Camera:
insert image description here


Drag in the first bird Followand let the camera follow the bird:
insert image description here


Adjust some parameters to choose a suitable position:
insert image description here


At the same time, create an Camera BGempty object named, add Polygona collision body to it, check it Is Trigger, and use it as the range of the camera (that is, if the bird exceeds this range, the camera will not follow):
insert image description here


In just now CM vcam1, add CinemachineConfiner:
insert image description here


Just Camera BGdrag in:
insert image description here


2. Follow multiple birds in sequence

Introduced in GameManager:

using Cinemachine;

If an error is reported, import Cinemachinethe sample program scene:
insert image description here


GameManager.csChanged code:

using Cinemachine;

    [Header("相机和弹弓")]
    public CinemachineVirtualCamera virtualCamera;
    public Transform slingshotLeftPos;    // 弹弓左部点,用于小鸟死后视角回到弹弓

    // 初始化小鸟
    private void InitBird()
    {
    
    
        for(int i = 0; i <birds.Count; i++)
        {
    
    
            if (i == 0)
            {
    
    
                birds[i].transform.position = originBirdPos;
                birds[i].enabled = true;
                birds[i].GetComponent<SpringJoint2D>().enabled = true;
                virtualCamera.Follow = birds[i].transform;  // 相机跟随小鸟
            }
            else
            {
    
    
                birds[i].enabled = false;
                birds[i].GetComponent<SpringJoint2D>().enabled = false;
            }
        }
    }
    
	// 判断游戏状态 及 是否启用下一只小鸟
    public void Next()
    {
    
    
        virtualCamera.Follow = slingshotLeftPos;
        virtualCamera.transform.position = slingshotLeftPos.position;

        if (pigs.Count == 0)
        {
    
    
            // 游戏胜利
            winUI.SetActive(true);
        }
        else
        {
    
    
            if (birds.Count == 0)
            {
    
    
                // 游戏失败
                loseUI.SetActive(true);
            }
            else
            {
    
    
                InitBird();
            }
        }
    }

The final demo effect:

Please add a picture description



reference

[SiKi Academy Unity] Unity Elementary Case - Angry Birds

Guess you like

Origin blog.csdn.net/weixin_46628481/article/details/122272140