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);
}
Related
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.
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.
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
I made my first game in unity,it is running smoothly.
It has a player and aliens and a map as usual.
sometimes the player gets stuck and does not move forward,
even though the animation of player moving forward runs and his legs keeps moving but still it doesn't move
I have to move in other directions and then it can pass through that point where it got stuck
It happens randomly and not on any fixed spot.
and I am not able to figure out why this is happening
I tried to make the map again but still its there
Any suggestions would be a great help.
ublic class Player : MonoBehaviour {
public float speed = 10f;
public Vector2 maxVelocity = new Vector2(3, 5);
public bool standing;
public float jetSpeed = 15f;
public float airSpeedMultiplier = .3f;
public AudioClip leftFootSound;
public AudioClip rightFootSound;
public AudioClip thudSound;
public AudioClip rocketSound;
public Vector3 PlayerDirection = new Vector3(1,1,1);
public int ArtifactCount = 0;
private Animator animator;
private PlayerController controller;
void Start(){
controller = GetComponent<PlayerController> ();
animator = GetComponent<Animator> ();
}
void PlayLeftFootSound(){
if (leftFootSound)
AudioSource.PlayClipAtPoint (leftFootSound, transform.position);
}
void PlayRightFootSound(){
if (rightFootSound)
AudioSource.PlayClipAtPoint (rightFootSound, transform.position);
}
void PlayRocketSound(){
if (!rocketSound || GameObject.Find ("RocketSound"))
return;
GameObject go = new GameObject ("RocketSound");
AudioSource aSrc = go.AddComponent<AudioSource> ();
aSrc.clip = rocketSound;
aSrc.volume = 0.7f;
aSrc.Play ();
Destroy (go, rocketSound.length);
}
void OnCollisionEnter2D(Collision2D target){
if (!standing) {
var absVelX = Mathf.Abs(GetComponent<Rigidbody2D>().velocity.x);
var absVelY = Mathf.Abs(GetComponent<Rigidbody2D>().velocity.y);
if(absVelX <= .1f || absVelY <= .1f){
if(thudSound)
AudioSource.PlayClipAtPoint(thudSound, transform.position);
}
}
}
// Update is called once per frame
void Update () {
var forceX = 0f;
var forceY = 0f;
var absVelX = Mathf.Abs (GetComponent<Rigidbody2D>().velocity.x);
var absVelY = Mathf.Abs (GetComponent<Rigidbody2D>().velocity.y);
if (absVelY < .2f) {
standing = true;
} else {
standing = false;
}
if (controller.moving.x != 0) {
if (absVelX < maxVelocity.x) {
forceX = standing ? speed * controller.moving.x : (speed * controller.moving.x * airSpeedMultiplier);
PlayerDirection = transform.localScale = new Vector3 (forceX > 0 ? 1 : -1, 1, 1);
}
animator.SetInteger ("AnimState", 1);
} else {
animator.SetInteger ("AnimState", 0);
}
if (controller.moving.y > 0) {
PlayRocketSound();
if (absVelY < maxVelocity.y)
forceY = jetSpeed * controller.moving.y;
animator.SetInteger ("AnimState", 2);
} else if (absVelY > 0) {
animator.SetInteger("AnimState", 3);
}
GetComponent<Rigidbody2D>().AddForce (new Vector2 (forceX, forceY));
}
}
Thanks
You should check that the point you are going is not outside your map.
I think that when you are adding forces to the rigidbody you can add "too much" forces and that rigidbody collides with something and after that it get stacked.
Edit:
Check the OnCollisionEnter, OnCollisionStay and Exit also the triggers.
http://docs.unity3d.com/ScriptReference/MonoBehaviour.OnCollisionEnter.html
I'm making a simple game as a means to learn C#. However, I've run into issues with generating multiple enemies.
First, the cloned enemies do not move down the screen. And second, if the enemies collide with each other it produces an infinite loop of new (spawning) enemies. I figured out part of the movement problem, I need to enable the script on the clones inside Unity, but I am unsure how to "properly" fix it (i.e. non-manually).
Here is the script for the enemies:
using UnityEngine;
using System.Collections;
public class Enemy : MonoBehaviour {
public Transform TS;
public float minSpeed = 3f, maxSpeed = 8f, currentSpeed;
public float llocation = -9.15f, rlocation = 9.15f, ylocation = 7.65f; //Above visible screen
// Use this for initialization
void Start () {
TS = transform; //Cache Transform.
currentSpeed = Random.Range(minSpeed, maxSpeed); //Randomize enemy speed;
TS.position = new Vector3 (Random.Range (llocation, rlocation), ylocation, 0); //Randomize enemy spawn point.
}
// Update is called once per frame
void Update () {
TS.position += (Vector3.down * currentSpeed * Time.deltaTime); //Bring enemy down the screen.
if (TS.position.y < -5.35f) {
TS.position = new Vector3 (Random.Range (llocation, rlocation), ylocation, 0);
currentSpeed = Random.Range(minSpeed, maxSpeed);
} //end new spawnpoint and speed.
}
void OnTriggerEnter(Collider collider)
{
if (collider.CompareTag("Laser") || collider.CompareTag("Player")) { //Tag is name of prefab.
//When the laser hits the enemy, destroy the enemy.
Destroy(this.gameObject);
}
if (Player.score < 500 || Player.playerLives >= 1) {
for (int enemies = 0; enemies < 3; enemies++) {
print("Enemies: " + enemies);
Vector3 nposition = new Vector3 (Random.Range (llocation, rlocation), ylocation, 0);
Instantiate(this, nposition, Quaternion.identity);
//TS.position += (Vector3.down * currentSpeed * Time.deltaTime);
}
}
}
}
Try the following code for function "OnTriggerEnter" :
void OnTriggerEnter(Collider collider)
{
if (collider.CompareTag("Laser") || collider.CompareTag("Player")) { //Tag is name of prefab.
//When the laser hits the enemy, destroy the enemy.
Destroy(this.gameObject);
}
if(collider.CompareTag("Enemy")) {
if (Player.score < 500 || Player.playerLives >= 1) {
for (int enemies = 0; enemies < 3; enemies++) {
print("Enemies: " + enemies);
Vector3 nposition = new Vector3 (Random.Range (llocation, rlocation), ylocation, 0);
Instantiate(gameObject, nposition, Quaternion.identity);
//TS.position += (Vector3.down * currentSpeed * Time.deltaTime);
}
}
}
}