Unity How to limit Spawner? - c#

I am working on a game like 2 cars. So there will be two lines and I have used two object spawner which is going to spawn two shapes, i,e Circle and Square. So when player collides with circle score should update. And when Square falls player is supposed to avoid it by going to another lane. But what is the problem is something both the spawner spawns square simultaneously or with small gap. So player is not able to escape. Any solution for this. Well I guess it does not help much but here is my script
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Instantiter : MonoBehaviour {
public GameObject[] gameobject;
public float SpawnDelay= 3f;
private GameObject objectkeeper;
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
float Spawntime = SpawnDelay * Time.deltaTime; // 1 *1/60
if (Random.value < Spawntime) {
Spawn ();
}
}
void Spawn(){
int number = Random.Range (0, 2);// creating random number between 0 and 1
objectkeeper = Instantiate (gameobject [number], this.transform.position, Quaternion.identity) as GameObject;
objectkeeper.transform.parent = this.transform;
}
void OnDrawGizmos(){
Gizmos.DrawWireSphere (this.transform.position, 0.5f);
}
}
Thank you for your time and consideration

Try this,
It will only spawn one object at a time between the min-max period
It does not cleanup old objects
It allows for more than 2 prefabs
I tried keeping to your code format as much as possible
Disclaimer : I do not currently have a visual studio/mono develop open (in a boring meeting) so i have not tested this :]
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Instantiter : MonoBehaviour {
public GameObject[] prefabs;
// Adding a min-max allows full control of spawning behaviour without editing code again.
// for a fixed time use the same value
public float MinimumSpawnDelay = 3f;
public float MaximumSpawnDelay = 6f;
private GameObject spawnedObject;
// Made this static so it retains it's value across all instances of this script.
// If you want each Instantiter object to function on it's own, remove the static keyword
private static float nextSpawnTime;
// Use this for initialization
void Start () {
// Artificial delay so we do not spawn an object directly at startup
SetNextSpawnTime();
}
// Update is called once per frame
void Update () {
if (Time.time >= nextSpawnTime) {
Spawn ();
}
}
void Spawn(){
// allows you to add more objects to the prefabs array without changing code.
var prefabToSpawn = prefabs[Ranom.Range(0, prefabs.Length)];
spawnedObject = Instantiate (prefabToSpawn, transform.position, Quaternion.identity);
spawnedObject.transform.parent = transform;
SetNextSpawnTime();
}
void OnDrawGizmos() {
Gizmos.DrawWireSphere (transform.position, 0.5f);
}
void SetNextSpawnTime(){
// a simple variable to hold when we should spawn another object, efficient.
nextSpawnTime = Time.time + Random.Range(MinimumSpawnDelay, MaximumSpawnDelay);
}
}

Try using a static variable -
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Instantiter : MonoBehaviour {
public GameObject[] gameobject;
public float SpawnDelay= 3f;
private GameObject objectkeeper;
// Static variable shared across all instances of this script
public static float nextSpawn = 0f;
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
// check if SpawnDelay duration has passed
if (Time.time >= nextSpawn) {
// Now spawn after ramdom time
float Spawntime = SpawnDelay * Time.deltaTime; // 1 *1/60
if (Random.value < Spawntime) {
Spawn ();
}
}
}
void Spawn(){
int number = Random.Range (0, 2);// creating random number between 0 and 1
objectkeeper = Instantiate (gameobject [number], this.transform.position, Quaternion.identity) as GameObject;
objectkeeper.transform.parent = this.transform;
// Set the nextSpawn time to after SpawnDelay Duration
nextSpawn = Time.time + SpawnDelay;
}
void OnDrawGizmos(){
Gizmos.DrawWireSphere (this.transform.position, 0.5f);
}
}

Related

Unity3D: How can I destroy instances of an obstacle prefab once the player passes them on the z-axis in an endless runner?

