How Can I Not Make Points Spawn In The Same Place Twice? (Unity) - unity3d

guys so I'm trying to make an endless Map Generator for my 2D grappling Hook Game Kinda like Danis square Game and I was trying to generate a set number of swingable points in certain range to test.
Everything works fine except that some Points overlap each other when spawned So I was wondering how could I prevent this from happening?
Should I change my code or is there any method of spawning things I should try so they don't overlap?
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MapGenerator : MonoBehaviour
{
public Transform Endpositin;
public int NumOfSwwingablePoints;
public GameObject SwinggablePoint;
public int MinX, MaxX;
public int MinY, MaxY;
public int Xpos;
public int Ypos;
Vector2 PointPos;
void Start()
{
for (int i = 0; i <= NumOfSwwingablePoints; i++)
{
Xpos = Random.Range(MinX, MaxX);
Ypos = Random.Range(MinY, MaxY);
PointPos = new Vector2(Xpos, Ypos);
Instantiate(SwinggablePoint, PointPos, Quaternion.identity);
}
}
// Update is called once per frame
void Update()
{
}
}
I have Tried this Method and I have also tried to increase values and giving the points colliders to see if they overlap but none of that works. I have also tried update function, but they just keep spawning, and it never stops

My suggestion is everytime you create a new block then save the position of the block in a list.
when next time you create a new block, check the new position with the list.
Here is the code.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MapGenerator : MonoBehaviour
{
public Transform Endpositin;
public int NumOfSwwingablePoints;
public GameObject SwinggablePoint;
public int MinX, MaxX;
public int MinY, MaxY;
private int Xpos;
private int Ypos; // this can be private since we use only privatly
Vector2 PointPos;
List<Vector2> PointPosList = new List<Vector2>();
void Start()
{
for (int i = 0; i < NumOfSwwingablePoints; i++) // I change <= to < since we start from 0
{
Generating();
}
}
void Generating()
{
bool foundSamePosition;
do
{
foundSamePosition = false;
Xpos = Random.Range(MinX, MaxX);
Ypos = Random.Range(MinY, MaxY);
PointPos = new Vector2(Xpos, Ypos);
// finding the generated position is already exist
for (int i = 0; i < PointPosList.Count; i++)
{
if (SamePosition(PointPos, PointPosList[i]))
{
foundSamePosition = true;
}
}
} while (foundSamePosition);// if we found the position try again
// if not found, add the new position to a list for next time check
PointPosList.Add(PointPos);
Instantiate(SwinggablePoint, PointPos, Quaternion.identity);
}
private bool SamePosition(Vector2 v1, Vector2 v2)
{
return (v1.x == v2.x && v1.y == v2.y);
}
}

Related

How to create spawner in a row in unity

I want to spawn 3 object horizontally and I want to spawn them randomly (for example in first spawn if blue is in the middle next it will be get positioned randomly and the other same as this one)
And here is the code I have now:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class EnemySpawner : MonoBehaviour {
public float min_X = -2.3f, max_X = 2.3f;
public GameObject[] colorobject;
public float timer = 2f;
void Start() {
Invoke("SpawnObject", timer);
}
void SpawnObject() {
float pos_X = Random.Range(min_X, max_X);
Vector3 temp = transform.position;
temp.x = pos_X;
if(Random.Range(0, 3) > 0) {
Instantiate(colorobject[Random.Range(0, colorobject.Length)],
temp, Quaternion.identity);
} else {
//
}
Invoke("SpawnObject", timer);
}
} // class
You can try to have a random integer value and a range. For example, if I decide the range between 0-6,if my number is between 0 and 1, I will spawn Red-Blue-Green;if it is between 1 and 2, I will spawn Red-Green-Blue. This may not be the best approach but the only one I can think of right now. You can use Random.Range for that as you have used it above :D

RayCast2D ignor hitting own Collider

