How to Move disabled gameObjects from one list to another? - c#

I'm been making an endless runner game. I have a set of tiles (4 atm) which I spawn randomly. For optimization purposes I decided instead of instantiating and destroying game objects once the player run though it do disable them and once a when a tile is needed to spawn from the deactivated tiles. I made two lists active and deactivate which will do the above scenario. I managed to disable them but I don't know how to add them to the disable list and spawn them when. needed. How can I achieve it.
Here's the code and what I did so far.
TileManager.cs
void Update ()
{
//Vector3 offset = new Vector3(0f, 0f, Time.time * speed);
//GameObject go;
//go.transform.SetParent(transform);
if (playerTransform.position.z - safeZone > (spawnZ - amtOfTilesOnScreen * tileLength))
{
SpawnTile();
DeleteTile();
}
}
private void DeleteTile()
{
//Destroy(activeTiles[0]);
activeTiles[0].SetActive(false);
activeTiles.RemoveAt(0);
//deactivatedTiles.RemoveAt(0);
}
private void SpawnTile(int prefabIndex = -1)
{
GameObject go;
if (prefabIndex == -1)
{
go = Instantiate(tilePrefabs[RandomPrefabIndex()]) as GameObject;
}
else
{
go = Instantiate(tilePrefabs[prefabIndex]) as GameObject;
}
go.transform.SetParent(transform);
go.transform.position = Vector3.forward * spawnZ;
spawnZ += tileLength;
activeTiles.Add(go);
//go.SetActive(false);
//if (deactivatedTiles != null)
//{
// Debug.Log("Has a Tile");
// deactivatedTiles[0].SetActive(true);
//}
//Debug.Log(deactivatedTiles);
}
A help would be greatly appreciated.