I've tried setting different names for the instantiations and Destroy(this), Destroy(this.gameObject), and just Destroy(gameObject) but none of them seem to work...
Here is the code for the instantiations attached to an empty game object:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Spawner : MonoBehaviour
{
public GameObject[] obstaclePatterns;
public Transform player;
private float timeBtwSpawn;
public float startTimeBtwSpawn;
public float obstacleSpawnDistance;
public float obstacleSpDMin;
public float obstacleSpDMax;
public float decreaseTime;
public float minTime = 0.65f;
public float obstacleHeightMin = 10f;
public float obstacleHeightMax = 15f;
// makes obstacles randomly ahead of player
private void FixedUpdate() {
if (timeBtwSpawn <= 0) {
obstacleSpawnDistance = Random.Range(obstacleSpDMin, obstacleSpDMax);
int rand = Random.Range(0, obstaclePatterns.Length);
Instantiate(obstaclePatterns[rand], new Vector3(obstaclePatterns[rand].transform.position.x, Random.Range(obstacleHeightMin, obstacleHeightMax), player.position.z + obstacleSpawnDistance), Quaternion.identity);
rand = Random.Range(0, obstaclePatterns.Length);
Instantiate(obstaclePatterns[rand], new Vector3(obstaclePatterns[rand].transform.position.x, Random.Range(obstacleHeightMin, obstacleHeightMax), player.position.z + obstacleSpawnDistance), Quaternion.identity);
rand = Random.Range(0, obstaclePatterns.Length);
Instantiate(obstaclePatterns[rand], new Vector3(obstaclePatterns[rand].transform.position.x, Random.Range(obstacleHeightMin, obstacleHeightMax), player.position.z + obstacleSpawnDistance), Quaternion.identity);
timeBtwSpawn = startTimeBtwSpawn;
if (startTimeBtwSpawn > minTime) {
startTimeBtwSpawn -= decreaseTime;
}
}
else {
timeBtwSpawn -= Time.deltaTime;
}
}
}
And here is the code for the destroy function attached to the obstacle prefab:
using UnityEngine;
public class ObjectDestruction : MonoBehaviour {
public Transform player;
// Update is called once per frame
void FixedUpdate()
{
if (transform.position.z < player.position.z) {
Destroy(gameObject);
Debug.Log("test");
}
}
}
The Debug.Log works fine, but the console keeps producing this error: MissingReferenceException: The object of type 'GameObject' has been destroyed but you are still trying to access it. Your script should either check if it is null or you should not destroy the object. Spawner.FixedUpdate () (at Assets/Scripts/Spawner.cs:26)
EDIT: Destroy(this) seems to get rid of the error message, but it does not destroy the objects.
Thank you so much in advance!
I am not familiar with unity3d, but I suspect that when you destroy an object you also need to remove references to it:
Currently, you have an array of gameObjects stored in obstaclePatterns, so when you destroy the object it becomes null, but remains in the obstaclePatterns array and your code keeps trying to use it.
There are two ways to fix this:
When you destroy a GameObject you could remove it from the obstaclePatterns array, for example int x = IndexOf(obstaclePatterns, gameObject); obstaclePatterns[x] = null; or
Make your program check if the GameObject in obstaclePatterns is null, and if so, then do not use it, for example if(obstaclePatterns[x] != null){do stuff here}.
Alternately:
Are you sure that you want to destroy the game object? Wouldn't it be better to just move the object ahead of the player again and re-use it?

Add a cooldown to a Shooting Script

