How Create Angry Bird Style Game In Unity.

How Create Angry Bird Style Game In Unity.

Unity is a powerful and widely-used game development platform and engine known for its versatility, ease of use, and ability to create stunning interactive experiences across various platforms. With Unity, developers can build games, interactive applications, simulations, and more for a wide range of platforms, including mobile devices, consoles, desktops, and even virtual reality (VR) and augmented reality (AR) devices. Its cross-platform capabilities make it a popular choice for game developers, indie creators, and large studios alike.

"Angry Birds" is a popular mobile game franchise developed by Rovio Entertainment. The game was first released in December 2009 and quickly gained widespread popularity due to its simple yet addictive gameplay and charming characters.

In "Angry Birds" game, players use a slingshot to launch various types of birds at structures populated by pigs. The objective is to eliminate all the pigs on each level using as few birds as possible. Each bird has its unique abilities, such as splitting into multiple birds, accelerating in mid-air, or causing explosions. The structures are designed with physics-based mechanics, and players must strategically aim and time their shots to maximize damage and pig elimination.

Creating an "Angry Birds" style game in Unity involves several steps, including setting up the project, designing the gameplay mechanics, creating the art assets, implementing physics, and coding the mechanics. Here's a general overview of how you can start working on such a game:

To create a project in Unity you will need to have Unity and Unity Hub installed. You can download it from Unity's website. To complete the project, follow this tutorial from start to end.

1. Create Project:

First, we open the Unity Hub and Create a 2D Project.

Creation of project

2. Creating Scenes:

In our scene, there are several components arranged as follows:

  1. Background Sprites: Three background sprites are present, all assigned to the "Background" sorting layer. Each sprite has the ParallaxScrolling script attached, which produces a captivating parallax effect as the camera moves.
  2. Destroyers: These consist of basic quads acting as triggers, and they feature the Destroyer script. Positioned at the screen's left, top, and right boundaries, their role is to deactivate or eliminate objects that exit the scene. The Destroyer object is designed as a prefab, facilitating its usage in other scenes if desired.
  3. Birds: Three bird characters are included, set up as kinematic rigidbodies initially (before user interaction). They come with a circle collider, a trail renderer for a flight trail, and a "whoosh" sound effect upon launch. The Bird script is attached to control their behavior. The Smoke material used in the Trail Renderer is sourced from Unity Standard Assets' Particle package.
  4. GameManager: This is an empty GameObject hosting the GameManager script, which could also be linked to the Main Camera.
  5. Enemy Building: A GameObject encompasses building blocks and pig characters as children.
  6. Bricks: Bricks are tagged as such and equipped with a BoxCollider2D. They are rigidbodies and possess the Brick script for management. These individual brick units are created as prefabs to enhance reusability.
  7. Pigs: Each pig character features a Rigidbody, CircleCollider2D, distinctive sound, and the Pig Script/Code for functionality.
  8. Floor: Sprites constituting the ground are part of the Floor object. Edge colliders with the Floor Physics material prevent easy rolling for rigidbodies. The bounciness is zero, and each piece of ground is structured as a prefab. The edge collider's direction is indicated by a blue arrow.
  9. Slingshot: This object holds the slingshot sprites, essential transforms, and line renderers. Two line renderers depict the strings linking the slingshot and the waiting bird. Another line renderer projects the bird's trajectory when launched. Additional game objects on the left, right, and bird wait positions act as starting points.
  10. Camera: An orthographic camera with four scripts associated with it, which will be detailed later in the blog post.

3. Program the Game:

With the visual elements in position, the next step involves incorporating the script responsible for managing the animation.

Camera Follow Code:

The camera follow script tracks the motion of the thrown bird, ensuring the camera moves in accordance with it. This script also enforces a constraint on the camera's position, guaranteeing that the camera's X-coordinate remains within the scene's boundaries.

using UnityEngine;

public class CameraFollow : MonoBehaviour
{
    public Vector3 StartingPosition { get; private set; }
    
