Unity 2d infinite map generation with walls - c#

I trying to make 2d game in unity. I want to make something similar to guy in this video: https://youtu.be/OXRUEqbV2oM
I want to make world generation similar to his, but I was looking on some YouTube tutorials and didn't find how to do it.
If somebody can help me I would appreciate it.
I was looking all over the YouTube and internet and didn't find any way to do it. Even tutorial about procedural generation didn't help me.
Thanks

You should make tiles(parts of your world), and randomly generate them.
Currently i'm trying to make it,
it's problably going to take a while.

This is what i made.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class WorldBuilder : MonoBehaviour
{
public GameObject[] Tiles;
private float RandomNumber;
private float PositionToSpawnX;
public float PositionToSpawnY;
private void Start()
{
RandomNumber = Random.Range(0, 3);
PositionToSpawnX = 0;
Destroy(gameObject, 5);
}
void Update()
{
if(RandomNumber == 0)
{
Instantiate(Tiles[0], new Vector3(PositionToSpawnX, PositionToSpawnY, 0), Quaternion.identity);
RandomNumber = Random.Range(0, 3);
PositionToSpawnX += 5;
}
if (RandomNumber == 1)
{
Instantiate(Tiles[1], new Vector3(PositionToSpawnX, PositionToSpawnY, 0), Quaternion.identity);
RandomNumber = Random.Range(0, 3);
PositionToSpawnX += 5;
}
if (RandomNumber == 2)
{
Instantiate(Tiles[2], new Vector3(PositionToSpawnX, PositionToSpawnY, 0), Quaternion.identity);
RandomNumber = Random.Range(0, 3);
PositionToSpawnX += 5;
}
if (RandomNumber == 3)
{
Instantiate(Tiles[3], new Vector3(PositionToSpawnX, PositionToSpawnY, 0), Quaternion.identity);
RandomNumber = Random.Range(0, 3);
PositionToSpawnX += 5;
}
}
}
You Get the tiles you've Made and put the in the Tiles Array, and run the game(my tiles are 5 unit in scale, if you want it to work you should make your tiles the same size as mine).
if you didn't understand something you can tell me (:

Related

How to spawn random 2D platforms that do not overlap in Unity?

I'm looking for a way to randomly spawn platforms that do not overlap with each other. All the tutorials I found on this topic are for an endless runner game type, and my project is not like that. So far I know how to spawn my platforms but I need those gaps between them. I'm a total begginer in Unity and C# so I'm looking for a simple code if possible.
My code now:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class GameStateManager: MonoBehaviour {
public GameObject YellowPrefab;
public int howManyYellow;
void Start()
{ GameObject tmpYellow;
for (int i = 0; i < howManyYellow; i++)
{
tmpYellow = Instantiate(YellowPrefab, new
Vector3(Random.Range(-50, 50), Random.Range(-
40, -17), 0), Quaternion.identity);
}
}
My platforms have box colliders used by platform effector, if that information is needed.
Edit:
If possible, it would be nice to be able to set max distance between the random platforms, but if it's something hard to do with that kind of code then it's OK without that:)
Look into Physics2D.OverlapBox() or related functions, depending on your needs.
With this you can check if your object's collider is overlapping with any other collider, like so:
for (int i = 0; i < howManyYellow; i++)
{
tmpYellow = Instantiate(YellowPrefab,
new Vector3(Random.Range(-50, 50),
Random.Range(-40, -17), 0),
Quaternion.identity);
BoxCollider2D tmpYCollider = tmpYellow.GetComponent<BoxCollider2D>();
tmpyCollider.enabled = false; // Disable object's own collider to prevent detecting itself
// while collider overlaps, move your object somewhere else (e.g. 17 units up)
while (Physics2D.OverlapBox(tmpYCollider.bounds.center, tmpYCollider.size, 0) != null)
{
tmpYellow.transform.Translate(new Vector3(0, 17));
// or do something else
}
tmpyCollider.enabled = true; // enable the collider again
}
From what I understand, you want to create a bunch of platforms randomly in the area of (-50,-40) -> (50,-17).
If you do not want a platform to be created in the same spot you need to keep track of the location that all of the platforms were placed in.
public GameObject YellowPrefab;
public int howManyYellow;
private List<Vector3> locations;
void Start()
locations = new List<Vector3>();
{
GameObject tmpYellow;
for (int i = 0; i < howManyYellow; i++)
{
bool hasItem = false;
Vector3 tempLocation;
do{
tempLocation = new Vector3(Random.Range(-50, 50), Random.Range(-40, -17), 0);
foreach (Vector3 item in locations)
{
if(tempLocation == item){
hasItem = true;
}
}
} while(hasItem);
locations.Add(tempLocation);
tmpYellow = Instantiate(YellowPrefab, tempLocation, Quaternion.identity);
}
}

unity2d: randomly change position of gameobject after it has been looped

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();
}
}

Instantiating in Unity

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.

Setting the spawn position for a 3D object

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

Spawn gameObject horde, modify concentration of spawned objects

How would I create a non-uniform random generation of gameObjects (enemies) that mimic the formation of a "horde" like this image:
I want there to be more gameObjects in the front and less as it trails off towards the back. I thought of making an Empty gameObject and having the enemies target with code like this:
public Vector3 target : Transform;
if (target == null && GameObject.FindWithTag("Empty"))
{
target = GameObject.FindWithTag("Empty").transform;
}
However, doing that would not give me the "trail" effect where there are fewer int he back.
Here is my code for randomly generating enemies, if it helps:
void SpawnHorde()
{
for (int i = 0; i < hordeCount; i++)
{
Vector3 spawnPosition = new Vector3(Random.Range (0, 200), 50, Random.Range (0, 200));
Instantiate(Resources.Load ("Prefabs/Sphere"), spawnPosition, Quaternion.identity);
}
}
Does anyone have a suggestion as to how to achieve this?
My results after implementing #Jerry's code:
More concentrated in the front; less in the back :)
I would go for Maximilian Gerhardt suggestions. Here is some raw implementation, for you to tweak it as you want. The most important to tweak is positioning in one column, what you can achieve with some random numbers.
void SpawnHorde()
{
int hordeCount = 200;
float xPosition = 0;
const int maxInColumn = 20;
while (hordeCount > 0)
{
int numberInColumn = Random.Range(5, maxInColumn);
hordeCount -= numberInColumn;
if (hordeCount < 0)
numberInColumn += hordeCount;
for (int i = 0; i < numberInColumn; i++)
{
Vector3 spawnPosition = new Vector3(xPosition, 50, Random.Range(0, 100));
Instantiate(Resources.Load("Prefabs/Sphere"), spawnPosition, Quaternion.identity);
}
xPosition += (float)maxInColumn * 2f / (float)hordeCount;
}
}

Categories