I Have this simple scrip fot the player to shoot a prefab when clicking the "Disparo" button, in this case the left click. Now its broken because you can spam the click and shoot every second. I dont Know how to add a cooldown to this to make that you only can shoot every certain time.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityStandardAssets.CrossPlatformInput;
public class ProjectileShooter : MonoBehaviour
{
public AudioClip disparo;
GameObject prefab;
public float shootSpeed;
// Start is called before the first frame update
void Start()
{
prefab = Resources.Load("Projectile") as GameObject;
}
// Update is called once per frame
void Update()
{
if (CrossPlatformInputManager.GetButtonDown("Disparo"))
{
GameObject Projectile = Instantiate(prefab) as GameObject;
Projectile.transform.position = transform.position + Camera.main.transform.forward * 2;
Rigidbody rb = Projectile.GetComponent<Rigidbody>();
rb.velocity = Camera.main.transform.forward * shootSpeed;
Destroy(Projectile, 2.2f);
}
}
}
One way to achieve what you want is to set a boolean to check if the process is in cooldown.
private bool isInCooldown = false;
Then in your if statement you can invoke a new method, after completing your computations. As explained in Unity docs Invoke method:
Invokes the method methodName in time seconds.
if (CrossPlatformInputManager.GetButtonDown("Disparo"))
{
if(!isInCooldown){
//Your code here
Invoke("ResetCooldown", 2f);
isInCooldown = true;
}
}
And the ResetCooldown method is simply:
private void ResetCooldown () {
isInCooldown = false;
}
Hope this helps.
The script below sets the cool time easily. You can set the cooldown time by changing shootcoolTime. and do not touch youCanShootNow. that variable only use to save time when you can shoot again;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityStandardAssets.CrossPlatformInput;
public class ProjectileShooter : MonoBehaviour
{
public AudioClip disparo;
GameObject prefab;
public float shootSpeed;
public float shootcoolTime;
float youCanShootNow;
// Start is called before the first frame update
void Start()
{
prefab = Resources.Load("Projectile") as GameObject;
youCanShootNow = 0;
}
public void Update()
{
if (youCanShootNow < Time.time)
{
if (CrossPlatformInputManager.GetButtonDown("Disparo"))
{
GameObject Projectile = Instantiate(prefab) as GameObject;
Projectile.transform.position = transform.position + Camera.main.transform.forward * 2;
Rigidbody rb = Projectile.GetComponent<Rigidbody>();
rb.velocity = Camera.main.transform.forward * shootSpeed;
Destroy(Projectile, 2.2f);
youCanShootNow = Time.time + coolTime;
}
}
}
}

Unassigned variable in Unity

I've just started learning Unity 2D with the "How to make a 2D game" course from Brackeys on YouTube about 3 hrs ago. I'm using Unity 2018.4.1f1 on Ubuntu 18.04, and because JS is not supported in my version so I have to use C# instead. But I've encountered this error on the third video: The variable mainCam of GameSetup has not been assigned. This is my code in C#:
GameSetup.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class GameSetup : MonoBehaviour
{
public Camera mainCam;
public BoxCollider2D topWall, bottomWall, leftWall, rightWall;
public Transform Player1, Player2;
// Start is called before the first frame update
void Start()
{
// topWall = GetComponent<BoxCollider2D>();
// mainCam = GetComponent<Camera>();
// If I uncomment this, there would be a new error: There is no 'Camera' attached to '_GM' game object, but a script is trying to access it.
}
// Update is called once per frame
void Update()
{
// Move each wall to its edge location
topWall.size = new Vector2(mainCam.ScreenToWorldPoint(new Vector3(Screen.width * 2.0f, 0f)).x, 1.0f);
topWall.offset = new Vector2(0f, mainCam.ScreenToWorldPoint(new Vector3(0f, Screen.width, 0f)).y + 0.5f);
}
}
With the help of Google, I've add rb2d.GetComponent<Rigibody2D>() in Start() from the script of the second video under and prevent the error (there are no Start() in the video)
PlayerControls.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerControls : MonoBehaviour
{
public KeyCode moveUp, moveDown;
public float speed = 10;
private Rigidbody2D rb2d = new Rigidbody2D();
// Start is called before the first frame update
void Start()
{
rb2d = GetComponent<Rigidbody2D>();
}
// Update is called once per frame
void Update()
{
if (Input.GetKey(moveUp))
{
Vector3 v = rb2d.velocity;
v.y = speed;
rb2d.velocity = v;
// rb2d.velocity.y = speed;
}
else if (Input.GetKey(moveDown))
{
Vector3 v = rb2d.velocity;
v.y = speed * (-1);
rb2d.velocity = v;
}
else
{
Vector3 v = rb2d.velocity;
v.y = 0;
rb2d.velocity = v;
}
}
}
How can I fix the bug in GameSetup.cs ? I've done exactly what said in the video, but only changed the language from JS to C#
Either assign it null:
public Camera mainCam = null;
But you are most likely missing to attach a camera object to it in the Unity3D editor. Check your inspector and make sure that whatever object that is using this script(GameSetup.cs) has a camera object assigned to its public variable.
Should look something like this. You have to drag and drop a camera object to the Gameobject.

Unity C# unusual obit

