1

I am trying to create a ball hitting game in the baseball format. I create a ball as a prefab. I want to push the ball to the main scene within a certain period of time.

For example; when the first ball is in the scene, the second ball will spawn after 5-6 seconds, then the third, fourth etc. I am the beginner level of Unity and I am not good at C#. I am not sure whether I am using the true functions such as Instantiate. Here is my script:

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

public class Ball : MonoBehaviour {
    public float RotateSpeed = 45; //The ball rotates around its own axis
    public float BallSpeed = 0.2f; 

    public GameObject[] prefab;

    public Rigidbody2D rb2D;

    void Start() {
        rb2D = GetComponent<Rigidbody2D>(); //Get component attached to gameobject
        Spawn ();
    }

    void FixedUpdate() {
        rb2D.MoveRotation(rb2D.rotation + RotateSpeed * Time.fixedDeltaTime); //The ball rotates around its own axis
        rb2D.AddForce(Vector2.left * BallSpeed);
        InvokeRepeating("Spawn", 2.0f, 2.0f);

    }

    public void Spawn () 
    {
        int prefab_num = Random.Range(0,3);
        Instantiate(prefab[prefab_num]);
    }

}

After I apply this script, the result is not what I want.

enter image description here

Programmer
  • 121,791
  • 22
  • 236
  • 328
Katzenliebe
  • 39
  • 1
  • 2
  • 12

4 Answers4

3

Add InvokeRepeating("Spawn", 2.0f, 2.0f); to the Start not the FixedUpdate. InvokeRepeating invokes the method methodName in time seconds, then repeatedly every repeatRate seconds. You can check the documentation here.

ThePyzhov
  • 259
  • 2
  • 14
WaleedYaser
  • 605
  • 5
  • 9
3

Use Coroutines

private IEnumerator SpawnBall() {
    while(true) {
        Instantiate(baseball);
        yield return new WaitForSeconds(5);
    }
}

Which can then be started with StartCoroutine() and terminated in one of three ways:

  • internally by breaking out of the while loop with break (the function would then have no more lines to execute and exit)
  • internally by yield break
  • externally by calling StopCoroutine() on a reference to the coroutine
Community
  • 1
  • 1
  • How can I use coroutine with prefab? When I want to update the code, it gives an error: `The type UnityEngine.GameObject[] cannot be used as type parameter T in the generic type or method UnityEngine.Object.Instantiate(T). There is no implicit reference conversion from UnityEngine.GameObject[] to UnityEngine.O` @Draco18s – Katzenliebe May 29 '18 at 15:23
  • 1
    Prefabs have nothing to do with your problem, but rather that you're trying to pass *an array* to a function that does not take an array. – Draco18s no longer trusts SE May 29 '18 at 18:57
2

Alternative to the other answers: Just use a countdown. This sometimes gives you more control

// Set your offset here (in seconds)
float timeoutDuration = 2;

float timeout = 2;

void Update()
{
    if(timeout > 0)
    {
        // Reduces the timeout by the time passed since the last frame
        timeout -= Time.deltaTime;

        // return to not execute any code after that
        return;
    }

    // this is reached when timeout gets <= 0

    // Spawn object once
    Spawn();

    // Reset timer
    timeout = timeoutDuration;
}
derHugo
  • 83,094
  • 9
  • 75
  • 115
  • Thank you. But I still can't achieve the expected result: https://i.imgur.com/c2TA5ZF.gif It's really hard to understand the issue for me. – Katzenliebe May 30 '18 at 14:54
  • I don't really get what you are doing or trying to archive to be honest. I wouldn't put this update function in the ball itself but on a seperated static gameoject. Right now it seems to be exponential because: you spawn a new ball every 2 seconds BUT: this newly spawned ball as well spawns a new ball every 2 seconds => after 2 seconds you have 2 balls, after 4 seconds both spawn a new ball => 4 balls; again after 2 seconds every of those spawn a new ball => 8 balls .... – derHugo May 31 '18 at 18:14
0

I updated my script by considering your feedbacks and it works like a charm. Thanks to all!

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using System.Threading;

public class Ball : MonoBehaviour {
    public float RotateSpeed = 45; //The ball rotates around its own axis
    public float BallSpeed = 0.2f; 

    public GameObject BaseBall;
    public Transform BallLocation;

    public Rigidbody2D Ball2D;

    void Start() {
        Ball2D = GetComponent<Rigidbody2D>(); //Get component attached to gameobject
        InvokeRepeating("Spawn", 5.0f, 150f);
    }       

    void FixedUpdate() {
        Ball2D.MoveRotation(Ball2D.rotation + RotateSpeed * Time.fixedDeltaTime); //The ball rotates around its own axis
        Ball2D.AddForce(Vector2.left * BallSpeed);
    }

    public void Spawn () 
    {
        Instantiate (BaseBall, BallLocation.position, BallLocation.rotation);
    }
}
Katzenliebe
  • 39
  • 1
  • 2
  • 12