Menu
CoddyTech

Multibola

Lección 15 de 16 del curso Juego en Unity: Rompebloques de Coddy.

Una mejora Multiball divide la pelota: dos copias salen disparadas desde donde está. Instantiate copia un objeto de la escena igual que copia un prefab, pero solo se transfieren los datos que guardaría el Inspector: campos públicos y campos [SerializeField], como speed y paddle. Un campo privado como launched empieza con su valor predeterminado, false, y la velocidad del Rigidbody empieza en cero. Así que hay que indicarle a la copia qué hacer, o se queda sobre la paleta.

Cuando hay varias pelotas en juego, GameManager las mantiene en una List<Ball>, y perder una pelota solo cuesta una vida cuando es la última. Los Slime que se dividen funcionan igual:

List<Slime> slimes = new List<Slime>();

public void Split(Slime slime)
{
    Slime half = Instantiate(slime, slime.transform.position, Quaternion.identity);
    half.Hop(Vector3.left);   // los campos privados de la copia se inicializan desde cero: indícale qué hacer
    slimes.Add(half);
}

public void SlimeDied(Slime slime)
{
    slimes.Remove(slime);
    Destroy(slime.gameObject);
    if (slimes.Count == 0) Debug.Log("Room cleared");
}

La primera pelota de la lista puede ser una copia, ya que la original puede perderse mientras las copias siguen volando, así que el código que necesita la pelota usa la lista, no el campo Ball de la escena.

challenge icon

Desafío

Difícil
  1. En GameManager, agrega using System.Collections.Generic; y List<Ball> balls = new List<Ball>();. Start() agrega primero ball a la lista.
  2. Escribe public void SplitBall(): crea dos copias de balls[0] en su posición, lanza una hacia new Vector3(-0.6f, 1f, 0f) y la otra hacia new Vector3(0.6f, 1f, 0f), y agrega ambas a la lista.
  3. Cambia BallLost: mientras haya más de una pelota en la lista, se elimina de ella la pelota perdida y se destruye, sin perder ninguna vida. Cuando se despeje un nivel, vuelve a colocar balls[0] en la plataforma en lugar de ball.
  4. En PowerUp, al recoger un objeto Multiball, se llama a GameManager.Instance.SplitBall().

Pulsa Play, recoge un potenciador rosa y después pulsa Check.

Pruébalo tú mismo

using UnityEngine;
using UnityEngine.SceneManagement;
using TMPro;

public class GameManager : MonoBehaviour
{
    public static GameManager Instance;

    public Brick brickPrefab;
    public Transform wall;
    public string[] levels;
    public float spacingX = 1.75f;
    public float spacingY = 0.75f;
    public float topY = 6f;

    public Ball ball;
    public int lives = 3;
    public TMP_Text scoreText;
    public TMP_Text livesText;
    public GameObject gameOverPanel;
    public GameObject[] powerUps;
    public float dropChance = 0.15f;

    int score;
    int level;
    int bricksLeft;

    void Awake()
    {
        Instance = this;
    }

    void Start()
    {
        BuildLevel(0);
        ShowHud();
    }

    void BuildLevel(int index)
    {
        level = index;
        string[] rows = levels[index].Split('/');
        for (int row = 0; row < rows.Length; row++)
        {
            string line = rows[row];
            float left = -(line.Length - 1) * spacingX / 2f;
            for (int col = 0; col < line.Length; col++)
            {
                char c = line[col];
                if (c == '.') continue;
                Vector3 pos = new Vector3(left + col * spacingX, topY - row * spacingY, 0f);
                Brick brick = Instantiate(brickPrefab, pos, Quaternion.identity, wall);
                brick.SetHits(c - '0');
                bricksLeft++;
            }
        }
    }

    public void BrickBroken(Brick brick)
    {
        score += brick.points;
        bricksLeft--;
        ShowHud();
        if (Random.value < dropChance)
        {
            GameObject prefab = powerUps[Random.Range(0, powerUps.Length)];
            Instantiate(prefab, brick.transform.position, Quaternion.identity);
        }
        if (bricksLeft == 0)
        {
            ball.ResetToPaddle();
            BuildLevel((level + 1) % levels.Length);
        }
    }

    public void BallLost(Ball lost)
    {
        lives--;
        ShowHud();
        if (lives == 0)
        {
            gameOverPanel.SetActive(true);
            lost.gameObject.SetActive(false);
        }
        else lost.ResetToPaddle();
    }

    public void PlayAgain()
    {
        SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex);
    }

    void ShowHud()
    {
        scoreText.text = "Score: " + score;
        livesText.text = "Lives: " + lives;
    }
}
quiz iconPonte a prueba

Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.

Todas las lecciones de Juego en Unity: Rompebloques