I am looking to make my first actual game called Bottomless. It seems I am having a problem with the obstacle generator script in Unity2D. I want the obstacle to generate vertically, where a player is falling down the level.
Here my script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Generator : MonoBehaviour
{
public GameObject spike;
public float maxspeed;
public float minspeed;
public float currentspeed;
void Awake()
{
currentspeed = Random.Range(maxspeed, minspeed);
spikegen();
}
void spikegen()
{
GameObject SpikeIns = Instantiate(spike, transform.position, transform.rotation);
}
void Update()
{
}
}
Seems like running this code crashes unity quickly. Does anyone have better alternative?
So, I have been considering your problem, and I think the best thing to do would be to create spawn points in your map pieces for the spikes to fit in. Then, when your player is falling, and the new map is loaded, grab the spawn points, add them to a list, choose one randomly, and then instantiate your spike there. Or get the map pieces themselves to spawn the spikes as they are loaded.
Method 1:
Create spawn points on your map piece. Create and add the following script. Place the spawn points in the list in inspector. And call function on Awake/Start.
using System.Collections;
using UnityEngine;
public class MapScript : MonoBehaviour
{
//Spike you want to instantiate
public GameObject spike;
//List for you to place spawn points in the inspector
public List<GameObject> Spawnpoints = new List<GameObject>();
public void Awake()
{
//Get a random number from 0 to our lists count
int random = Random.Range(0, Spawnpoints.Count);
//Instantiate at the random spawn point
GameObject SpikeIns = Instantiate(spike, Spawnpoints[random].transform.position, transform.rotation);
}
}
Method 2:
Similar to the example above, except the code to spawn happens in the Generator script (this is not the preferred method as we will have to access the map piece's script).
So use the code above but remove the Awake and spike GameObject, and then for your generator script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Generator : MonoBehaviour
{
public GameObject spike;
public float maxspeed;
public float minspeed;
public float currentspeed;
void Awake()
{
currentspeed = Random.Range(maxspeed, minspeed);
spikegen();
}
void Update()
{
}
void spikegen()
{
List<GameObject> Spawners = new List<GameObject>();
foreach(GameObject spawn in refernceToOtherScripts.Spawnpoints)
{
Spawners.Add(spawn);
}
int random = Random.Range(0, Spawners.Count);
GameObject SpikeIns = Instantiate(spike, Spawners[random].transform.position, transform.rotation);
}
}
Neither of these have been tested as I am on my work computer, but they should both work perfectly fine. As you have probably guessed, there are a lot of different way to go about this.
Related
I'm kinda new to unity, been spinning my head around it this couple of last days. I've encoutered a problem where when I'm spawning 2 or more players into my scene they just get launched out of the map. I've figured out that it's a problem with the spawn points. I did set up a range between some values where they will be spawned but seems that they still spawn into the same spot and get lauched across the map.
What I want to do is, create 4 spawnpoints(the maximum number of people that can play the game) in which they will get spawned based on the number of players.
I have a function called "SetPosition" with the code:
public void SetPosition()
{
transform.position = new Vector3(Random.Range(-1,11), 0.8f, Random.Range(-4,5));
}
and it is used here, if the scene is "Game"
private void Update()
{
if(SceneManager.GetActiveScene().name == "Game")
{
if(PlayerModel.activeSelf == false)
{
SetPosition();
PlayerModel.SetActive(true);
}
Any support is appreciated, been trying to find an answer but could find anything that would fit my need.
At early stage best solution will be create 4 empty game objects at the places where you want to keep spawn point.
Then take an array of Transform to store those in script and just pass the random index to get a point.
public Transform[] points;
public Vector3 GetRandomPoint()
{
return points[Random.Range(0,point.length)].position;
}
So I've done something. I've added 4 empty objects with a parent called "SpawnManager", also made a script for the spawn manager that is down below:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SpawnManager : MonoBehaviour
{
public static SpawnManager Instance;
Spawnpoint[] spawnpoints;
void Awake()
{
Instance = this;
spawnpoints = GetComponentsInChildren<Spawnpoint>();
}
public Transform GetSpawnPoint()
{
return spawnpoints[Random.Range(0, spawnpoints.Length)].transform;
}
}
In the PlayerModel script where I set the spawn position for the player I've added this function but it doesn't work. No errors, but it doesn't respect the spawnpoints
public void SetPosition()
{
Transform spawnpoint = SpawnManager.Instance.GetSpawnPoint();
transform.position = spawnpoint.position;
}
The SetPosition function was like this before I edited it:
public void SetPosition()
{
transform.position = new Vector3(Random.Range(-1,11), 0.8f, Random.Range(-4,5));
}
I'm making a 2D game and trying to make a characters move automatically when they spawn from the door to the desk or close to the sofa then stop there. the problem is that they don't collide with anything in the background like sofa or table or desk and they keep going trying to force move and going out of the canvas. this is a GIF for the game play and script that i'm using on the characters:
What am I supposed to do?
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CharacterConstantMove : MonoBehaviour
{
GameManager Game_Manager;
void Start()
{
GameObject gameController = GameObject.FindGameObjectWithTag("GameController");
Game_Manager = gameController.GetComponent<GameManager>();
}
void Update()
{
transform.Translate(Game_Manager.moveVector * Game_Manager.moveSpeed * Time.deltaTime);
}
}
GameManager.Cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class GameManager : MonoBehaviour
{
public float moveSpeed = 1.0f;
public Vector2 moveVector;
}
That's what happens when you translate the body in every frame. From an answer to this similar problem has been addressed, Transform is not a physics-based component. It's the position, rotation, and scale of the object. It doesn't interact with physics system on it's own. Rigidbody is a physics-based component that performs different kinds of physics interactions, like collisions, forces, and more.
Add a rigidbody component to your gameobject and set its velocity, it then interacts with the game physics.
private Rigidbody2D rb;
private void Awake() {
rb = GetComponent<Rigidbody2D>();
}
private void Update() {
rb.velocity = Game_Manager.moveVector * Game_Manager.moveSpeed;
}
I'm currently making a 3D endless runner game with the choice to select different skins for the player. Everything's going smoothly until I come across a problem, in which I try to assign two collision game objects to each character prefab in the container that can detect the player's collision box when it collides with a powerup.
It only detects the first playerContainer's (Milo) 'Coin Detect' game object (eventhough it's been deactivated) and does not recognize the 'Coin Detect' collision game object in the Baddie playerContainer (which the player has chosen to play)
So my question is, how am I able to get the script to recognize the child that's active in the third playerContainer game object instead of it automatically detecting the first playerContainer game object's child?
From the Magnet powerup script I've made, the script detects the first playerContainer's 'Coin Detect' game object only. As shown in the attached picture below:
Here's my current script where the player is able to select their preferred characters.
using System.Collections.Generic;
using UnityEngine;
public class EnablePlayerSelector : MonoBehaviour
{
public GameObject[] players;
public int currPlayerCount;
void Start()
{
currPlayerCount = PlayerPrefs.GetInt("SelectedPlayer", 0);
foreach (GameObject player in players)
player.SetActive(false);
players[currPlayerCount].SetActive(true);
}
}
and here's the script where I deactivate the 'Coin Detect' collision game Object and activate it when the player collides with the powerup.
using System.Collections.Generic;
using UnityEngine;
public class Magnet : MonoBehaviour
{
public GameObject coinDetect;
void Start()
{
coinDetect = GameObject.FindGameObjectWithTag("CoinDetect");
coinDetect.SetActive(false);
Debug.Log("False");
}
private void OnTriggerEnter(Collider other)
{
if(other.gameObject.tag == "Player")
{
StartCoroutine(coinActivate());
Destroy(transform.GetChild(0).gameObject);
}
}
IEnumerator coinActivate()
{
Debug.Log("Hi");
coinDetect.SetActive(true);
yield return new WaitForSeconds(5f);
coinDetect.SetActive(false);
}
}
Well your issue is rather that you are doing GameObject.FindGameObjectWithTag("CoinDetect") which will return whatever is the first encountered CoinDetect in your scene in this moment. So unless EnablePlayerSelector.Start is executed before the Magnet.Start it will always be the first one since they are still all active by then.
You could probably already solve your issue by following the general thumb-rule:
Do things where you do not depend on other components already in Awake
Do things where you o depend on other components in Start
This way you already cover most of the use cases and are sure that components are self-initialized (Awake) before anything is accessing them in Start.
So simply change the EnablePlayerSelector.Start into Awake and you should be fine.
In very specific cases you might still have to adjust the Script Execution Order or use events.
Instead of doing this at all though I would rather in the moment of the collision request the current one from the PlayerContainer directly:
// put this on each player root object
public class Player : MonoBehaviour
{
// reference these via the Inspector
[SerializeField] private GameObject coinDetector;
[SerializeField] private GameObject playerrange;
// ... and in general any information bout this Player that is relevant for other scripts
// Readonly accessor property
public GameObject CoinDetector => coinDetector;
}
and then rather have
public class EnablePlayerSelector : MonoBehaviour
{
[SerializeField] private Player[] players;
[SerializeField] private int currPlayerCount;
public Player CurrentPlayer => players[currPlayerCount];
// In general do things where you don't depend on other scripts already in Awake
// This way you could actually already solve your issue by keeping things where you do
// depend on others in Start
private void Awake()
{
currPlayerCount = PlayerPrefs.GetInt("SelectedPlayer", 0);
for(var i = 0; i < players.Length; i++)
{
players[i].gameObject.SetActive(i == currPlayerCount);
}
}
}
and then finally do e.g.
public class Magnet : MonoBehaviour
{
public float effectDuration = 5f;
private IEnumerator OnTriggerEnter(Collider other)
{
var playerSelector = other.GetComponentInParent<EnablePlayerSelector>();
if(!playerSelector) yield break;
Debug.Log("Hi");
Destroy(transform.GetChild(0).gameObject);
var coinDetect = playerSelector.CurrentPlayer.CoinDetector;
coinDetect.SetActive(true);
yield return new WaitForSeconds(effectDuration);
coinDetect.SetActive(false);
}
}
or alternatively if the other in this case refers to the object with the Player component anyway you could also directly do
public class Magnet : MonoBehaviour
{
public float effectDuration = 5f;
private IEnumerator OnTriggerEnter(Collider other)
{
if(!other.TryGetComponent<Player>(out var player)) yield break;
Debug.Log("Hi");
Destroy(transform.GetChild(0).gameObject);
var coinDetect = player.CoinDetector;
coinDetect.SetActive(true);
yield return new WaitForSeconds(effectDuration);
coinDetect.SetActive(false);
}
}
I am making a game and in the game im trying to make the enemy go towards the player when the player steps into the sight of the enemy. I cant figure out how to make the name (player) mean anything im very new at this its my second attempt on makin a game please help me im very confused im running c#
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Enemy : MonoBehaviour
{
private Transform _target;
[SerializeField] private float _speed = 9;
void Awake() {
_target = FindObjectOfType(Player)().transform;
}
void update() {
transform.position = Vector3.MoveTowards(transform.position,_target.position, _speed * Time.deltaTime);
}
}
You need to use the typeof operator instead of passing the class name.
void Awake() {
_target = FindObjectOfType(typeof(Player))().transform;
}
Is there a C# way in Unity to duplicate an existing GameObject and all of its children? In my case, I have an empty GameObject with a number of Text objects as children and I would like to create a copy of them all, including relative positions, text values, font, colors, etc....
Prefabs won't work easily because I want to copy the object including its current state.
The Instantiate function is used to clone any GameObject and its hierarchy.
public GameObject rootObj;
void Start()
{
GameObject duplicate = Instantiate(rootObj);
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class main : MonoBehaviour
{
public GameObject hk;
void Start()
{
hk = new GameObject("I am hk");
}
void Update()
{
hk = new GameObject("I am hk");
}
}