    private const float MinCameraX = 0;
    private const float MaxCameraX = 13;
    
    public bool IsFollowing { get; private set; }
    public Transform BirdToFollow { get; set; }

    void Start()
    {
        StartingPosition = transform.position;
    }

    void Update()
    {
        if (IsFollowing)
        {
            if (BirdToFollow != null)
            {
                Vector3 birdPosition = BirdToFollow.transform.position;
                float clampedX = Mathf.Clamp(birdPosition.x, MinCameraX, MaxCameraX);
                Vector3 newPosition = new Vector3(clampedX, StartingPosition.y, StartingPosition.z);
                transform.position = newPosition;
            }
            else
            {
                IsFollowing = false;
            }
        }
    }
}
        

Camera Movement Code:

The script for camera movement empowers users to slide their view across the screen through touch or mouse interactions while the bird remains in its dormant phase, ready for launching. This feature grants users the ability to observe the entire scene, strategizing their shot accordingly. The script consistently monitors mouse coordinates, facilitating seamless adjustments to the camera's positioning. To replicate an agile dragging sensation, a dragSpeed parameter is progressively integrated each frame. Both the horizontal (X) and vertical (Y) coordinates of the camera are confined within the scene's boundaries, preventing users from dragging the camera outside of these limits.

using UnityEngine;

public class CameraMove : MonoBehaviour
{
    private float dragSpeed = 0.01f;
    private float timeDragStarted;
    private Vector3 previousPosition = Vector3.zero;
    
    public SlingShot SlingShot;

    void Update()
    {
        if (SlingShot.slingshotState == SlingshotState.Idle && GameManager.CurrentGameState == GameState.Playing)
        {
            if (Input.GetMouseButtonDown(0))
            {
                timeDragStarted = Time.time;
                dragSpeed = 0f;
                previousPosition = Input.mousePosition;
            }
            else if (Input.GetMouseButton(0) && Time.time - timeDragStarted > 0.05f)
            {
                Vector3 input = Input.mousePosition;
                float deltaX = (previousPosition.x - input.x) * dragSpeed;
                float deltaY = (previousPosition.y - input.y) * dragSpeed;
                
                float newX = Mathf.Clamp(transform.position.x + deltaX, 0, 13.36336f);
                float newY = Mathf.Clamp(transform.position.y + deltaY, 0, 2.715f);
                
                transform.position = new Vector3(newX, newY, transform.position.z);
                previousPosition = input;
                
                if (dragSpeed < 0.1f) 
                {
                    dragSpeed += 0.002f;
                }
            }
        }
    }
}
        

Bird Code:

The Bird script begins by deactivating the bird's trail renderer to prevent its display before launch. Subsequently, it sets the bird as kinematic to avoid gravitational effects prior to takeoff. The collider's radius is augmented, and the initial state of the bird is established.

using UnityEngine;

public class Bird : MonoBehaviour
{
    void Start()
    {
        TrailRenderer trailRenderer = GetComponent<TrailRenderer>();
        trailRenderer.enabled = false;
        trailRenderer.sortingLayerName = "Foreground";

        Rigidbody2D rigidbody = GetComponent<Rigidbody2D>();
        rigidbody.isKinematic = true;

        CircleCollider2D collider = GetComponent<CircleCollider2D>();
        collider.radius = Constants.BirdColliderRadiusBig;

        State = BirdState.BeforeThrown;
    }
}        

Within the FixedUpdate, we evaluate whether the bird's velocity has reached a minimal value and if the bird was launched from the slingshot. This scenario indicates the completion of its descent and signifies its stationary state. Subsequently, we initiate the removal of the bird after a brief delay of 2 seconds.

void FixedUpdate()
{
    // Check if the bird has been thrown and its speed is extremely low
    if (State == BirdState.Thrown &&
        GetComponent<Rigidbody2D>().velocity.sqrMagnitude <= Constants.MinVelocity)
    {
        // Initiate bird destruction after 2 seconds
        StartCoroutine(DestroyAfter(2));
    }
}        

