So I'm working on a project for class in which, using Unity3D, I'm instatiating fish game objects into a game and making them appear randomly across the background. Currently, I have this code that's supposed to make my critter appear. I wrote two scripts that are supposed to make my critter game objects appear on different sides of the screen
using UnityEngine;
using System.Collections;
public class Wrangler : MonoBehaviour {
public static float halfWidth = 6;
public static float halfHeight = 5;
public GameObject critterPrefab;
public GameObject crabPrefab;
int critterCount = 0; //how many we've made so far
int critterMax = 5; //how many you want
int crabCount = 0;
int crabMax = 5;
// how long between critter spawns
void Start()
{
StartCoroutine("SpawnCritter");
StartCoroutine("SpawnCrab");
}
IEnumerator SpawnCritter()
{
while (critterCount < critterMax)
{
CreateCritter();
yield return new WaitForSeconds(1.0f);
}
}
IEnumerator SpawnCrab()
{
while (crabCount < crabMax)
{
CreateCrab();
yield return new WaitForSeconds(1.0f);
}
}
void CreateCritter() {
critterCount++;
Instantiate(critterPrefab);
}
void CreateCrab() {
crabCount++;
Instantiate(crabPrefab);
}
}
using UnityEngine; //allows us to use objects and stuff from Unity Engine
using System.Collections;
//creates a class we can manipulate called "Critter" and allows it to do the
//same thing MonoBehavior does
public class Critter : MonoBehaviour {
//variables here are for the class to use and functions can use them any time
//It looks like you can create variables first, then create the functions
protected Rigidbody rb;
// Use this for initialization
public virtual void Start () {
float startX = Random.Range (-Wrangler.halfWidth, Wrangler.halfwidth);
float startY = Random.Range (-Wrangler.halfHeight, Wrangler.halfheight);
transform.position = new Vector2 (startX, startY);
rb = GetComponent<Rigidbody> ();// Functions make classes do stuff
setVelocity ();
}
public virtual void setVelocity() {
rb.velocity = new Vector2 (-1,0);
}
// Update is called once per frame
void Update () {
if (transform.position.x > Wrangler.halfWidth)
transform.position = new Vector2 (-Wrangler.halfWidth, transform.position.y);
if(transform.position.x < Wrangler.halfWidth)
transform.position = new Vector2 (Wrangler.halfWidth, transform.position.y);
if(transform.position.y > Wrangler.halfHeight)
transform.position = new Vector2 (-Wrangler.halfHeight, transform.position.y);
if(transform.position.y < Wrangler.halfHeight)
transform.position = new Vector22 (Wrangler.halfHeight, transform.position.y);
}
}
I keep getting compiler errors in Unity that say things like "Wrangler does not contain definition for "halfWidth" when I clearly define halfWidth = 6.
What do I do to add the definition and fix these errors?
C# is case sensitive.
In Critter code you use:
float startX = Random.Range (-Wrangler.halfWidth, Wrangler.halfwidth);
float startY = Random.Range (-Wrangler.halfHeight, Wrangler.halfheight);
In Wrangler, halfWidth and halfWidth are declared with capital W and H, but here you use halfwidth and halfheight.
About the error in the image - the Wrangler as you posted is correct and should compile, however pay attention that the error is about "CrabPrefab" and not "crabPrefab" as you declared it, so maybe in your local code you used capital CrabPrefab and CritterPrefab instead?
Just pay attention to the case of your variables.
Related
I'm currently developing a game in Unity and I ran into a small problem. I'm trying to generate a rainbow color effect that is similar to what happens when someone catches a star in mario kart or supermario on a specific gameobject. Essentially all the instances of the prefab attached to the script InteractControl that are active should get this effect (Either loop or lerp trough 5 different colors continusesly) while the variable timeLeft > 0 and the score > 10 and then go back to the original value of the color they had when timeLeft < 0.
Ive already tried multiple things including using a coroutine, and reseting the color inisde of it multiple times. Creating a new method and allowing acces to it only if a bool whom's value is set within the timeleft > 0 if statement is true, or currently trying to lerp the color however this all doesnt seem the work. Trying to make an animation could also be an option however its too complicated to make the objects of different colours match the same dimensions as the original I have so I really want to make it change trough the script.
These are the relevant parts of the script in question:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class InteractControl : MonoBehaviour, IPooledObject
{
public Transform[] spawnPoints;
public Color[] _colors;
private float t = 0.2f;
private Rigidbody2D rb;
GameObject target;
Vector3 directionToTarget;
public static int LevelStart = 0;
public static float moveSpeed = 5f;
public static bool isSlowMotion = true;
public static float timeLeft = 12f;
private float randomSpawnTime;
private int Spawn = 1;
private float scaledTime;
private Color oldColor;
private Color newColor;
private float newT;
private void Start()
{
scaledTime = Mathf.Sin(t) * (float)(5 - 1);
oldColor = _colors[(int)scaledTime];
newColor = _colors[(int)(scaledTime + 1f)];
newT = scaledTime - Mathf.Round(scaledTime);
}
public void OnObjectSpawn()
{
target = GameObject.FindWithTag("White Ball");
rb = GetComponent<Rigidbody2D>();
}
void Update()
{
if (target != null)
{
if (ScoreScript.scoreValue > 10)
{
timeLeft -= Time.deltaTime;
if (timeLeft > 0)
{
directionToTarget = (target.transform.position - transform.position).normalized;
rb.velocity = new Vector2(directionToTarget.x * moveSpeed,
directionToTarget.y * moveSpeed);
GetComponent<Renderer>().material.color = Color.Lerp(oldColor, newColor, 5f);
if (Spawn == 1)
{
randomSpawnTime = Random.Range(2, 8);
Spawn++;
}
if (timeLeft < randomSpawnTime && Spawn <= 2)
{
BallSpawnerControl.ClockSpawn = true;
}
}
if (timeLeft < 0)
{
GameObject[] gos = GameObject.FindGameObjectsWithTag("ColouredBall Highress");
foreach (GameObject go in gos)
{
go.SetActive(false);
}
BallSpawnerControl.HeartSpawn = true;
}
}
}
}
}
In the vertical game, I am creating random blocks spawn within a 100f. I am randomly creating 3 different types of objects which are 'platforms' 'boostplatforms' and 'breakableplatforms'. My code for generating all of these give no errors and when I run the game the blocks generated when I check the activity however visually only the objects named 'platform' appear.
The coding I used for this was:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class LevelGenerator : MonoBehaviour {
public GameObject platformPrefab;
public GameObject platformPrefab2;
public GameObject platformPrefab3;
public int numberOfPlatforms = 999;
public int numberOfBoostPlatforms = 999;
public int numberOfBreakablePlatforms = 999;
public float levelWidth = 100f;
public float minY = 55f;
public float maxY = 120f;
// Use this for initialization
void Start () {
Vector3 startPosition = new Vector3 ();
for (int i = 0; i < numberOfPlatforms; i++)
{
startPosition.y += Random.Range (minY, maxY);
startPosition.x = Random.Range (-levelWidth, levelWidth);
Instantiate (platformPrefab, startPosition, Quaternion.identity);
}
for (int i = 0; i < numberOfBoostPlatforms; i++)
{
startPosition.y += Random.Range (minY, maxY);
startPosition.x = Random.Range (-levelWidth, levelWidth);
Instantiate (platformPrefab2, startPosition, Quaternion.identity);
}
for (int i = 0; i < numberOfBreakablePlatforms; i++)
{
startPosition.y += Random.Range (minY, maxY);
startPosition.x = Random.Range (-levelWidth, levelWidth);
Instantiate (platformPrefab3, startPosition, Quaternion.identity);
}
}
// Update is called once per frame
void Update () {
}
}
Based on the information provided, I would recommend the following:
Verify that your prefab variables are set to the correct prefabs.
Notice that each platform's Y position is cumulative. Verify that the boost and break platforms aren't simply spawning after all of the standard platforms (which they will be based on your code).
Switch to object pooling. You are spawning 3,000 objects in a single frame even though the majority won't even be visible. The idea would be to spawn a small pool, 10 of each let's say, and when a new platform is needed (coming into view) you recycle one of the existing objects that is no longer visible or needed. Unity's Object Pooling tutorial
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'm using an Array to multiply a 3D object randomly in the space, so i'm getting a lot of nice objects floating randomly over the y, x and z axes.
This object has also an Audio Source with a sound attached to it, which means that after applying the random-array-positioning I get different objects with different Audio Sources as well.
The problem is that I'm also changing the scale of those objects, which it's working super well, but the size/scale/radius of the Audio Source it's not changing at all.
How can I change the scale of the objects and change the size/scale/radius of the Audio Source at the same time, to match both equally or proportionally in size?
I'm looking here but I Can't figured out.
https://docs.unity3d.com/ScriptReference/AudioSource.html
This is the code that I'm using for:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class multipleObjectsGrandes : MonoBehaviour {
public GameObject prefabGrandes;
public GameObject[] gos;
public int cantidad;
public float minScaleObj;
public float maxScaleObj;
void Awake()
{
gos = new GameObject[cantidad];
for(int i = 0; i < gos.Length; i++)
{
//Position
Vector3 position = new Vector3(Random.Range(-40.0f, 40.0f), Random.Range(-40.0f, 40.0f), Random.Range(-40.0f, 40.0f));
GameObject clone = (GameObject)Instantiate(prefabGrandes, position, Quaternion.identity);
//Scale
clone.transform.localScale = Vector3.one * Random.Range(minScaleObj, maxScaleObj);
//Rotation
clone.transform.rotation = Quaternion.Euler(Random.Range(0.0f, 360.0f), Random.Range(0.0f, 360.0f), Random.Range(0.0f, 360.0f));
gos[i] = clone;
}
}
}
This is the code that i'm using to multiply objects:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class multipleObjectsGrandes : MonoBehaviour
{
public GameObject prefabGrandes;
public GameObject[] cuerpos;
public int cantidad;
public float minScaleObj;
public float maxScaleObj;
public float escalaMax;
void Awake ()
{
cuerpos = new GameObject[cantidad];
for (int i = 0; i < cuerpos.Length; i++) {
//Position
Vector3 position = new Vector3 (Random.Range (-40.0f, 40.0f), Random.Range (-40.0f, 40.0f), Random.Range (-40.0f, 40.0f));
GameObject clone = (GameObject)Instantiate (prefabGrandes, position, Quaternion.identity);
//Scale
clone.transform.localScale = Vector3.one * Random.Range (minScaleObj, maxScaleObj);
//Rotation
clone.transform.rotation = Quaternion.Euler (Random.Range (0.0f, 360.0f), Random.Range (0.0f, 360.0f), Random.Range (0.0f, 360.0f));
escalaMax = clone.transform.localScale.x;
//Debug.Log(escalaMax);
}
}
}
Everything is ok here when I'm debugging "escalaMax" in the console.
The variable "escalaMax" is the one that i'm passing to the other script which is inside the object that I'm multiplying which has an audioSource attached to it. This is the script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[RequireComponent (typeof(AudioSource))]
public class AudioRandomPitch : MonoBehaviour
{
public float startingPitch = 1;
public float minPitchRandom = 0;
public float maxPitchRandom = 0;
AudioSource audio;
public float audioScale;
void Start ()
{
startingPitch = Random.Range (minPitchRandom, maxPitchRandom);
audio = GetComponent<AudioSource> ();
audio.pitch = startingPitch;
GameObject theMultiplicator = GameObject.Find ("Multiplicador_deCuerpos");
multipleObjectsGrandes multiplicatorScript = theMultiplicator.GetComponent<multipleObjectsGrandes> ();
multiplicatorScript.escalaMax = audioScale;
//this is not working
audio.maxDistance = audioScale;
Debug.Log(audioScale);
}
}
Here I'm first saving the value coming from the other script escalaMax inside the new variable audioScale.
The problem now is when I try to pass the audioScale value to the audio.maxDistance var.
I'm super close I know, but as you can see, i'm not a really good programmer and I'm probably doing something stupidly wrong... :/
Thanks for the help!
I know that the topic of the question has been already asked and some answer have been given to it, but i'm asking it again because i fail misserably when i try to apply the answers from the other topics.
The problem that i have is that, i have a prefab (quad) 'Star' with a material into it and an script that makes it change color after some time:
using UnityEngine;
public class Star: MonoBehaviour {
public enum StarType {
BRIGHT,
DARK,
F,
K,
L,
P
}
private Ship ship;
private StarType starType;
private float timeLimit = .30f, timer;
private System.Random rand;
public void Awake() {
ship = FindObjectOfType<Ship>();
timer = .0f;
rand = new System.Random();
}
public void Start() {
refactor();
}
public void Update() {
timer += Time.deltaTime;
if(timer > timeLimit) {
refactor();
timer = .0f;
}
}
public void LateUpdate() {
transform.eulerAngles = new Vector3(ship.transform.eulerAngles.x,
ship.transform.eulerAngles.y,
ship.transform.eulerAngles.z);
}
public void refactor() {
starType = (StarType) rand.Next(0,
System.Enum.GetValues(typeof(StarType)).Length);
switch(starType ) {
case StarType.BRIGHT:
renderer.material.color = Color.white;
break;
case StarType.DARK:
renderer.material.color = Color.black;
break;
case StarType.F:
renderer.material.color = Color.red;
break;
case StarType.K:
renderer.material.color = Color.cyan;
break;
case StarType.L:
renderer.material.color = Color.green;
break;
case StarType.P:
renderer.material.color = Color.magenta;
break;
}
}
public StarType getStarType() {
return starType;
}
}
And this stars being instantiated in a Chunk class:
public class Chunk : MonoBehaviour {
public Star star;
private IList<Star> stars;
public void Awake() {
stars = new List<Star>();
Star auxStar = (Star) Instantiate(star, transform.position,
Quaternion.identity);
auxStar.transform.SetParent(transform);
stars.Add(auxStar);
}
}
I was assuming that each star would change the color independently, but instead of that they all change to the same color.
I've tried using sharedMaterial instead of material as i read it on some asnwers, though the result and behaviour seems the same?, and i tried giving random init colors to the stars, but the most that i get is having a few of them changing to a color different from the rest, though still the same between them (And i'm trying to change colors all the time, not only upon creation).
I've read too creating a material and asigning to each one at instantiating, but i had no luck:
auxStar.renderer.material = (Material)
Instantiate(star.renderer.material);
Does someone know how can the problem be handled?
According to Unity API reference, you are doing the right thing.
The issue in your code is that you are instantiating a MonoBehaviour
public Star star;
...
Star auxStar = (Star) Instantiate(star, transform.position, Quaternion.identity);
where star is a MonoBehaviour, you are not instantiating the actual GameObject with the Mesh Render and/or Material. Instead make sure you are instantiating the right GameObject Prefab, not just the component, like this:
public GameObject starPrefab;
...
GameObject starClone = (GameObject) Instantiate (starPrefab);
Star auxStar = starClone.GetComponent<Star> ();
In that way you have control of the GameObject, if you need, and every component associated with the Cloned Object, in this case Star. You don't have to instantiate the Prefab Material cause it will be already instantiated.
Here is a simple Example:
using UnityEngine;
using System.Collections;
public class SpawnStar : MonoBehaviour {
public GameObject StarPrefab;
public bool InstantiateStar = false;
void Update () {
if (InstantiateStar) {
GameObject starClone = (GameObject)Instantiate (StarPrefab);
float r = Random.Range (0f, 1f);
float g = Random.Range (0f, 1f);
float b = Random.Range (0f, 1f);
float a = Random.Range (0f, 1f);
starClone.renderer.material.color = new Color (r, g, b, a);
InstantiateStar = false;
}
}
}
Side Note: Make sure to not modify the Prefab during gameplay since is the source of all other cloned objects.
Try using Random.Range() As in System.Random is generated by system time. As we know that Time is not Really Random. It still depends on mil sec times and generate the the logic of Random as we can't really tell which mil sec the random will run.
Since System.Random runs on 1 timeline which your scripts are using. Random.Range() is a bet you can consider since it uses SystemTime and independent time On Run of the platform. Shares with Time.DeltaTime.