Board.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Board : MonoBehaviour
{
public Transform m_emptySprite;
private int m_height = 14;
private int m_width = 6;
// number of rows where we won't have grid lines at the top
public int m_header = 8;
// Start is called before the first frame update
void Start()
{
DrawEmptyCells();
}
void DrawEmptyCells()
{
for (int y = 0; y < m_height - m_header; y++)
{
for (int x = 0; x < m_width; x++)
{
Transform tile;
tile = Instantiate(m_emptySprite, new Vector3(x, y, 0), Quaternion.identity) as Transform;
tile.name = "Tile ( x = " + x.ToString() + " ,y = " + y.ToString() + ")";
tile.transform.parent = transform;
}
}
}
}
Tile.cs
public class Tile : MonoBehaviour
{
private Vector2[] adjacentDirections = new Vector2[] { Vector2.up, Vector2.down, Vector2.left, Vector2.right };
void OnMouseDown()
{
GetAllAdjacentTiles();
}
private GameObject GetAdjacent(Vector2 castDir)
{
RaycastHit2D hit = Physics2D.Raycast(transform.position, castDir);
if (hit.collider != null)
{
print(hit.collider.gameObject.name);
return hit.collider.gameObject;
}
return null;
}
private List<GameObject> GetAllAdjacentTiles()
{
List<GameObject> adjacentTiles = new List<GameObject>();
for (int i = 0; i < adjacentDirections.Length; i++)
{
adjacentTiles.Add(GetAdjacent(adjacentDirections[i]));
}
return adjacentTiles;
}
}
I have tried to use the code above to detect tiles in all 4 directions but when I click on a tile I just get the name of the tile that was clicked.
Each tile has the Tile Script and a BoxCollider2D attached, why is it not printing all 4 tiles surrounding the current tile?
By default for Physics2D you are hitting your own collider the Raycast starts in.
To solve this go to the Physics2D Settings via Edit &rightarrow; Project Settings &rightarrow; Physics2D and disable the option
Queries Start In Colliders
Enable this option if you want physics queries that start inside a Collider 2D to detect the collider they start in.

Coroutine still running even if game is paused and time scale set to 0

As the title pointed out, for some reason when my game is paused my co-routine still runs. I even went as far as to put the time scale condition in a while condition so that the while doesnt run if it paused but to no avail. I've added my code in it's entirety and hope that someone will be able to assist.
using UnityEngine;
using System.Collections;
using Chronos;
public class ObjectSpawn : BaseBehaviour //MonoBehaviour
{
public float minTime = 3f;
public float maxTime = 9f;
public float minX = -65.5f;
public float maxX = -5.5f;
public float topY = -5.5f;
public float z = 0.0f;
public int count = 50;
public GameObject prefab;
public bool doSpawn = true;
public float fallGrav =1.0f;
int first = 1;
void Start()
{
Clock clock = Timekeeper.instance.Clock("MovingOneWayPlatforms");
StartCoroutine(Spawner());
}
IEnumerator Spawner()
{
while (first == 1) {
yield return time.WaitForSeconds(8.0f);
first = 0;
}
while (doSpawn && count > 0 /*&& time.timeScale != 0 */)
{
Renderer renderer = GetComponent<Renderer>();
float min = renderer.bounds.min.x;
float max = renderer.bounds.max.x;
Vector3 v12 = new Vector3(Random.Range(minX, maxX), this.gameObject.transform.position.y, 0f);
prefab.GetComponent<Rigidbody2D>().gravityScale = fallGrav;
prefab = Instantiate(prefab, v12, Random.rotation);
count--;
// yield return new WaitForSeconds(Random.Range(minTime, maxTime));
yield return time.WaitForSeconds(Random.Range(minTime, maxTime));
Destroy(prefab, 6);
}
}
}
Try to uncomment your 2nd while statement, I think that is your problem.
I am new and still not used to Chronos.
Maybe I'm wrong but my guess is this line.
Destroy(prefab, 6);
In my understanding, Destroy's delay should not affected by chronos.
You better use new Coroutine to destroy it.
like this
StartCoroutine(DestroyRoutine(prefab))
IEnumurator DestroyRoutine(GameObject gameobject)
{
yield return time.WaitForSeconds(6);
Destroy(gameObject)
}

Unity Networking enemy spawning is not working