The DestroyAfter coroutine;

IEnumerator DestroyAfter(float seconds)
{
    yield return new WaitForSeconds(seconds);
    Destroy(gameObject);
}        

Furthermore, an OnThrow method is present (invoked by the bird launched script), serving to alter the bird's state. In this process, the bird transitions to a non-kinematic state, its collider radius is reduced, and the trail renderer is enabled.

public void OnThrow()
{
    GetComponent<AudioSource>().Play();

    GetComponent<TrailRenderer>().enabled = true;

    GetComponent<Rigidbody2D>().isKinematic = false;

    GetComponent<CircleCollider2D>().radius = Constants.BirdColliderRadiusNormal;

    State = BirdState.Thrown;
}        

Brick Code:

The brick script is responsible for monitoring collisions. It features a "health" variable that diminishes based on the velocity of the colliding object. Should the health value fall beneath zero, the brick is subsequently eliminated.

using UnityEngine;

public class Brick : MonoBehaviour
{
    public float Health = 70f;

    void OnCollisionEnter2D(Collision2D collision)
    {
        Rigidbody2D collisionRigidbody = collision.gameObject.GetComponent<Rigidbody2D>();
        
        if (collisionRigidbody == null)
        {
            return;
        }

        float damage = collisionRigidbody.velocity.magnitude * 10;

        if (damage >= 10)
        {
            GetComponent<AudioSource>().Play();
        }

        Health -= damage;

        if (Health <= 0)
        {
            Destroy(gameObject);
        }
    }
}        

Pig Code:

The Pig script examines collisions, when a bird collides with the pig, the pig is promptly eliminated. In the event of a collision with another object, like another pig or a brick, the script computes the inflicted damage. If the damage remains under a specified threshold, the pig's appearance is altered to display the version with blackened eyes. Similarly, should the health descend below zero, the pig is eradicated.

using UnityEngine;

public class Pig : MonoBehaviour
{
    public float Health = 150f;
    public Sprite SpriteShownWhenHurt;
    private float ChangeSpriteHealth;

    void Start()
    {
        ChangeSpriteHealth = Health - 30f;
    }

    void OnCollisionEnter2D(Collision2D collision)
    {
        Rigidbody2D collisionRigidbody = collision.gameObject.GetComponent<Rigidbody2D>();

        if (collisionRigidbody == null)
        {
            return;
        }

        if (collision.gameObject.CompareTag("Bird"))
        {
            GetComponent<AudioSource>().Play();
            Destroy(gameObject);
        }
        else
        {
            float damage = collisionRigidbody.velocity.magnitude * 10;
            Health -= damage;

            if (damage >= 10)
            {
                GetComponent<AudioSource>().Play();
            }

            if (Health < ChangeSpriteHealth)
            {
                GetComponent<SpriteRenderer>().sprite = SpriteShownWhenHurt;
            }

            if (Health <= 0)
            {
                Destroy(gameObject);
            }
        }
    }
}        

Destroying Code:

The Destroyer script examines collisions involving trigger interactions (recall that the destroyer possesses a trigger collider). It possesses the capability to eradicate any birds, pigs, or bricks it comes into contact with. One might question the inclusion of "Pig" or "Brick" since only "Birds" will make contact.

However, the rationale behind this approach is to account for potential unforeseen circumstances that could arise when the game is accessed by a vast number of users. By implementing this precaution, the script ensures comprehensive functionality and robustness.

using UnityEngine;

public class Pig : MonoBehaviour
{
    public float Health = 150f;
    public Sprite SpriteShownWhenHurt;
    private float ChangeSpriteHealth;

    void Start()
    {
        ChangeSpriteHealth = Health - 30f;
    }