Instead of deactivating and then re-activating your tiles, you could just move them from the back to the front when needed, like this:
|---|---|---|---|
|---|---|---|---|
|
V
|---|---|---|---|
|---|---|---|---|
(The first picture is the old state, and the second one is the state after). Instead of
if (playerTransform.position.z - safeZone > (spawnZ - amtOfTilesOnScreen * tileLength)) {
SpawnTile();
DeleteTile();
}
Do something like
if (playerTransform.position.z - safeZone > (spawnZ - amtOfTilesOnScreen * tileLength)) {
if (activeTiles.Count() < (NumberOfTilesThatFitOnScreen + 1)) {
var spawnedTile = SpawnTileAtFront();
activeTiles.Add(spawnedTile);
} else {
var movedTile = activeTiles[0];
MoveTileToFront(movedTile);
//Puts the moved tile at the end of the array, so the next tile that will be moved is always the one in back
activeTiles.RemoveAt(0);
activeTiles.Add(movedTile);
}
}
and then implement these two methods like so:
private void MoveTileToFront(GameObject tile)
{
tile.transform.position = Vector3.forward * spawnZ;
spawnZ += tileLength;
}
private GameObject SpawnTileAtFront(int prefabIndex = -1)
{
GameObject go;
if (prefabIndex == -1)
{
go = Instantiate(tilePrefabs[RandomPrefabIndex()]) as GameObject;
}
else
{
go = Instantiate(tilePrefabs[prefabIndex]) as GameObject;
}
go.transform.SetParent(transform);
MoveTileToFront(go);
return go;
}
Set NumberOfTilesThatFitOnScreen to the number of tiles that completely fill the screen.
Now your game should keep spawning new tiles until there is enough so that if you alter the last or first tile, it won't show on the screen. Then, once this amount is reached, the game should take the last tile (which isn't on screen) and move it to the front (which also shouldn't be on the screen). Then you're character will encounter this tile again, and another off-screen tile will be moved to the front, and so on. Ideally, it would look like the character is on an infinite path

Just move the tile from the active list to the deactivate list, like this:
private void DisposeActiveTile(int index)
{
GameObject unused_tile = activeTiles[index];
activeTiles.RemoveAt(index);
deactivatedTiles.Add(unused_tile);
}
private GameObject GetLastUnusedTile()
{
if(deactivatedTiles.Count == 0)
return null;
int last_index = deactivatedTiles.Count - 1;
GameObject unused_tile = deactivatedTiles[last_index];
deactivatedTile.RemoveAt(last_index);
return unused_tile;
}
When removing an object from the list, the object is not destroyed if it is referenced by another variable.

Related

(Flappy Bird) Function to alter object that spawns based on number of already instantiated prefabs?

In my flappy bird game, I want to create a loop that works through instantiated pipes, altering the pipe prefab (to reduce space between pipes + increase respawn rate) to increase difficulty based on player score.
The code below works, but I'd like to implement difficulty differently. I don't know how to add newly instantiated objects to a list.
I'd also like to add an event animation that plays after each level (before new pipe prefab instantiated), pausing the loop as the "new level" text flies across the screen.
private void Start()
{
InvokeRepeating("SpawnPipe", .05f, respawnRate);
}
private void SpawnPipe()
{
int levelOne = 8;
int levelTwo = 18;
int levelThree = 29;
if(GameManager.score < levelOne)
{
GameObject pipes1 = Instantiate(pipePrefab1, transform.position, Quaternion.identity);
pipes1.transform.position += Vector3.up * Random.Range(minHeight, maxHeight);
}
if (GameManager.score > levelOne && GameManager.score < levelTwo)
{
GameObject pipes2 = Instantiate(pipePrefab2, transform.position, Quaternion.identity);
pipes2.transform.position += Vector3.up * Random.Range(minHeight, maxHeight);
}
if (GameManager.score > levelTwo && GameManager.score < levelThree)
{
GameObject pipes3 = Instantiate(pipePrefab3, transform.position, Quaternion.identity);
pipes3.transform.position += Vector3.up * Random.Range(minHeight, maxHeight);
}
}
Not sure if this is what you are asking for but Lists are used like this:
List<GameObject> pipes = new List<>();
pipes.add(pipes1);
Using InvokeRepeating to spawn the pipes is probably a bad idea because it gives you little control. I would recommend to check in your Update loop if a certain time passed or distance was traveled and spawn pipes accordingly;

How to rotate the cube I click instead of all cubes rotating at the same time?

So i am instantiating cubes and i want to rotate a single cube which i click, however when i click on the cube, all instantiated cubes rotate at the same time, I keep trying with boolean but no success. Any help would be appreciated. UNITY 2D
{
public int rotationDirection = -1; //-1 for clockwise
public int rotationStep = 5; //Should be less than 90
public bool noRotation;
// public GameObject cubeBox;
private Vector3 currentRotation, targetRotation;
// Update is called once per frame
void Update()
{
if (Input.GetMouseButtonDown(0))
{
RaycastHit2D hit = Physics2D.Raycast(Camera.main.ScreenToWorldPoint(Input.mousePosition), Vector2.zero);
if (hit.collider != null && hit.collider.tag == "colourBox" && noRotation == false)
{
Debug.Log("object clicked: " + hit.collider.tag);
RotateCube();
}
}
}
void RotateCube()
{
currentRotation = gameObject.transform.eulerAngles;
targetRotation.z = (currentRotation.z + (90 * rotationDirection));
StartCoroutine(objectRotationAnimation());
}
IEnumerator objectRotationAnimation()
{
currentRotation.z += (rotationStep * rotationDirection);
gameObject.transform.eulerAngles = currentRotation;
yield return new WaitForSeconds(0);
if (((int)currentRotation.z > (int)targetRotation.z && rotationDirection < 0))
{
StartCoroutine(objectRotationAnimation());
}
}
}
If I understand you correctly this script is present on all cubes.
The problem is that when you click with your mouse every single cube will create its own instance of a raycast. After that every cube will check if the hit.collider is not null, if its tag is colourBox and if noRotation equals false.
You in fact don't check anywhere what cube you just clicked on. You can simply add this check by comparing the instance ID of the gameobject the raycast collided with and the instance ID of the gameobject where the script runs.
if (hit.collider != null && hit.collider.tag == "colourBox" && noRotation == false)
{
// Check if the cube that was clicked was this cube
if (hit.collider.gameObject.GetInstanceID() == gameObject.GetInstanceID())
{
Debug.Log("object clicked: " + hit.collider.tag);
RotateCube();
}
}
This way every cube will compare its instance ID with the instance ID of the clicked object. Only the clicked object will return true in this if statement and thus runs the RotateCube method.
Used this instead of RayCastHit2D ....Deleted everything inside Update and created a new void.
private void OnMouseDown()
{
RotateCube();
}

Spawning a GameObjects have same script but different behavior?

I have a project in my collage for traffic car simulation in unity, and the one of the project requirements is to let the user enter the number of the cars, and each one of them should driving like AI_Driver, and i wrote a script to spawning cars with Instantiate function , i spawned 1000 car and when i am spawning a car, i am making some changes like (the position of the spawned car on the y axis),
the problem is some of the cars has been edited correctly exactly what i want but, the others not applying the changes with the position
.
and here is the script:
public class VehicleSpawner : MonoBehaviour
{
public GameObject[] vehiclePrefabs;
public int vehiclesToSpawn;
public bool navON = false;
public bool aStarON = true;
void Start()
{
StartCoroutine(SpawnMany(0));
}
IEnumerator SpawnMany(int count)
{
while (count < vehiclesToSpawn)
{
GameObject obj = Instantiate(vehiclePrefabs[1]);
GameObject[] spawningPints = GameObject.FindGameObjectsWithTag("spawningPoint");
Transform child = spawningPints[Random.Range(0, spawningPints.Length)].transform;
WaypointNavigator nav = obj.GetComponent<WaypointNavigator>();
nav.spawner = this;
nav.priority = Random.Range(0, 2 * vehiclesToSpawn);
if (!aStarON)
{
nav.currentWaypoint = child.GetComponent<Waypoint>();
nav.navON = navON;
}
else
{
Transform dest = transform.GetChild(Random.Range(0, transform.childCount - 1));
nav.start = child.GetComponent<Waypoint>();
nav.end = dest.GetComponent<Waypoint>();
nav.priority = Random.Range(0, 10000);
nav.aStarON = aStarON;
}
// change in the position
obj.transform.position = new Vector3(
child.GetComponent<Waypoint>().GetPosition().x,
child.GetComponent<Waypoint>().GetPosition().y + 0.5f,
child.GetComponent<Waypoint>().GetPosition().z
);
yield return new WaitForSeconds(0.05f);
count++;
}
}
}
Please any one can help??
Cache spawningPints. Never use Find, because it just runs foreach gameObject in the hierarchy.
Try first to change position, then add Nav component (it might cache position and teleport car back after you change position throw transform).

How do I get a component from a ever changing List of objects?

while working in a 3d endless runner game in unity I came across this issue. I have a List of platforms(segments/roads) that lay in front of the player while the player runs in z direction. I have downloaded a new asset package called Dreamteck splines. So each platform has a spline component attached to it. Once a platform is laid the player grabs the spline and runs according to the pattern of the spline.
Let's say that the player is on the first platform. When the player reaches the end of the first platform's spline, the OnEndReached() event handler is called, which basically says what you want to happen when the spline's endpoint is reached. So I want to know how to I get the next spline once the end is reached.
P = player
As seen in the image above this is what I am trying to accomplish. As a brief description of how platforms are laid is that once the player goes to the next road the one he just passed gets disabled so next time he can reuse the road in front of the player in random manner.
The code: track manager script.
public Segment[] tilePrefabs;
public static Segment newSegment;
public static List<Segment> m_Segments;
public static List<Segment> m_PastSegements;
private int m_SafeSegmentLeft;
private int m_PreSegments = -1;
private float startingSegmentDistance = 4f;
private int startingSafeSegments = 2;
private int amtSegmentsOnScreen = 10;
private float segmentRemovalDistace = -40f;
private float m_TotalWorldDistance;
private float m_CurrentSegmentDistance;
void Update ()
{
while (m_Segments.Count < amtSegmentsOnScreen)
{
SpawnNewSegment();
}
m_TotalWorldDistance += scaledSpeed;
m_CurrentSegmentDistance += scaledSpeed;
if (m_CurrentSegmentDistance > m_Segments[0].worldLength)
{
m_CurrentSegmentDistance -= m_Segments[0].worldLength;
m_PastSegements.Add(m_Segments[0]);
m_Segments.RemoveAt(0);
}
Vector3 currentPos;
Quaternion currentRot;
Transform playerTransform = playerMotor.transform;
m_Segments[0].GetPointAtInWorldUnit(m_CurrentSegmentDistance, out currentPos, out currentRot);
bool needRecenter = currentPos.sqrMagnitude > floatingOriginThreshold;
if (needRecenter)
{
int count = m_Segments.Count;
for (int i = 0; i < count; i++)
{
m_Segments[i].transform.position -= currentPos;
}
count = m_PastSegements.Count;
for (int i = 0; i < count; i++)
{
m_PastSegements[i].transform.position -= currentPos;
}
m_Segments[0].GetPointAtInWorldUnit(m_CurrentSegmentDistance, out currentPos, out currentRot);
}
playerTransform.rotation = currentRot;
playerTransform.position = currentPos;
for (int i = 0; i < m_PastSegements.Count; i++)
{
if ((m_PastSegements[i].transform.position - currentPos).z < segmentRemovalDistace)
{
m_PastSegements[i].Cleanup();
m_PastSegements.RemoveAt(i);
i--;
}
}
}
public void SpawnNewSegment()
{
int useSegment = Random.Range(0, tilePrefabs.Length);
if (useSegment == m_PreSegments)
{
useSegment = (useSegment + 1) % tilePrefabs.Length;
}
Segment segmentToUse = tilePrefabs[useSegment];
newSegment = Instantiate(segmentToUse, Vector3.zero, Quaternion.identity);
Vector3 currentExitPoint;
Quaternion currentExitRotation;
if (m_Segments.Count > 0)
m_Segments[m_Segments.Count - 1].GetPointAt(1.0f, out currentExitPoint, out currentExitRotation);
else
{
currentExitPoint = transform.position;
currentExitRotation = transform.rotation;
}
newSegment.transform.rotation = currentExitRotation;
Vector3 entryPoint;
Quaternion entryRotation;
newSegment.GetPointAt(0.0f, out entryPoint, out entryRotation);
Vector3 pos = currentExitPoint + (newSegment.transform.position - entryPoint);
newSegment.transform.position = pos;
newSegment.manager = this;
newSegment.transform.localScale = new Vector3((Random.value > 0.5f ? -1 : 1), 1, 1);
newSegment.objectRoot.localScale = new Vector3(1.0f / newSegment.transform.localScale.x, 1, 1);
if (m_SafeSegmentLeft <= 0)
SpawnObstacle(newSegment);
else
m_SafeSegmentLeft -= 1;
m_Segments.Add(newSegment);
}
The player script
//Current tile segment;
private Segment currentSegment;
//Spline Follower
private SplineFollower follower
//For Dreamteck spline -->
private Segment nextSegment;
void Start()
{
playerCollider = GetComponent<CapsuleCollider>();
anim = GetComponent<Animator>();
follower = GetComponent<SplineFollower>();
moveLane = currentLane;
follower.onEndReached += Follower_onEndReached;
}
private void Follower_onEndReached()
{
currentSegment = nextSegment;
follower.computer = currentSegment.spline;
}
void OnTriggerEnter(Collider col)
{
nextSegment = col.GetComponentInParent<Segment>();
}
The segment script : Attached to each road/ platform
public SplineComputer spline;
public static Segment next;
SplinePoint[] points;
void Start()
{
spline = GetComponentInChildren<SplineComputer>();
spline.space = SplineComputer.Space.Local;
points = spline.GetPoints();
if (points.Length == 0)
return;
}
At the moment I use colliders, each road has a box collider component. Once the player reach end of the platform it does get the next spline component. It works but sometimes it fails to recognize the next spline and use the same spline which causes the player to run the same platform that he passed again and again.
So I'm out of ideas. So came here to find a solution or advice. Help would be appreciated.
In this case I would simply store my possible segments in a List then when I reached the end get the next segment and move the current 1st segment to the end or where ever you want to move it in the list.
That is
public Segment currentSegment;
public List<Segment> segments;
void OnEndReached()
{
//Put the completed segmetn back in the list ... probably at the end or randomized anywhere but at the start
segments.Insert(segments.Count-1, currentSegment);
//Now get the next segment
currentSegment = segments[0];
segments.RemoveAt(0);
}
In this model you have a simple List which represents the order your segments will appear in, you always set the current segment to the next in the list e.g. index 0 and you put them back in the list when done... putting them at the end or if you want to randomize order slotting them in anyware except index 0 e.g.
segments.Insert(UnityEngine.Random.Range(1, segments.Count), currentSegment);
Note that I removed the segment I am on from the list ... the list just represents the upcoming order which in runner games I find it handy to know that e.g. so I can reset things, change attributes of the segments based on performance, score, etc.
Using OnTriggerEnter, or OnTriggerEnter2D if you're dealing with 2D colliders, should do the job. But as you say you already are working with colliders, I assume this is what you have tried.
You could try:
OnTriggerStay
A Raycast down to the ground object. In this link is a 2D Example: https://kylewbanks.com/blog/unity-2d-checking-if-a-character-or-object-is-on-the-ground-using-raycasts
You can also raycast with 3D objects.
What you would be using it for in this case is basically to shoot a "laser" into the ground below your player and grab an object there based on which layers you tell it to hit. So if you have a layer called "Ground" which your platform is part of, then it can only return objects from that layer.
Just remember to raycast often so it's updated to reflect the game.

Unity 2D C# gameObject does not activate other gameObjects if statements when colliding with each other. Why?

The way this game works is that the game starts off with a Largest Ball. When the rocket hits the large ball it splits into two medium balls and then into two small balls. When the rocket hits the smallest ball it gets destroyed.
The problem I'm having is that when the rocket collides with the ball. The rocket gets destroyed, but the ball does "not" divide into two Large balls and so forth.
I just noticed this and I'm wondering if my problem will be fixed if I turn this code statement to == "smallest ball" instead of !=.
if (target.tag == "Rocket")
{
if (gameObject.tag != "Smallest Ball")
{
InstantializeBallsonoff();
}
else {
AudioSource.PlayClipAtPoint(popsounds[Random.Range(0, popsounds.Length)], transform.position);
//play random audio in the popsounds array at current position of ball
gameObject.SetActive(false); //deactivate the gameobject
}
}
}//ontriggerenter
This is the full code for my ball Script
using UnityEngine;
using System.Collections;
public class Ball : MonoBehaviour {
private float forceX, forceY;
private Rigidbody2D ball;
[SerializeField]
private bool moveLeft, moveRight;
[SerializeField]
private GameObject originalBall;
private GameObject ball1, ball2;
private Ball ball1script, ball2script;
[SerializeField]
private AudioClip[] popsounds; //array
// Use this for initialization
void Awake () {
ball = GetComponent<Rigidbody2D>();
ballspeed();
}
// Update is called once per frame
void Update () {
ballmovement();
}
void InstantiatingBalls()
{
if (this.gameObject.tag != "Smallest Ball")
{
ball1 = Instantiate(originalBall); //create copy of originalball into ball1
ball2 = Instantiate(originalBall);
ball1.name = originalBall.name;
ball2.name = originalBall.name;
ball1script = ball1.GetComponent<Ball>(); //get the ball script
ball2script = ball2.GetComponent<Ball>();
}
}//InstantiatingBalls
void InstantializeBallsonoff() {
InstantiatingBalls();
Vector3 temp = transform.position; //start from current ball location
ball1.transform.position = temp;
ball1script.setmoveLeft(true);
ball2.transform.position = temp;
ball2script.setmoveRight(true);
ball1.GetComponent<Rigidbody2D>().velocity = new Vector2(0, 2.5f); //x,y
ball2.GetComponent<Rigidbody2D>().velocity = new Vector2(0, 2.5f); //x,y
AudioSource.PlayClipAtPoint(popsounds[Random.Range(0, popsounds.Length)], transform.position);
//play random audio in the popsounds array at current position of ball
gameObject.SetActive(false); //deactivate the gameobject
}//InstantializeBallsonoff
public void setmoveLeft(bool moveLeft) { //canMoveLeft
this.moveLeft = moveLeft;
this.moveRight = !moveLeft; //moveRight is now false b/c we set moveLeft to true
}
public void setmoveRight(bool moveRight) {//canMoveRight
this.moveRight = moveRight;
this.moveLeft = !moveRight;
}
void ballmovement() {
if (moveLeft) {
Vector3 temp = transform.position; //current position of ball
temp.x -= Time.deltaTime; // represent time per frame
transform.position = temp;
}
if (moveRight) {
Vector3 temp = transform.position; //current position of ball
temp.x += Time.deltaTime; // represent time per frame
transform.position = temp;
}
}
void ballspeed() {
forceX = 2.5f;
switch (this.gameObject.tag) {
//this refers to gameobject that holds this script
case "Largest Ball":
forceY = 11.5f;
break;
case "Large Ball":
forceY = 10.5f;
break;
case "Medium Ball":
forceY = 9f;
break;
case "Small Ball":
forceY = 8f;
break;
case "Smallest Ball":
forceY = 7f;
break;
}//switch
}//ballspeed
void OnTriggerEnter2D (Collider2D target) {
if (target.tag == "Ground") {
ball.velocity = new Vector2(0, forceY);
}
if (target.tag == "Right Wall") {
setmoveLeft(true);
/*moveRight = false;
moveLeft = true;*/
}
if (target.tag == "Left Wall")
{
setmoveRight(true);
/*moveRight = true;
moveLeft = false;*/
}
if (target.tag == "Rocket")
{
if (gameObject.tag != "Smallest Ball")
{
InstantializeBallsonoff();
}
else {
AudioSource.PlayClipAtPoint(popsounds[Random.Range(0, popsounds.Length)], transform.position);
//play random audio in the popsounds array at current position of ball
gameObject.SetActive(false); //deactivate the gameobject
}
}
}//ontriggerenter
}//ball
This is partial of my code where the rocket gets destroyed when it collides with the large ball & the top. This is the other part that I am having trouble with.
void OnTriggerEnter2D(Collider2D target) {
if (target.tag == "Top") {
Destroy(gameObject);
}
string[] ballhit = target.name.Split();
/*array ballhit
split = deletes the space between two words and make it so it takes 2 spaces in the array*/
for (int s = 0; s < ballhit.Length; s++) {
Debug.Log("The array contains: " +ballhit [s]);
if (ballhit.Length > 1)
{ //ball names will always be more than 1 length "Largest Ball"
if (ballhit[1] == "Ball")
{
Destroy(gameObject);
}//destroy object
}//ballhit name length
}// name increments
}//triggerCollider
This is my full Rocket Script
using UnityEngine;
using System.Collections;
public class Rocket : MonoBehaviour {
private Rigidbody2D rocket;
private float speed = 5f;
// Use this for initialization
void Awake () {
rocket = GetComponent<Rigidbody2D>();
}
// Update is called once per frame
void Update () {
rocket.velocity = new Vector2(0, speed); //x, y rocket movement
}
void OnTriggerEnter2D(Collider2D target) {
if (target.tag == "Top") {
Destroy(gameObject);
}
string[] ballhit = target.name.Split();
/*array ballhit
split = deletes the space between two words and make it so it takes 2 spaces in the array*/
for (int s = 0; s < ballhit.Length; s++) {
Debug.Log("The array contains: " +ballhit [s]);
if (ballhit.Length > 1)
{ //ball names will always be more than 1 length "Largest Ball"
if (ballhit[1] == "Ball")
{
Destroy(gameObject);
}//destroy object
}//ballhit name length
}// name increments
}//triggerCollider
}//rocket
Your code is much more complicated than it needs to be an therefore the actual error is difficult to find.
First off, your moveLeft and moveRight bools are mutually exclusive. You need only one of them. I would event prefer to replace both with a public int currentDirection which you set to 1 for right and -1 for left.
Your new ballMovement method could then simply be:
void MoveBall() // C# methods are upper-case by convention
{
transform.position += Vector3.right * currentDirection * Time.deltaTime;
}
The way you check with which type of ball you are colliding is not very safe. I would suggest you use an enum to differentiate the ball sizes.
public enum BallSizes { Largest, Large, Medium, Small, Smallest }; // The different possible values
public BallSize size = BallSizes.Largest; // The balls current size, the biggest size by default
This also allows you to store your y-axis force values in a matching array and access them easily without the use of a switch or else-if:
private float[] forcesY = new float[]{ 11.5f, 10.5f, 9f, 8f, 7f };
void SetBallSpeed()
{
forceX = 2.5f;
forceY = forcesY[(int)size];
}
I think the problem you had with the ball not splitting is is connected to this.
Upon collision, you detected the type of ball you collided with, by examining its tag. But you always Instantiate the new balls using the same prefab, and I never saw you change the tag. So what type of ball are you creating?
If you use the method I described above, you can simply assign a general tag "Ball" and handle the rest with the BallSizes-enum. When creating the new balls you can do the following:
[SerializedField] // The SerializedField property makes it show up in the inspector, even though it is private
private Ball ballPrefab; // Attention: Type "Ball"
public void IsHit() // Method to execute upon rocket collision
{
if(ball.size != BallSizes.Smallest)
{
Ball leftBall = Instantiate(ballPrefab). // Notice that, when you assign you prefab as Type "Ball", you directly get the Ball-Component as the return value.
leftball.direction = -1;
leftball.size = (BallSizes)(size + 1); // Add one to size, to get get the next enum value, which is the next smaller size.
Ball rightBall = .... // Do same stuff for the right ball
}
Destroy(this.gameObject);
}
I don't know how you plan to visualise the type of ball, but you might want to add a float[] ballScales, which you use to shrink the ball's actual size, something like: leftBall.transform.localScale = Vector3.one * ballScales[(int)size].
Finally, another reason your collision does not work might well be, that you handle it in two different places. If you destroy the rocket after it detects collision with the ball, nothing has happend to the ball yet. If the ball is checking for collision afterward it will most likely not find the rocket, because you already destroyed it. A clean way to solve this, would be to let the rocket notify the ball of the collision:
void OnTriggerEnter2D(Collider2D target)
{
if(target.tag == "Top")
Destroy(gameObject);
else if(target.tag == "Ball")
{
target.GetComponent<Ball>().IsHit(); // We know this component should exist when the object is tagged "Ball"
Destroy(gameobject);
}
}
You can then remove that from you ball collision and shorten it to this:
void OnTriggerEnter2D (Collider2D target)
{
if(target.tag == "Ground")
ball.velocity = new Vector2(0, forceY);
if(target.tag == "Right Wall" || target.tag == "Left Wall")
direction *= -1; // Inverts the direction, + <-> -
}
Phew, that was a lot.
I hope this is still relevant and answers more questions than it raises.
Happy coding!

Categories