I am making a multiplayer MMO with unity and I am stuck on syncing up enemy spawning between clients. Basically the enemies spawn as intended, but only on the user that spawned them. Here is my code (Sorry it is a bit long, just wanted to include any information that could be relevant, as the is my first time with networking):
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Networking;
[System.Serializable]
public class EnemySpawn {
public GameObject prefab;
public int difficulty;
public int rarity;
[HideInInspector()]
public GameObject instance;
}
public class EnemySpawner : NetworkBehaviour {
public EnemySpawn[] enemys;
public int maxDiff = 8;
public int spawnDistMin = 15;
public int spawnDistMax = 35;
public int spawnLvlDist = 30;
private int diffOnScreen;
private EnemySpawn enemyToSpawn;
public List<EnemySpawn> enemysOnScreen = new List<EnemySpawn>();
void Start() {
StartCoroutine (Spawn());
}
void Update() {
List<EnemySpawn> newEnemysOnScreen = new List<EnemySpawn>();
foreach(EnemySpawn c in enemysOnScreen) {
if (c.instance == null) {
diffOnScreen -= c.difficulty;
} else {
newEnemysOnScreen.Add (c);
}
}
enemysOnScreen = newEnemysOnScreen;
}
//IMPORTANT PART!!! \/\/\/
[Command]
void CmdSpawn(Vector3 pos) {
GameObject spawning = Instantiate (enemyToSpawn.prefab, pos, Quaternion.identity);
NetworkServer.Spawn (spawning);
diffOnScreen += enemyToSpawn.difficulty;
enemysOnScreen.Insert (0,enemyToSpawn);
enemysOnScreen [0].instance = spawning;
spawning.GetComponent<MonsterMain>().lvl = Mathf.RoundToInt(spawning.transform.position.magnitude / spawnLvlDist);
}
IEnumerator Spawn() {
while (true) {
int n = 0;
while (n != 1) {
enemyToSpawn = enemys [Random.Range (0, enemys.Length)];
n = Random.Range (1, enemyToSpawn.rarity);
}
while (maxDiff - diffOnScreen <= enemyToSpawn.difficulty) {
yield return null;
}
yield return null;
Transform player = Player.localPlayer.transform;
Vector2 randomOffset = Random.insideUnitCircle.normalized * Random.Range (spawnDistMin, spawnDistMax);
CmdSpawn(player.position + new Vector3(randomOffset.x,randomOffset.y,0));
}
}
}
I am using Unity 2017.1.3.3p3, and I am building this to IOS. It is a 2d game and I am using unity's build in networking system. Again everything works except that the enemies only spawn on one screen. I am connecting one phone to the editor. Any help is appreciated. thank you!

Can not print out gameobject's position's value correctly

When trying to print out (debug) my objects value, it gives me the position's value of where it's original position is (the startposition in world space). So my object is placed in -3.51 in y in world space before starting the game, therefore it only prints out -3,51 on every update despite the fact that in the inspector you can see the y position (in transform) changing when the object moves.
This is the code that does it:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
// Icke procedurell
public class createLevels : MonoBehaviour {
public GameObject doodle;
public Transform doodleTransform;
public GameObject greenPlatform;
public float distMultiplier = 1f;
public float valueY;
public int ammountPlatforms = 10;
public float levelWidth = 3f;
public float minY = 0.2f;
public float maxY = 1.5f;
public Vector3 spawnPosition = new Vector3();
void Start()
{
for (int i = 0;i < ammountPlatforms; i++) // Instansierar en startsumma platformar.
{
spawnPosition.y += Random.Range(minY, maxY); // Ökning i y
spawnPosition.x = Random.Range(-levelWidth, levelWidth); // Ingen ökning i x..
Instantiate(greenPlatform, spawnPosition, Quaternion.identity);
}
}
void Update()
{
Debug.Log(doodle.GetComponent<Transform>().position.y);
/*
if (doodleTransform.position.y >= 10)
{
Debug.Log("I am over a certain distance.");
distMultiplier++;
Instantiate(greenPlatform, spawnPosition, Quaternion.identity);
}
*/
}
}
Also note that this is a script on another gameobject referencing my "wanted" gameobject's position.
To summarize the question, if you look in the update function, observe the "Debug.Log". It only prints out my startvalue, and i am trying to print out the objects position in y in realtime, being dynamic.