    void OnCollisionEnter2D(Collision2D collision)
    {
        Rigidbody2D collisionRigidbody = collision.gameObject.GetComponent<Rigidbody2D>();

        if (collisionRigidbody != null)
        {
            if (collision.gameObject.CompareTag("Bird"))
            {
                GetComponent<AudioSource>().Play();
                Destroy(gameObject);
            }
            else
            {
                float damage = collisionRigidbody.velocity.magnitude * 10;
                Health -= damage;

                if (damage >= 10)
                {
                    GetComponent<AudioSource>().Play();
                }

                if (Health < ChangeSpriteHealth)
                {
                    GetComponent<SpriteRenderer>().sprite = SpriteShownWhenHurt;
                }

                if (Health <= 0)
                {
                    Destroy(gameObject);
                }
            }
        }
    }
}        

Main Program that manage the game:

In the context of the "Angry Birds" game, the GameManager plays a pivotal role in coordinating and managing various aspects of the game's mechanics and flow. Its responsibilities encompass:

  1. Game Initialization: The GameManager typically handles the setup of game elements at the beginning, ensuring that the scene is properly configured for gameplay.
  2. Level Management: It may manage the progression between different levels, including loading new levels, tracking the current level, and handling level completion conditions.
  3. UI and User Interaction: The GameManager often controls the user interface elements, such as displaying scores, level information, and buttons for navigation or restarting levels.
  4. Game State Management: It tracks the overall game state, including whether the game is in progress, paused, or over. This can affect various game mechanics and behaviors.
  5. Event Handling: The GameManager can be responsible for handling game events, such as collisions, victories, losses, or interactions triggered by the player.
  6. Score Tracking: It may manage the player's score, including incrementing it based on successful actions like destroying pigs and structures.
  7. Game Over Conditions: The GameManager determines when the game is over, whether due to the player's success or failure, and triggers appropriate actions like displaying game over screens or transitioning to a victory sequence.
  8. Player Input Handling: It could manage user input, including touch or mouse interactions, and relay this input to the relevant game components.
  9. Dynamic Object Management: In some cases, the GameManager might handle the instantiation, activation, or deactivation of objects during gameplay.
  10. Audio and Visual Effects: It could manage the triggering of sound effects, animations, and visual effects to enhance the game's immersion.
  11. Overall Game Flow: The GameManager ensures that the game progresses smoothly, handling transitions between different game phases and states.

using UnityEngine;
using System.Collections.Generic;

public class GameManager : MonoBehaviour
{
    public CameraFollow cameraFollow;
    private int currentBirdIndex;
    public SlingShot slingshot;

    [HideInInspector]
    public static GameState CurrentGameState = GameState.Start;

    private List<GameObject> Bricks;
    private List<GameObject> Birds;
    private List<GameObject> Pigs;

    void Start()
    {
        InitializeGame();
        slingshot.BirdThrown -= Slingshot_BirdThrown;
        slingshot.BirdThrown += Slingshot_BirdThrown;
    }

    private void InitializeGame()
    {
        CurrentGameState = GameState.Start;
        slingshot.enabled = false;

        Bricks = new List<GameObject>(GameObject.FindGameObjectsWithTag("Brick"));
        Birds = new List<GameObject>(GameObject.FindGameObjectsWithTag("Bird"));
        Pigs = new List<GameObject>(GameObject.FindGameObjectsWithTag("Pig"));
    }

    private void Slingshot_BirdThrown(object sender, System.EventArgs e)
    {
        currentBirdIndex++;
        if (currentBirdIndex < Birds.Count)
        {
            cameraFollow.BirdToFollow = Birds[currentBirdIndex].transform;
        }
    }
}        

Within the Update method, the current gamestate enum value is assessed as follows:

  • When on the brink of commencing, the script monitors whether the user has initiated a tap on the screen.
  • During the "Playing" state, the script evaluates if all on-screen movement has ceased or if more than 5 seconds have transpired since the bird's release. Should either criterion be met, the slingshot's functionality is deactivated, paving the way for the next bird's launch preparation.
  • If the player emerges victorious or faces defeat, a subsequent tap from the user triggers the restart of the current level. In a conventional gameplay scenario, a triumph would propel the player to the subsequent level.

