I'm writting a small 2D game in Unity with C#. I have built two obstaclespawner which spawn vertical lines. After the lines have been spawned, they move down. One of the spawner is located at the upper left edge and the other one at the upper right edge. Currently, new objects are spawned after a certain time. But my goal is, for example, to spawn a new object on the upper left edge when the object which is spawned on the top right has traveled a certain distance.
Could this possibly be done via the coordinates of the objects?
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ObstacleSpawner : MonoBehaviour
{
public GameObject[] obstacles;
public List<GameObject> obstaclesToSpawn = new List <GameObject>();
int index;
void Awake()
{
InitObstacles();
}
// Start is called before the first frame update
void Start()
{
StartCoroutine (SpawnRandomObstacle ());
}
// Initialize obstacles
void InitObstacles()
{
index=0;
for(int i =0; i<obstacles.Length*3;i++){
GameObject obj = Instantiate(obstacles[index], transform.position, Quaternion.identity);
obstaclesToSpawn.Add(obj);
obstaclesToSpawn [i].SetActive (false);
index++;
if (index == obstacles.Length)
{
index= 0;
}
}
}
IEnumerator SpawnRandomObstacle()
{
//Wait a certain time
yield return new WaitForSeconds(3f);
}
//I want something like this
(if gameObject.x == -0.99){
//activate obstacles
int index = Random.Range(0, obstaclesToSpawn.Count);
while(true){
if (!obstaclesToSpawn[index].activeInHierarchy){
obstaclesToSpawn[index].SetActive(true);
obstaclesToSpawn [index].transform.position = transform.position;
break;
}else{
index = Random.Range (0, obstaclesToSpawn.Count);
}
}
StartCoroutine (SpawnRandomObstacle ());
}
}
As far as I understand, you need to save in each spawner the reference to other spawner.
public class ObstacleSpawner : MonoBehaviour
{
public ObstacleSpawner otherSpawner;
...
Then in spawner check the position of obstacle in the second spawner. Something like this:
...
if (otherSpawner.obstaclesToSpawn[someIndex].transform.position.x <= -0.99)
{
// Spawn new obstacle in this spawner...
...
}
Comparing position of an object to a certain position in the world is something that might work for you right now but may cause problems in the future if you ever try to change anything in the way your scene is set up.
You're looking for distance travelled by an object and you have everything necessary to calculate said distance.
The starting point for all your obstacles spawned by an ObstacleSpawner is the position of the ObstacleSpawner object so you don't need to cache the spawn position which makes things a lot easier.
You need a variable defining the distance after which you want to spawn another obstacle something like public float distBeforeNextObstacle = 1f, then you can compare this distance against the obstacle's distance from its spawn position (use Vector3 or Vector2, both have a Distance method, you should choose whatever fits your game best):
if(Vector3.Distance(obstaclesToSpawn[index].transform.position, transform.position)>=distBeforeNextObstacle)
{
//Spawn next obstacle
}
Related
My game characters keep spawning at one position and they get squashed together i want them to spawn one after another from the door of the shop and after they recieve their product they leave from the door again This is a picture of how they look when they spawn since i'm putting them in a group spawn:
This is the script i'm using to spawn them:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CharacterSpawn : MonoBehaviour
{
[SerializeField]
private float spawnRadius = 7, time = 1.5f;
public GameObject[] enemies;
public Transform groupTransform;
void Start()
{
StartCoroutine(SpawnAnEnemy());
}
IEnumerator SpawnAnEnemy()
{
Vector2 spawnPos = GameObject.Find("Bengal").transform.position;
Instantiate(enemies[Random.Range(0, enemies.Length)], spawnPos, Quaternion.identity, groupTransform);
yield return new WaitForSeconds(time);
StartCoroutine(SpawnAnEnemy());
}
}
EDIT: They still spawn together even after trying the solution bellow check this picture:
I think you will need two scripts for this. One to handle selecting enemy to spawn and another to handle where to place the enemy.
This will pick a random enemy prefab:
public GameObject[] enemies; //Add to enemy prefabs
int spawnEnemy; //Random enemy index
void Start()
{
Pick();
}
void Pick()
{
spawnEnemy = Random.Range(0, enemies.Length);
GameObject Spawn = Instantiate(enemies[spawnEnemy], transform.position, Quaternion.identity);
This will place the enemy prefab in a random position. To avoid overlapping, a float "spaceBetweenEnemies" is introduced.
//Add to your enemy manager. Create an empty game object if you don't have one
//This will place the enemies in random position
public GameObject enemyDistribution;
GameObject spawn;
public int numberOfEnemiesToSpawn;
public float spaceBetweenEnemies = 2; //This is the space between enemies. To avoid overlapping
public float xPos = 5; //x axis
public float yPos = 5; //y axis
void Start()
{
for (int i = 0; i < numberOfEnemiesToSpawn; i++)
{
SpreadItem();
}
}
void SpreadItem()
{
Vector3 ranPos = new Vector3(Random.Range(-xPos, xPos) + spaceBetweenEnemies, Random.Range(-yPos, yPos) + spaceBetweenEnemies, 0f) + transform.position; //z axis is set to zero
spawn = Instantiate(enemyDistribution, ranPos, Quaternion.identity);
}
This may not prevent the enemies from spawning outside the screen parameters. I recommend writing a simple script to attract the enemies towards the centre of the screen of to the player. You can use an "OnTriggerEnter2d" method to check for collision between enemies and to move away from each other. There are good tutorials on "Flocking" on YouTube. You enemies will behave like swarms. This might come in handy for your game.
Hope this helps.
Add a float value called spaceBetweenObjects and add it to the spawnPos
//start with and small value and gradually increase or decrease it until you are happy with the result.
public float spaceBetweenObjects = 1;
Instantiate(enemies[Random.Range(0, enemies.Length)], spawnPos + spaceBetweenObjects, Quaternion.identity, groupTransform);
I've created some boxes to recreate a 2D level where the dungeon is being created in a procedural generation. Altho when I run my script it creates the right levels, but it does not align the Spawnpoints to each other.
This causes an unlimited level generation (since the spawn points don't touch) but it also makes sure that there is no way for the character to go from 1 way to the other. I've made sure that every level is 10 x 10 and the spawn points are 10 pixels away from the middle of the rooms. I wanted to ensure collision between the spawn points but unfortunately, this is not the case.
I have created multiple rooms where each has their own exit (Spawn Point) depending on where the spawn point is, it can connect with another room that has the same spawn point (Room with a left exit is connected by a room with at least a right exit).
I put all of this in an int, declaring the number of rooms that are available.
Roomspawner code
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class RoomSpawner : MonoBehaviour
{
public int openingDirection;
// 1 --> need bottom door
// 2 --> need top door
// 3 --> need left door
// 4 --> need right door
private RoomTemplates templates;
private int rand;
private bool spawned = false;
void Start(){
templates = GameObject.FindGameObjectWithTag("Rooms").GetComponent<RoomTemplates>();
Invoke("Spawn", 0.5f);
}
void Spawn(){
if(spawned == false){
if(openingDirection == 1){
// Need to spawn a room with a BOTTOM door.
rand = Random.Range(0, templates.bottomRooms.Length);
Instantiate(templates.bottomRooms[rand], transform.position, templates.bottomRooms[rand].transform.rotation);
} else if(openingDirection == 2){
// Need to spawn a room with a TOP door.
rand = Random.Range(0, templates.topRooms.Length);
Instantiate(templates.topRooms[rand], transform.position, templates.topRooms[rand].transform.rotation);
} else if(openingDirection == 3){
// Need to spawn a room with a LEFT door.
rand = Random.Range(0, templates.leftRooms.Length);
Instantiate(templates.leftRooms[rand], transform.position, templates.leftRooms[rand].transform.rotation);
} else if(openingDirection == 4){
// Need to spawn a room with a RIGHT door.
rand = Random.Range(0, templates.rightRooms.Length);
Instantiate(templates.rightRooms[rand], transform.position, templates.rightRooms[rand].transform.rotation);
}
spawned = true;
}
void OnTriggerEnter2D(Collider2D other){
if(other.CompareTag("SpawnPoint")){
if(other.GetComponent<RoomSpawner>().spawned == false && spawned == false){
// spawns walls blocking off any opening !
Instantiate(templates.closedRoom, transform.position, Quaternion.identity);
Destroy(gameObject);
}
spawned = true;
}
}
}
}
Room templates
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class RoomTemplates : MonoBehaviour
{
public GameObject[] bottomRooms;
public GameObject[] topRooms;
public GameObject[] leftRooms;
public GameObject[] rightRooms;
public GameObject closedRoom;
}
I did a new test with a room where it has only 1 spawn point. I Paused the game the second the 2nd spawn point was created so you can see that the 2nd level is created a with a different height than the starting one.
Underneath you can see the connecting room spawning just above the starting one. By doing this it messes up all the rest of the rooms.
Instead I want it to be like this
It seems to me like the problem arises due to the way you instantiate the copies of the rooms.
They are all instantiated at transform.position but given that they appear to spawn at all sorts of places, I'd suggest that you make sure that the pivot point/center point of the prefabs/meshes of your Room Templates are aligned correctly.
I'm working on a small game project for school in UNITY, specifically a clone of a snake game called Rattler Race. I'm pretty much a complete beginner with the engine, hence why I'm struggling a bit. The game we're suppose to make has to have 30 unique levels that have ascending complexity, something like this: Final level
My main problem at the moment is spawning food for the snake so it doesn't overlap with any inner walls or the borders.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SpawnFood : MonoBehaviour
{
public GameObject FoodPrefab;
public Transform BorderTop;
public Transform BorderBottom;
public Transform BorderLeft;
public Transform BorderRight;
public Transform Obstacle;
Vector2 pos;
// Use this for initialization
void Start ()
{
for (int i = 0; i < 10; i++) {
Spawn();
}
}
void Spawn()
{
pos.x = Random.Range(BorderLeft.position.x + 5,BorderRight.position.x - 5);
pos.y = Random.Range(BorderBottom.position.y + 5, BorderTop.position.y - 5);
Instantiate(FoodPrefab, pos, Quaternion.identity);
}
// Update is called once per frame
void Update ()
{
}
}
The code is very simple ofcourse because at the moment the game field is empty with no obstacles:
Current state
However my problem is if I was to scale up that tiny red obstacle, like so:
Big Obstacle
The food would spawn behind it(every level has 10 food objects) and be impossible to get. My idea was to build levels off of one object(the "Obstacle") and its copies, I don't really know if that idea is sound yet but I wanted to try.
If theres any way or any method to spawn food objects in locations so they don't overlap with the obstacle, like to check if the space is already occupied or a method that checks if a would be food object intersects with an existing obstacle, I would be very grateful if someone teaches me, because I'm really lost at the moment.
Assuming your food is exactly one unit long, you could have a coroutine which would check if there is something around that food gameObject, if there isn't anything, you can spawn it.
public LayerMask layerMask; //Additional variable so you can control which layer you don't want to be detected in raycast
void Spawn(){
StartCoroutine(GameObjectExists());
}
IEnumerator GameObjectExists(){
do{
yield return null;
pos.x = Random.Range(BorderLeft.position.x + 5,BorderRight.position.x - 5);
pos.y = Random.Range(BorderBottom.position.y + 5, BorderTop.position.y - 5);
}while(Physics2D.OverlapCircle(new Vector2(pos), 1f, layerMask); //1f is the radius of your food gameObject.
Instantiate(FoodPrefab, pos, Quaternion.identity);
yield return null;
}
The waypoints example is from the unity docs tutorial site.
When i put two spheres the enemies will go between them and also not good when they get to one way point they are not turning back sharp 180 degrees but they are like moving backward without turning and then turning. What i want to do is when they get to a way point to turn sharp 180 degrees on the place then to start walking to the other way point. How can i do it ? Shoud i add a state in the animator for that ?
The second problem is when i put the cylinder as waypoint with one sphere the enemies will go to the sphere and will stay there then will make rounds around the sphere they will never get to the cylinder.
This is a screenshot of the scene after baking it.
I set the Terrain to be Navigation Static and Walkable.
I also set the Spheres and the Cylinder to be Naviagtion Static and Walkable.
Guard and Guard 1 are the enemies(ThirdPersonController)
This is a screenshot of the scene the two enemies of the left the two spheres and the big cylinder.
This is the patrol script:
using UnityEngine;
using System.Collections;
public class Ai : MonoBehaviour {
public Transform[] points;
private int destPoint = 0;
private NavMeshAgent agent;
// Use this for initialization
void Start () {
agent = GetComponent<NavMeshAgent> ();
agent.autoBraking = false;
GotoNextPoint ();
}
void GotoNextPoint()
{
if (points.Length == 0)
return;
agent.destination = points [destPoint].position;
destPoint = (destPoint + 1) % points.Length;
}
// Update is called once per frame
void Update () {
if (agent.remainingDistance < 1.5f)
GotoNextPoint ();
}
}
This is a shot video clip i recorded show how they are patrolling.
And also the main player is getting angry all the time not sure why.
Clip
I am creating an endless jumping game. I have created a lot of obstacles to spawn randomly for time and for spaces, but now I want to make the obstacles spawn not in the same place as the previous ones, because they are spawning but sometimes they can spawn on the top of the other or near the others or even inside them, so please help me!
code:
using UnityEngine;
using System.Collections;
public class SpawnObstacles : MonoBehaviour {
public GameObject[] Obstacle;
public float MINTObstacle;
public float MAXTObstacle;
public bool spawning = false;
public Transform pos;
void Update()
{
if (!spawning)
{
StartCoroutine("SpawnObstacle");
}
}
IEnumerator SpawnObstacle()
{
spawning = true;
yield return new WaitForSeconds(Random.Range(MINTObstacle, MAXTObstacle));
Vector2 finalposition = new Vector2(Random.Range(3,7), Random.Range(pos.position.y - 6f, pos.position.y - 6f));
Instantiate(Obstacle[Random.Range(0, Obstacle.Length)], finalposition, Quaternion.identity);
spawning = false;
}
}
I think what you want is some kind of bounding box around each obstacle that represents the "padding" that you want around that obstacle, where no other can be placed. You might use a primitive collider for this purpose.
When you create a new obstacle at a random position, you could check to see if its "padding" collides with another obstacle's "padding", and if so, re-calculate the random position.
One issue I foresee if if you have a very crowded space, this check might have to be re-done many many times before a valid location is found. You may want to limit the number of checks it can do, and if it doesn't find a valid spot it just doesn't spawn the object after 20 tries or so.