I was making a game about space, like KSP and other space simulator game.
This is the normal orbit.
The normal orbit is a circle.
But this is my orbit .
I try using Collider2D and Point effector2D to create gravity but it is not well too.
This is my code:
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class Gravity : MonoBehaviour {
public float Mass;
private List<GameObject> InRangeObjects;
// Use this for initialization
void Start () {
InRangeObjects = new List<GameObject>();
}
// Update is called once per frame
void Update () {
ApplyGravity();
}
void OnTriggerStay2D(Collider2D col)
{
List<GameObject> InRangeObjectstemp = new List<GameObject>();
InRangeObjectstemp.Add(col.gameObject);
InRangeObjects = InRangeObjectstemp;
////////////////////////////////////
}
public void ApplyGravity()
{
foreach (GameObject Ga in InRangeObjects)
{
float distance = (Ga.transform.position - transform.position).magnitude;
if (Ga.GetComponent<TotalDataStorer>().UseInGameGravity == true)
{
float GravitationalPule = (6.673e-11f * ((Mass * Ga.GetComponent<Rigidbody2D>().mass) / (distance * distance))) * Time.deltaTime;
Debug.Log(GravitationalPule);
Vector3 temp = Ga.transform.position - transform.position;
Ga.GetComponent<Rigidbody2D>().AddForce(new Vector2(temp.x, temp.y) * GravitationalPule * -1) ;
}
}
}
}
I have a flower like orbit, how can I fix this?
The problem is your object is not traveling fast enough, that is an orbit of a slow moving outer object not a regular "circular" orbit, you will have to tweak the speed at which your object is moving. In general you got everything right, it is an orbit, and it is mathematically correct, just you need to get the initial conditions correct.
Oh and you spelled pull wrong in GravitationalPule, it is GravitationalPull.

Detect if enemy is facing Player

I am making a game in which if the distance is less than 2 and the enemy is facing the player, text comes up with a restart option. In the update there is an if and else statement which should detect if the enemy is behind or in front of the player. However, the in front option seems to be called once the distance is less than 2, regardless of if the player is facing the npc.
This script is attached to the Enemy:
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
public class EnemyFollow : MonoBehaviour {
Transform player;
Transform enemy;
public GameObject EnemyCaughtCam;
public Text SheCaughtYou;
public GameObject Restart;
public float Speed = 3f;
public float rotS = 3f;
public float sT = 3f;
NavMeshAgent nav;
float timeTillOptionsMenu = 3.0f;
// Use this for initialization
void Awake() {
player = GameObject.FindGameObjectWithTag ("MainCamera").transform;
//enemy = GameObject.FindGameObjectWithTag ("Enemy").transform;
nav = GetComponent<NavMeshAgent> ();
EnemyCaughtCam.SetActive(false);
SheCaughtYou.text = "";
}
// Update is called once per frame
void Update () {
nav.SetDestination (player.position);
DistanceDeath();
if (npcIsFacingPlayer (player)&& !playerIsFacingNpc(player))
print ("Behind");
else if (npcIsFacingPlayer (player)&& playerIsFacingNpc(player))
print ("In Front");
DistanceDeath ();
}
public void DistanceDeath(){
float distance = Vector3.Distance(player.transform.position,
transform.position);
if (distance < 2 ){
EnemyCaughtCam.SetActive(true);
SheCaughtYou.text = "SHE CAUGHT YOU!";
timeTillOptionsMenu -= Time.deltaTime;
if(timeTillOptionsMenu < 0)
{
Restart.SetActive(true);
}
}
}
public bool npcIsFacingPlayer(Transform other)
{
Vector3 toOther =
other.position - transform.position;
return (Vector3.Dot(toOther, transform.forward) > 0);
}
public bool playerIsFacingNpc(Transform other)
{
Vector3 toOther =
transform.position - other.position;
return (Vector3.Dot(toOther, other.forward) > 0);
}
}
First, you are missing some brackets, second there is an stra DistanceDeathcall, here is how your function Update is read:
// Update is called once per frame
void Update () {
nav.SetDestination (player.position);
/** what does the call do here? */
DistanceDeath();
if (npcIsFacingPlayer (player)&& !playerIsFacingNpc(player))
print ("Behind");
else if (npcIsFacingPlayer (player)&& playerIsFacingNpc(player))
print ("In Front");
/** are you missing brackets here? Distance Death is always called */
DistanceDeath ();
}

Categories