ריבוי כדורים
שיעור 15 מתוך 16 בקורס משחק Unity: שובר לבנים של Coddy.
שדרוג Multiball מפצל את הכדור: שני עותקים עפים מהמקום שבו הוא נמצא. Instantiate מעתיק אובייקט מהסצנה כפי שהוא מעתיק prefab, אבל רק מה שה־Inspector היה שומר עובר: שדות ציבוריים ושדות עם [SerializeField], כמו speed ו־paddle. שדה פרטי כמו launched מתחיל בערך ברירת המחדל שלו, false, והמהירות של ה־Rigidbody מתחילה באפס. לכן צריך לומר לעותק מה לעשות, אחרת הוא נצמד למשוט.
כשיש כמה כדורים במשחק, ה־GameManager שומר אותם בתוך List<Ball>, וכדור שאבד גורם לאובדן חיים רק כשהוא האחרון. סליימים שמתפצלים פועלים באותו אופן:
List<Slime> slimes = new List<Slime>();
public void Split(Slime slime)
{
Slime half = Instantiate(slime, slime.transform.position, Quaternion.identity);
half.Hop(Vector3.left); // השדות הפרטיים של העותק מאותחלים מחדש: צריך להורות לו מה לעשות
slimes.Add(half);
}
public void SlimeDied(Slime slime)
{
slimes.Remove(slime);
Destroy(slime.gameObject);
if (slimes.Count == 0) Debug.Log("Room cleared");
}הכדור הראשון ברשימה עשוי להיות עותק, מכיוון שהמקורי יכול ללכת לאיבוד בזמן שהעותקים ממשיכים לעוף, ולכן קוד שזקוק לכדור משתמש ברשימה ולא בשדה Ball מהסצנה.
אתגר
קשה- ב־
GameManager, הוסףusing System.Collections.Generic;ואתList<Ball> balls = new List<Ball>();. הפונקציהStart()מוסיפה אליו תחילה אתball. - כתוב
public void SplitBall(): צור שני עותקים שלballs[0]במיקום שלו, אחד שמשוגר לכיווןnew Vector3(-0.6f, 1f, 0f)ואחד לכיווןnew Vector3(0.6f, 1f, 0f), והוסף את שניהם לרשימה. - שנה את
BallLost: כשיש יותר מכדור אחד ברשימה, הסר ממנה את הכדור שאבד והשמד אותו, מבלי לאבד חיים. כשמסיימים שלב, החזר אתballs[0]אל המחבט במקום אתball. - ב־
PowerUp, פריט Multiball קורא ל־GameManager.Instance.SplitBall()כשאוספים אותו.
לחץ על Play, תפוס פריט כוח ורוד, ואז לחץ על Check.
נסו בעצמכם
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;
}
}
השיעור הזה כולל חידון קצר. התחילו את השיעור כדי לענות עליו ולעקוב אחרי ההתקדמות.