basically I have made a very simple game that has blocks falling, I have basic C# knowledge but I can't really figure out on my own how I would go about this. Basically I'm dropping 3 blocks one in the middle, left, and right that you have to avoid. I have made an instantiation script that spawns them on each spawn position within 1 to 4 seconds randomly, but sometimes it will accidentally spawn all 3! I just need a check to see if 2 have already spawned on the left and right, then don't spawn one in the middle, and vice versa. Could you guys help me? Thanks! Btw this is my current spawn script.
public GameObject spawn;
private float spawnTime;
void Start()
{
spawnTime = Random.Range(1, 5);
Invoke("Spawn", spawnTime);
}
void Spawn()
{
spawnTime = Random.Range(1, 5);
Instantiate(spawn, transform.position, Quaternion.identity);
Invoke("Spawn", spawnTime);
}
EDIT:
using UnityEngine;
public class randomSpawner : MonoBehaviour
{
public GameObject spawn;
private float spawnTime = 1;
void Start()
{
if (GameObject.FindGameObjectsWithTag("Cube").Length < 2)
{
spawnTime = Random.Range(1, 3);
Invoke("Spawn", spawnTime);
}
}
void Spawn()
{
if (GameObject.FindGameObjectsWithTag("Cube").Length < 2)
{
spawnTime = Random.Range(1, 3);
Instantiate(spawn, transform.position, Quaternion.identity);
Invoke("Spawn", spawnTime);
}
}
}
You could add a tag on your blocks let's say Block and then before instantiating one you do GameObject.FindGameObjectsWithTag("Block"); which will return an array and then you just verify the length of that array.
void Spawn()
{
if(GameObject.FindGameObjectsWithTag("Block").Length < 2){
Instantiate(spawn, transform.position, Quaternion.identity);
}
spawnTime = Random.Range(1, 5);
Invoke("Spawn", spawnTime);
}
You could also have a static variable that you increment when spawning a block and decrement when you destroy one.
Related
I am trying to make an RTS game using Photon Networking For Unity. What I am trying to do is depending on the players in the specific room (2 in this example) all the players spawn at a different location. What I am having trouble is making a system that spawns the players at different locations and not at the same place when the game starts and PhotonNetwork.Instantiate is called. How can I use SpawnPositions With A list to check if a player is already spawned at the given location if so then it spawns at the next one I hope I covered everything if you need to know anything else just ask.
private GameObject playerPrefab; // Players Prefab
[SerializeField]
public Transform[] SpawnPositions; // 2 Spawn Positions in The unity hierarchy
public List<Vector3> spawnPoints = new List<Vector3>(); // List of spawnpoints to add to
void Start()
{
PhotonNetwork.Instantiate(playerPrefab.name, [what to do here], Quaternion.Euler(0, 0, 0));
}
Edit 2: using Transform[] SpawnPositions
private int spawnIndex;
...
void CreatePlayerObject()
{
if(spawnIndex >= SpawnPositions.length) spawnIndex = 0;
Vector3 position = SpawnPositions [spawnIndex].transform.position;
GameObject newPlayerObject = Instantiate(player, position, Quaternion.identity);
spawnIndex++;
}
...
end edit 2
You can make spawn points. I made the spawn points automatically find the right height. If you don't need auto height, you can use an empty MonoBehaviour or even use a tag. You can make many GameObjects in different positions with this script on them.
...
public class spawnPoint : MonoBehaviour {
public bool autoHeight = true;
public LayerMask putOnTopOfThese;
// Use this for initialization
void Start () {
RaycastHit hit;
Physics.Raycast (transform.position + Vector3.up * 100, -Vector3.up, out hit, 200, putOnTopOfThese);
transform.position = hit.point + Vector3.up;
}
}
To make every player spawn in a different position, you can cycle through the spawn points. Keep in mind that if you use a tag for spawn points instead of a MonoBehaviour, you would need to use GameObject.FindObjectsWithTag instead of FindObjectsOfType
For spawning in different positions:
private int spawnIndex;
...
void CreatePlayerObject()
{
spawnPoint[] sp = GameObject.FindObjectsOfType<spawnPoint> ();
if(spawnIndex >= sp.length) spawnIndex = 0;
Vector3 position = sp [spawnIndex].transform.position;
GameObject newPlayerObject = Instantiate(player, position, Quaternion.identity);
spawnIndex++;
}
...
For random spawning:
...
void CreatePlayerObject()
{
spawnPoint[] sp = GameObject.FindObjectsOfType<spawnPoint> ();
int chosen = Random.Range (0, sp.Length);
Vector3 position = sp [chosen].transform.position;
GameObject newPlayerObject = Instantiate(player, position, Quaternion.identity);
}
...
Edit: clarity
Thank you bazilbaachu(https://answers.unity.com/users/1127669/bazilbaachu.html).
I am posting my entire workflow of instantiating players at different positions:
Initially checking whether we are master client or not:
Then obtain list of players and send rpc to each of them individually on positions to spawn them.You can store an array of positions and send index in rpc.
Here is the code:
photonView = PhotonView.Get(this);
if(PhotonNetwork.IsMasterClient)
{
foreach(Player pl in PhotonNetwork.PlayerList)
{
//Debug.Log(pl);
photonView.RPC("InstantiationPlayer",pl,index);
index++;
}
}
[PunRPC]
void InstantiationPlayer(int index)
{
PhotonNetwork.Instantiate(Playerprefabs[value].name,SpawnPoints[index].transform.position, Quaternion.identity, 0);
}
Thank you.
public Transform[] spawnPoints;
private void Start()
{
int randomNumber = Random.Range(0, spawnPoints.Length);
Transform spawnPoint = spawnPoints[randomNumber];
PhotonNetwork.Instantiate(playerPrefabs.name, spawnPoint.position, Quaternion.identity);
}
Drag your GameObject points into Spawn Points
Im making a game where you have 3 blocks to move within and theres obstacle in two of them, heres a picture picture of game. the problem im having is that the obstacles sometimes take a break of like 3 seconds and then spawns again and then wait for sometime and start spawnining again. the pattern is not continous. I want them to always spawn with like a second inbetween.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class merHinder : MonoBehaviour
{
public Rigidbody2D orginal;
private Vector3[] spawnPos = new Vector3[3];
// Start is called before the first frame update
void Start()
{
//InvokeRepeating("timer", 0f, 1f);
StartCoroutine(SpawnAtIntervals(1f));
}
// Update is called once per frame
void Update()
{
spawnPos[0] = new Vector3(3, 3.86f, -5);
spawnPos[1] = new Vector3(-3, 3.86f, -5);
spawnPos[2] = new Vector3(0, 3.86f, -5);
}
private void FixedUpdate()
{
}
void Spawn()
{
int randomNumber = Random.Range(0, spawnPos.Length);
int randomNumber1 = Random.Range(0, spawnPos.Length);
if (randomNumber != randomNumber1)
{
Rigidbody2D clone1 = Instantiate(orginal, spawnPos[randomNumber], Quaternion.identity);
Rigidbody2D clone2 = Instantiate(orginal, spawnPos[randomNumber1], Quaternion.identity);
}
//Destroy(orginal);
}
bool keepSpawning = true;
IEnumerator SpawnAtIntervals(float secondsBetweenSpawns)
{
// Repeat until keepSpawning == false or this GameObject is disabled/destroyed.
while (keepSpawning)
{
// Put this coroutine to sleep until the next spawn time.
yield return new WaitForSeconds(secondsBetweenSpawns);
// Now it's time to spawn again.
Spawn();
}
}
}
They only spawn if the random numbers are different. But sometiomes random results in the same number.
int randomNumber = Random.Range(0, spawnPos.Length);
int randomNumber1 = Random.Range(0, spawnPos.Length);
if (randomNumber != randomNumber1) // <- No spawn if both random numbers are the same
{
Rigidbody2D clone1 = Instantiate(orginal, spawnPos[randomNumber], Quaternion.identity);
Rigidbody2D clone2 = Instantiate(orginal, spawnPos[randomNumber1], Quaternion.identity);
}
Possible solution (bit hacky, but no heap allocation):
void Spawn()
{
int randomNumber = Random.Range(0, spawnPos.Length);
int randomNumber1 = Random.Range(0, spawnPos.Length);
while (randomNumber == randomNumber1)
{
// try again until numbers are different
randomNumber1 = Random.Range(0, spawnPos.Length);
}
Rigidbody2D clone1 = Instantiate(orginal, spawnPos[randomNumber], Quaternion.identity);
Rigidbody2D clone2 = Instantiate(orginal, spawnPos[randomNumber1], Quaternion.identity);
}
I am writing Scripts for flappy bird type game on my own(best way to learn unity scripting).
To optimize perfromance i want to generate only 5 Obstacle gameObjects(ObjectsOnScreen) at a time.So i wrote a code to destroy gameObject when its 16 units away from the player.And also to generate only one new Obstacle when there are less than 5 ObjectsOnScreen.
But my code is destroying one obsatcle and at the same time generating two objects (instead of one).So ultimately the objects will increase over time intead of remaining constant.
Please tell me mistakes in my code.thanks in advance.
//GameManager script::
public class GameManager : MonoBehaviour
{
static public int ObjectsOnScreen = 0;
public float poleDistance;
public int gapWidth;
static public bool reset=false;
float x = 8;
int gap;
public GameObject obstacle;
void FixedUpdate()
{
if(reset)
{
UnityEngine.SceneManagement.SceneManager.LoadScene(0);
}
if(ObjectsOnScreen<5)
{
gap = Random.Range(-6, 6);
GenerateObstacle(x, gap);
x += poleDistance;
Debug.Log("gap = " + gap);
ObjectsOnScreen++;
}
}
void GenerateObstacle(float x , float gap)
{
GameObject Top = Instantiate(obstacle, new Vector3(x, 8, 0) , Quaternion.identity);
GameObject Bottom = Instantiate(obstacle, new Vector3(x, -8, 0), Quaternion.identity);
Top.transform.localScale = new Vector3(1, (8 - gap)-gapWidth, 1);
Bottom.transform.localScale = new Vector3(1, -(8 + gap)+gapWidth, 1);
}
}
//Obstacle Script::
public class ObstacleScript : MonoBehaviour
{
GameObject player;
void Awake()
{
player = GameObject.Find("Player");
}
void FixedUpdate()
{
if ((transform.position.x - player.transform.position.x) <= -16)
{
GameManager.ObjectsOnScreen--;
Destroy(gameObject);
}
}
private void OnCollisionEnter2D(Collision2D collision)
{
PlayerScript player = collision.gameObject.GetComponent<PlayerScript>();
if(player!=null)
{
GameManager.reset = true;
}
}
}
You're calling instantiate twice in the GenerateObstacle function which will instantiate two objects (instead of one) of course...
GameObject Top = Instantiate(obstacle, new Vector3(x, 8, 0) , Quaternion.identity);
GameObject Bottom = Instantiate(obstacle, new Vector3(x, -8, 0), Quaternion.identity);
But then you're doing ObjectsOnScreen++, which only increments by one. Then later the two obstacles delete themselves, which effectively decrements twice.
You should probably increment by two ObjectsOnScreen += 2 to get an accurate count.
So, I am making this little game, where the character constantly moves upwards with an autoscroll camera. The character jumps from platform to platform and as soon as a platform or a background tile is nolonger visible, i loop it back up. I assigned a range to my plattforms in which a randomizer choses a value from so that the player gets an individual set of plattforms every time he or she starts the game. the problem is the looping: since i do the randomizing in the start() functions, the random poision of the plattforms is only assigned once and then looped and looped again and again. so the game gets kinda boring after a few loops with is like after 20 seconds :D
Here is my code:
private float randomFloat = 0;
private int subOrAdd = 0;
// Use this for initialization
void Start () {
subOrAdd = Random.Range(1, 10);
randomFloat = Random.Range(0f, 1.4f);
// randomly add or subtract height of object
if (subOrAdd < 6)
{
this.transform.position = new Vector2(transform.position.x, transform.position.y - randomFloat);
}
else if (subOrAdd >= 6)
{
this.transform.position = new Vector2(transform.position.x, transform.position.y + randomFloat);
}
}
Basically, I am having a hardcoded range and then randomly decide to either add or subtract the number that came out of the range. so how would i make it so, that the objects that get looped always ask for a new position? Because start is only called once as you know and even after looping, the position remains the same. I hope I made myself clear here :)
Any help would be awesome!
Here is the the code that loops the platforms:
public class PlattformLooper : MonoBehaviour {
public float spacingBetweenLoops = 0f;
private void OnTriggerEnter2D(Collider2D collider)
{
if (collider.gameObject.tag == "Plattform")
{
Debug.Log("TRIGGERED Plattform!");
float heightOfBGObj = ((BoxCollider2D)collider).size.y;
Vector3 pos = collider.transform.position;
pos.y += heightOfBGObj * (5*5)+spacingBetweenLoops;
collider.transform.position = pos;
}
}
Just extract your randomization logic into a separate method.
void Start () {
RandomizeHeight()
}
public void RandomizeHeight() {
subOrAdd = Random.Range(1, 10);
randomFloat = Random.Range(0f, 1.4f);
// randomly add or subtract height of object
if (subOrAdd < 6)
{
this.transform.position = new Vector2(transform.position.x, transform.position.y - randomFloat);
}
else if (subOrAdd >= 6)
{
this.transform.position = new Vector2(transform.position.x, transform.position.y + randomFloat);
}
}
Then you can call it whenever you want:
public class PlattformLooper : MonoBehaviour {
public float spacingBetweenLoops = 0f;
private void OnTriggerEnter2D(Collider2D collider)
{
if (collider.gameObject.tag == "Plattform")
{
Debug.Log("TRIGGERED Plattform!");
float heightOfBGObj = ((BoxCollider2D)collider).size.y;
Vector3 pos = collider.transform.position;
pos.y += heightOfBGObj * (5*5)+spacingBetweenLoops;
collider.transform.position = pos;
collider.GetComponent<YourComponent>().RandomizeHeight();
}
}
I am making an endless runner style game in unity where the floor tiles spawn randomly and endlessly in front of the player as they run and delete themselves after a certain distance behind the player this is all working fine and as intended however the individual tiles spawn about half way inside each other and as much as I try to debug my code I can't seem to effect them. Ideally, I want the code to do exactly what it's doing, but the tiles spawn end to end rather than inside each other.
Any help would be greatly appreciated.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Tile_Manager : MonoBehaviour
{
public GameObject[] tilePrefabs;
private Transform playerTransform;
private float spawnZ = 5.0f;
private float tileLength = 5.0f;
private float safeZone = 7.0f;
private int amtTilesOnScreen = 10;
private int lastPrefabIndex = 0;
private List<GameObject> activeTiles;
// Use this for initialization
void Start () {
activeTiles = new List<GameObject>();
playerTransform = GameObject.FindGameObjectWithTag ("Player").transform;
for (int i = 0; i < amtTilesOnScreen; i++)
{
if (i < 2)
SpawnTile(0);
else
SpawnTile();
}
}
// Update is called once per frame
void Update () {
if (playerTransform.position.z - safeZone > (spawnZ - amtTilesOnScreen * tileLength))
{
SpawnTile();
DeleteTile();
}
}
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);
}
private void DeleteTile()
{
Destroy(activeTiles [0]);
activeTiles.RemoveAt (0);
}
private int RandomPrefabIndex()
{
if (tilePrefabs.Length <= 1)
return 0;
int randomIndex = lastPrefabIndex;
while (randomIndex == lastPrefabIndex)
{
randomIndex = Random.Range(0, tilePrefabs.Length);
}
lastPrefabIndex = randomIndex;
return randomIndex;
}
}
stacked tiles
You need to take the length of a tile into account. Try changing this
go.transform.position = Vector3.forward * spawnZ;
to this
go.transform.position = Vector3.forward * (spawnZ + tileLength / 2);
to add half the tile length to the spawn position.
Wouldn't you want
go.transform.Translate(Vector3.forward * spawnZ);
not position?
As you're spawning things relative to the world coordinate system.
https://docs.unity3d.com/ScriptReference/Transform.Translate.html