void Update()
{
    switch (CurrentGameState)
    {
        case GameState.Start:
            if (Input.GetMouseButtonUp(0))
            {
                AnimateBirdToSlingshot();
            }
            break;
            
        case GameState.BirdMovingToSlingshot:
            // No action needed in this state
            break;
            
        case GameState.Playing:
            if (slingshot.slingshotState == SlingshotState.BirdFlying &&
                (BricksBirdsPigsStoppedMoving() || Time.time - slingshot.TimeSinceThrown > 5f))
            {
                slingshot.enabled = false;
                AnimateCameraToStartPosition();
                CurrentGameState = GameState.BirdMovingToSlingshot;
            }
            break;
            
        case GameState.Won:
        case GameState.Lost:
            if (Input.GetMouseButtonUp(0))
            {
                Application.LoadLevel(Application.loadedLevel);
            }
            break;
            
        default:
            break;
    }
}        

This mechanism ensures that the game's flow and interactions align cohesively with its distinctive states and conditions.

The below function AllPigsDestroyed() is ued to check whether all pigs are destroyed or null

private bool AllPigsDestroyed()
{
    return Pigs.All(x => x == null);
}        

The AnimateCameraToStartPosition method orchestrates the camera's movement back to its initial position. This action takes place following the bird's launch and the cessation of all in-game movement. Once the camera's relocation is finalized, the game evaluates the current game state. If all pigs have been eliminated, the player secures victory. Alternatively, if victory hasn't been achieved, the game progresses to the next available bird for launching. However, if no more birds remain, this denotes defeat for the player.

private void AnimateCameraToStartPosition()
{
    float distanceToStartPosition = Vector2.Distance(Camera.main.transform.position, cameraFollow.StartingPosition);
    float duration = distanceToStartPosition / 10f;
    if (duration == 0.0f) duration = 0.1f;

    Camera.main.transform.positionTo(duration, cameraFollow.StartingPosition)
        .setOnCompleteHandler((x) =>
        {
            cameraFollow.IsFollowing = false;

            if (AllPigsDestroyed())
            {
                CurrentGameState = GameState.Won;
            }
            else if (currentBirdIndex == Birds.Count - 1)
            {
                CurrentGameState = GameState.Lost;
            }
            else
            {
                slingshot.slingshotState = SlingshotState.Idle;
                currentBirdIndex++;
                AnimateBirdToSlingshot();
            }
        });
}        

The AnimateBirdToSlingshot function selects the subsequent bird intended for launch and positions it accurately within the slingshot. Upon completion, the slingshot functionality is activated, rendering the bird poised for release.

void AnimateBirdToSlingshot()
{
    CurrentGameState = GameState.BirdMovingToSlingshot;
    Birds[currentBirdIndex].transform.positionTo(
        Vector2.Distance(Birds[currentBirdIndex].transform.position / 10,
        slingshot.BirdWaitPosition.transform.position) / 10, // duration
        slingshot.BirdWaitPosition.transform.position) // final position
            .setOnCompleteHandler((animation) =>
            {
                animation.complete();
                animation.destroy(); // destroy the animation
                CurrentGameState = GameState.Playing;
                slingshot.enabled = true; // enable the slingshot
                slingshot.BirdToThrow = Birds[currentBirdIndex]; // set the current bird for throwing
            });
}        

The BirdThrown event handler informs the camera follow script that the bird currently in motion should be tracked. This ensures that the camera's movement responds to the bird's position.

private void Slingshot_BirdThrown(object sender, System.EventArgs e)
{
    cameraFollow.BirdToFollow = Birds[currentBirdIndex].transform;
    cameraFollow.IsFollowing = true;
}        

Bird Launching Code:

The slingshot script manages all interactions associated with the bird being attached to the slingshot. It commences by initializing several variables.

public class SlingShot : MonoBehaviour
{
    private Vector3 SlingshotMiddleVector;
    public SlingshotState slingshotState;

    public Transform LeftSlingshotOrigin, RightSlingshotOrigin;
    public LineRenderer SlingshotLineRenderer1;
    public LineRenderer SlingshotLineRenderer2;
    public LineRenderer TrajectoryLineRenderer;

    public GameObject BirdToThrow;
    public Transform BirdWaitPosition;

    public float ThrowSpeed;
    public float TimeSinceThrown;
}        

In the Start method, it configures the sorting layer for the line renderers (as this isn't currently achievable through the editor). Additionally, it computes the midpoint of the slingshot, which is the point equidistant from the two slingshot parts.

void Start()
{
    SlingshotLineRenderer1.sortingLayerName = "Foreground";
    SlingshotLineRenderer2.sortingLayerName = "Foreground";
    TrajectoryLineRenderer.sortingLayerName = "Foreground";

    slingshotState = SlingshotState.Idle;
    SlingshotLineRenderer1.SetPosition(0, LeftSlingshotOrigin.position);
    SlingshotLineRenderer2.SetPosition(0, RightSlingshotOrigin.position);

    SlingshotMiddleVector = new Vector3(
        (LeftSlingshotOrigin.position.x + RightSlingshotOrigin.position.x) / 2,
        (LeftSlingshotOrigin.position.y + RightSlingshotOrigin.position.y) / 2,
        0
    );
}        

The Update method is quite extensive, thus we'll break it down step by step. In the idle state of the slingshot:

  • The method relocates the bird to the appropriate position and reveals the slingshot's line renderers.
  • If the user taps the screen and the tap falls within the bird's collider (noting that the collider is larger prior to being thrown), the state is altered.

void Update()
{
    switch (slingshotState)
    {
        case SlingshotState.Idle:
            InitializeBird();
            DisplaySlingshotLineRenderers();

            if (Input.GetMouseButtonDown(0))
            {
                Vector3 tapLocation = Camera.main.ScreenToWorldPoint(Input.mousePosition);

                if (BirdToThrow.GetComponent<CircleCollider2D>().OverlapPoint(tapLocation))
                {
                    slingshotState = SlingshotState.UserPulling;
                }
            }
            break;
        // Other cases...
    }
}        

During the "User Pulling" state:

  • The user continuously drags the bird.
  • The script calculates the distance between the bird and the middle point of the slingshot.
  • If the distance surpasses a certain threshold, further dragging is restricted.
  • If the distance falls within the range of "1.5", the bird is adjusted to the intended position.
  • Subsequently, the trajectory of the bird upon release is displayed.

case SlingshotState.UserPulling:
    DisplaySlingshotLineRenderers();

    if (Input.GetMouseButton(0))
    {
        Vector3 tapLocation = Camera.main.ScreenToWorldPoint(Input.mousePosition);
        tapLocation.z = 0;

        if (Vector3.Distance(tapLocation, SlingshotMiddleVector) > 1.5f)
        {
            Vector3 maxPosition = (tapLocation - SlingshotMiddleVector).normalized * 1.5f + SlingshotMiddleVector;
            BirdToThrow.transform.position = maxPosition;
        }
        else
        {
            BirdToThrow.transform.position = tapLocation;
        }

        float distanceToMiddle = Vector3.Distance(SlingshotMiddleVector, BirdToThrow.transform.position);
        DisplayTrajectoryLineRenderer2(distanceToMiddle);
    }
    break;
// Additional cases...
        

When the user releases the bird, we assess whether the pulling duration is sufficient. If it meets the requirement, the bird is launched. If not, the bird is smoothly animated back to its initial position.

else
{
    SetTrajectoryLineRenderersActive(false);

    TimeSinceThrown = Time.time;
    float distanceToMiddle = Vector3.Distance(SlingshotMiddleVector, BirdToThrow.transform.position);

    if (distanceToMiddle > 1)
    {
        SetSlingshotLineRenderersActive(false);
        slingshotState = SlingshotState.BirdFlying;
        ThrowBird(distanceToMiddle);
    }
    else // Not pulled long enough, reinitiate
    {
        float animationDuration = distanceToMiddle / 10; // Adjusted duration
        BirdToThrow.transform.positionTo(animationDuration, BirdWaitPosition.transform.position)
            .setOnCompleteHandler((x) =>
            {
                x.complete();
                x.destroy();
                InitializeBird();
            });
    }
}        

The ThrowBird function calculates the throw's velocity based on the bird's drag during the pull. This velocity affects the bird's rigidbody property, resulting in the throw. Another approach could involve applying a force. Subsequently, the BirdThrown event is triggered, alerting the game manager about the bird's throw.

private void ThrowBird(float distance)
{
    Vector3 velocity = SlingshotMiddleVector - BirdToThrow.transform.position;
    BirdToThrow.GetComponent<Bird>().OnThrow();

    Rigidbody2D birdRigidbody = BirdToThrow.GetComponent<Rigidbody2D>();
    birdRigidbody.velocity = new Vector2(velocity.x, velocity.y) * ThrowSpeed * distance;

    BirdThrown?.Invoke(this, EventArgs.Empty);
}        

In the DisplaySlingshotLineRenderers function, the correct positioning of the slingshot's "strings" that hold the bird is established. The SetSlingshotLineRenderersActive and SetTrajectoryLineRenderers methods serve the purpose of enabling or disabling the relevant renderers.

void DisplaySlingshotLineRenderers()
{
    Vector3 birdPosition = BirdToThrow.transform.position;
    SlingshotLineRenderer1.SetPosition(1, birdPosition);
    SlingshotLineRenderer2.SetPosition(1, birdPosition);
}

void SetSlingshotLineRenderersActive(bool active)
{
    SlingshotLineRenderer1.enabled = active;
    SlingshotLineRenderer2.enabled = active;
}

void SetTrajectoryLineRenderersActive(bool active)
{
    TrajectoryLineRenderer.enabled = active;
}        

The DisplayTrajectoryLineRenderer is used to display the trajectory of the bird when thrown.

void DisplayTrajectoryLineRenderer2(float distance)
{
    SetTrajectoryLineRenderesActive(true);

    Vector2 slingshotToBird = BirdToThrow.transform.position - SlingshotMiddleVector;
    Vector2 initialVelocity = slingshotToBird * ThrowSpeed * distance;

    int segmentCount = 15;
    float segmentScale = 2;
    Vector3[] segments = new Vector3[segmentCount];

    // The first line point is wherever the player's cannon, etc. is
    segments[0] = BirdToThrow.transform.position;

    // Calculate trajectory segments
    for (int i = 1; i < segmentCount; i++)
    {
        float time = i * Time.fixedDeltaTime * 5;
        segments[i] = segments[0] + initialVelocity * time + 0.5f * Physics2D.gravity * Mathf.Pow(time, 2);
    }

    TrajectoryLineRenderer.positionCount = segmentCount;
    TrajectoryLineRenderer.SetPositions(segments);
}        

I trust you've found this tutorial valuable. Should you have any inquiries or thoughts to share, or perhaps you've ingeniously incorporated additional captivating effects using Unity's 2D techniques, feel free to share them with us in the comments section below. Your feedback and insights are greatly appreciated!

We also provide Services of 2D/3D Game Development, 2D/3D Animations, Video Editing and UI/UX Designing.

If you have questions or suggestions related to game or want something to build from us, Feel free to reach out to us anytime!

📱 Mobile: +971 544 614 238

📧 Email: wahhab_mirza@vectorlabzlimited.com

To view or add a comment, sign in

Insights from the community

Others also viewed

Explore topics