Spawning 2d objects randomly, but not overlapping with other objects - c#

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

Related

Unity destroying player outside of boundary box (Saving positions in a for loop)

I would like some help with figuring this out as my brain is having a funny day today at what is the best way to go about this.
I have an OnDrawGizmos as follows
Transform parentBounds;
void OnDrawGizmos()
{
parentBounds = this.gameObject.transform;
Vector3 from;
Vector3 to;
for (int a = 0; a < parentBounds.childCount; a++)
{
from = parentBounds.GetChild(a).position;
to = parentBounds.GetChild((a + 1) % parentBounds.childCount).position;
Gizmos.color = new Color(1, 0, 0);
Gizmos.DrawLine(from, to);
}
}
This code is attached on a "parent" object which contains 4 empty game objects as follows
Which produces the following Gizmo (Drawing a square based on where I put the empty objects within the parent)
I can even add more points if I desire.
SO WHAT IS THE PROBLEM ?
What I need is that if the player is not within this box area, I want the player to be destroyed. I'm not sure what the best practice is for this , should I make an array to hold the xmin, ymax, etc. ? or should I generate a new position vector on every loop ? I've tried a few ways that are not giving me the results I want and I taught to ask for some assistance.
Thank you all in advance !
If this is a 2D game (which I assume it is), how about having a script, that has reference to the player object and...
a) game is not using physics
... a public Rect boundaries. On each Update() check if player is within the boundaries and if not - destroy it.
void Update()
{
if (!boundaries.Contains(playerObject.transform.position))
{
Destroy(playerObject);
}
}
b) game is using physics
... a BoxCollider2D with the following script
void OnColliderExit2D(Collider2D collider)
{
// If collider is player object -> destroy collider.gameObject
}

When making the camera follow a ball, which one should control the camera position? The ball or the camera itself?

I am learning Unity3D and now creating a trivial (useless) game as follows.
The ball rolls down the inclined floor and the camera must follows the ball with the following relationship
x camera = x ball
y camera = y ball + 3
z camera = z - 10
There are two possible ways to control the camera position.
The ball controls the camera
In this scenario, I attach the following script to the ball.
public class Ball : MonoBehaviour
{
[SerializeField]
private Transform cameraTransform;
void Start() { }
void Update()
{
Vector3 newCameraPos = new Vector3
{
x = transform.position.x,
y = transform.position.y + 3f,
z = transform.position.z - 10f
};
cameraTransform.position = newCameraPos;
}
}
The camera controls itself
In this scenario, I attach the following script to the camera.
public class Camera : MonoBehaviour
{
[SerializeField]
private Transform ballTransform;
void Start() { }
void Update()
{
Vector3 newCameraPos = new Vector3
{
x = ballTransform.position.x,
y = ballTransform.position.y + 3f,
z = ballTransform.position.z - 10f
};
this.transform.position = newCameraPos;
}
}
Question
Even though both methods work as expected, I am wondering whether there are any pros and cons for each method. Which one should I use?
As you've already mentioned, both examples work as expected.
What I like to do though, is assign functionality to the object that is responsible for performing the 'action'. In this case the camera is 'following' something. At the moment, it is following the ball, but later if you wanted to make it follow something else, would it make sense to have to navigate to your ball gameobject to change that behaviour? I think not.
By assigning functionality to objects based on 'responsibilities' you will often find that your code ends up being much more modular in the long run.
Of course this sort of practice is nothing new to game development, or software development at all. It complements the Single Responsibility Principle and shares many of its qualities.
But, at the end of the day, if you're working on your code alone, then you will know the codebase inside out. So it's up to you really!
I would also suggest creating Components based off of those responsibilities whenever possible. So instead of having one generic Camera component, I would create a FollowTarget component and attach that to the camera. In doing so, you will have enabled the ability to use that very same Component to make some other, arbitrary object follow another arbitrary object in your game.
Happy learning!

Spawn objects in unity

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
}

How to ensure objects are not spawned on top of one another (random spawn location)

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.

Stuck trying to make the AI in Turn-Based Strategy Game

I can already make the movement grid via pathfinding and avoid obstacles for the player. Now I want to make the AI move itself based on the movement grid and available action points (just like the player does), but I don't know how to do it. Right now, I am only able to make the character move to the position (but it is not follow the pathfinding, this character suppose to be the AI). I am stuck trying to solve this problem, but couldn't. Could you guys help me out? Thanks.
Here is the code I've got so far (it makes the character which is suppose to be AI to move to the position, but it not follow the pathfinding):
using UnityEngine;
using System.Collections;
public class AIPlayer : Player
{
void Awake()
{
moveDestination = transform.position;
}
// Use this for initialization
void Start()
{
ColorChanger();
}
// Update is called once per frame
void Update()
{
}
public override void TurnUpdate()
{
if (GameManager.instance.currentPlayerIndex == 5)
{
if (Vector3.Distance(moveDestination, transform.position) > 0.1f)
{
transform.position += (moveDestination - transform.position).normalized * moveSpeed * Time.deltaTime;
if (Vector3.Distance(moveDestination, transform.position) <= 0.1f)
{
transform.position = moveDestination;
actionPoints--;
}
}
else
{
moveDestination = new Vector3(2 - Mathf.Floor(GameManager.instance.mapSize / 2), 1.5f, -2 + Mathf.Floor(GameManager.instance.mapSize / 2));
GameManager.instance.NextTurn();
}
}
base.TurnUpdate();
}
public override void TurnOnGUI()
{
}
public override void ColorChanger()
{
base.ColorChanger();
}
}
Here is the link video for the game:
http://www.youtube.com/watch?v=eo7DzbBPQBs&feature=youtu.be
There's no code for pathfinding there. It's just an overly complicated lerp. As well, moving directly to the position will cause major headaches with graphical obstacle avoidance.
Your best bet is to implement a grid-based navmesh and use something like an A* search to find the path. The movement would be limited to adjacent squares, so graphical obstacle avoidance wouldn't happen.
Have a look at this tutorial. It'll give you everything you need except for animating player movement and the game logic for the target position.

Categories