Sorting Order Not Working Correctly - unity3d

I am trying to change the order of a sorting layer in unity for a 2D game but the below script isn't working for me:
using UnityEngine;
using System.Collections;
public class LevelManager : MonoBehaviour {
public GameObject player;
public SpriteRenderer deadGuy;
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
if (player.transform.position.y < deadGuy.transform.position.y)
{
deadGuy.sortingOrder = 0;
} else
{
deadGuy.sortingOrder = 2;
}
}
}
The objects have been linked in the inspector window unity before running the game.
EDIT
This is now my code:
using UnityEngine;
using System.Collections;
public class LevelManager : MonoBehaviour {
public GameObject player;
public GameObject deadGuy;
public bool belowTheY;
// Use this for initialization
void Start () {
deadGuy.GetComponent<SpriteRenderer>().sortingOrder = 2;
}
// Update is called once per frame
void Update () {
if (player.transform.localPosition.y < deadGuy.transform.localPosition.y)
{
belowTheY = true;
deadGuy.GetComponent<SpriteRenderer>().sortingOrder = 0;
} else
{
belowTheY = false;
deadGuy.GetComponent<SpriteRenderer>().sortingOrder = 2;
}
}
}
bekowTheY is activating if the user goes below deadGuy's Y position so I know the if statement is executing correctly. However the sorting layer is not being changed

It seems that the player object was on sorting order 0 also, so when the deadGuy object was scripted to go to sorting order 0, it was still showing in front due to taking precedence.

Related

Display 10 separate Meshes one by one with looping behavior to create "Animation" for empty GameObject?

I have 10 meshes that are each basically freeze-"frames" of an animation of a whale swimming.
If I were to loop through displaying these meshes then it would create a pseudo-animation, which is what I want.
How can this be achieved? Currently I have GameObject AnimTest, and I've placed the 10 mesh .obj files as children to it. I've started with this code on a script changeMeshes for the GameObject:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class changeMeshes : MonoBehaviour
{
//Create array of the meshes
public float[] currentMesh;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
for (int i = 0; i < 10; i++)
{
currentMesh[i].gameObject.GetComponent<MeshRenderer>().enabled = true;
}
}
}
This is obviously very wrong since I'm new and confused, so I'm getting errors with script like float does not contain a definition for gameObject. Can anyone help lead me down the correct path?
Edit: Here's my better try at it.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class changeMeshes : MonoBehaviour
{
//Create array of the meshes
public GameObject[] whaleMeshes;
void FindWhales()
{
whaleMeshes = GameObject.FindGameObjectsWithTag("WhaleMesh");
print(whaleMeshes.Length);
}
void CycleWhales()
{
for (int i = 0; i < whaleMeshes.Length; i++)
{
if (i > 0)
{
whaleMeshes[i - 1].gameObject.GetComponentInChildren<MeshRenderer>().enabled = false;
}
whaleMeshes[i].gameObject.GetComponentInChildren<MeshRenderer>().enabled = true;
}
}
// Start is called before the first frame update
void Start()
{
FindWhales();
}
// Update is called once per frame
void Update()
{
CycleWhales();
}
}
The result now is that only the last Mesh is permanently rendered, rather than the script cycling through the meshes on a loop. How do I get the meshes to loop?
Well .. a float has no property .gameObject .. not even Mesh would
Since you say the objects are children of this component you can simply iterate through them.
And then I would simply activate and deactivate the entire GameObject.
Sounds like what you would want to do is something like
public class changeMeshes : MonoBehaviour
{
// How long should one mesh be visible before switching to the next one
[SerializeField] private float timePerMesh = 0.2f;
public UnityEvent whenDone;
private IEnumerator Start()
{
// Get amount of direct children of this object
var childCount = transform.childCount;
// Get the first child
var currentChild = transform.GetChild(0);
// Iterate through all direct children
foreach(Transform child in transform)
{
// Set all objects except the first child to inactive
child.gameObject.SetActive(child == currentChild);
}
// Iterate though the rest of direct children
for(var i = 1; i < childCount; i++)
{
// Wait for timePerMesh seconds
yield return new WaitForSeconds(timePerMesh);
// Set the current child to inactive
currentChild.gameObject.SetActive(false);
// Get the next child
currentChild = transform.GetChild(i);
// Set this one to active
currentChild.gameObject.SetActive(true);
}
// Optionally do something when done like e.g. destroy this GameObject etc
yield return new WaitForSeconds(timePerMesh);
whenDone.Invoke();
}
}

Control object rotation by mouse click in unity

I need help with my project in unity
I want to stop each object by clicking on it.
What I did so far:
all my objects rotate but when I click anywhere they all stop, I need them to stop only if I click on each one.
This is my code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class EarthScript : MonoBehaviour
{
public bool rotateObject = true;
public GameObject MyCenter;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
if (Input.GetMouseButtonDown(0))
{
if(rotateObject == true)
{
rotateObject = false;
}
else
{
rotateObject = true;
}
}
if(rotateObject == true)
{
Vector3 axisofRotation = new Vector3(0,1,0);
transform.RotateAround(MyCenter.transform.position,axisofRotation, 30*Time.deltaTime);
transform.Rotate(0,Time.deltaTime*30,0,Space.Self);
}
}
}
Theres two good ways to achieve this. Both ways require you to have a collider attatched to your object.
One is to raycast from the camera, through the cursor, into the scene, to check which object is currently under the cursor.
The second way is using unity's EventSystem. You will need to attach a PhysicsRaycaster on your camera, but then you get callbacks from the event system which simplifies detection (it is handled by Unity so there is less to write)
using UnityEngine;
using UnityEngine.EventSystems;
public class myClass: MonoBehaviour, IPointerClickHandler
{
public GameObject MyCenter;
public void OnPointerClick (PointerEventData e)
{
rotateObject=!rotateObject;
}
void Update()
{
if(rotateObject == true)
{
Vector3 axisofRotation = new Vector3(0,1,0);
transform.RotateAround(MyCenter.transform.position,axisofRotation, 30*Time.deltaTime);
transform.Rotate(0,Time.deltaTime*30,0,Space.Self);
}
}

OnCollisionEnter in unity won't call function

I'm a complete unity novice. I want to make a simple scene where you have three lives and you lose a live if you collide with a cube. This is my script:
using UnityEngine;
using UnityEngine.UI;
using System.Collections;
public class Lives : MonoBehaviour {
public Transform player;
public static int lives;
public Image live1;
public Image live2;
public Image live3;
// Use this for initialization
void Start () {
lives = 3;
live1.enabled = true;
live2.enabled = true;
live3.enabled = true;
}
void Update () {
DisplayOfHearts();
}
public static void Damage() {
lives -= 1;
}
public void OnCollisionEnter(Collision col) {
if (col.gameObject.tag == "cube") {
Lives.Damage();
}
}
public void DisplayOfHearts() {
if (lives == 2) {
live3.enabled = false;
}
else if (lives == 1) {
live2.enabled = false;
}
else if (lives == 0) {
live1.enabled = false;
}
}
}
What happens is the player can't move through the cube but the amount of lives stays three. Is there something I'm missing?
The problem is you have attached the script to a wrong game object. The script and the collider must be attached to the same game object.
Unity methods inside a MonoBehaviour script (such as OnEnable, Update, FixedUpdate, Awake, Start, OnTriggerEnter, OnCollisionStay, etc..) only work for the game object which the script is attached to.
If you attach the script to another game object don't expect any of those to work. Update only works while that game object is active. OnCollisionEnter only works when a collision occurs on a collider which is attached directly to that game object. (it doesn't even work when a child has the collider instead of the actual game object where script is attached to)

Unity 2D - How to place obstacle in Running game?

I finish making running game. But I placed obstacle like this :
This way makes phone frozen often. So I make a prefeb is made of obstacle object like this :
I want to use function SetActive(bool) to appear/disappear obstacle. Finally, How it works is My runner is at a standstill and background, obstacle, coin, juwel is moved. But My creator script has a big problem.
My Prolem :
As you see, This code create blank(red box) between two obstacle prefebs. I can't find problem. Plz help me...
Creator Script :
using UnityEngine;
using System.Collections;
public class CsPartCreator : MonoBehaviour {
int count = 1;
float timer = 0.0f;
// Use this for initialization
void Start () {
for (int i = 1; i < 26; i++)//set Deactive all object excluding first object (Because This object is watched at first.)
transform.GetChild(i).gameObject.SetActive(false);
}
// Update is called once per frame
void Update () {
timer += Time.deltaTime;
if (timer > 5f && count < 23)//every 5 seconds and count is smaller than the number of prefeb
{
transform.GetChild(count).gameObject.SetActive(true);//
count++;
timer = 0;
}
}
}
This is my Hierarchy :
I think , That missing prefab's Z value is more negative than background , Or you have used a sorting layer which is set to be behind background.
And Check if all obstacle gameobjects correctly orderered in Hirachy Part0, Part1, Part2, Part3 like that. Let me know if those are in correct order
Please check that :)
using UnityEngine;
using System.Collections;
using System.Linq;
using System.Collections.Generic;
public class CsPartCreator : MonoBehaviour
{
private GameObject player;
float timer = 0.0f;
private List<GameObject> obstacles;
void Awake()
{
player = GameObject.FindWithTag("Player");
obstacles = new List<GameObject>();
}
// Use this for initialization
void Start()
{
for (int i = 0; i < 26; i++)//set Deactive all object excluding first object (Because This object is watched at first.)
{
obstacles.Add(transform.GetChild(i).gameObject);
transform.GetChild(i).gameObject.SetActive(false);
}
}
// Update is called once per frame
void Update()
{
if (obstacles == null || obstacles.Count() == 0)
return;
var toActivate = obstacles.Where(x => x.transform.position.x > transform.position.x && x.transform.position.x < transform.position.x + 10).ToList(); // +10 is the range
foreach (GameObject go in toActivate)
{
go.SetActive(true);
obstacles.Remove(go);
}
}
}
Set player gameobject to "Player" tag as in image below

Unity prefab issues

I have created a prefab of a Terrain.
I pass it on to script where it gets instantiated (hundreds of times).
The problem is that the prefab itself gets changed with every instantiation. (its name and its translation).
How do I prevent this?
Sample code :
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class LandCrafter : MonoBehaviour {
public Terrain parentPiece;
public Terrain randomPiece;
void Start () {
for (int i = 0; i<=maxLandBlocks; i++) {
if (currentPlacedBlocks.Count <= maxLandBlocks) {
pieceList = GameObject.FindGameObjectsWithTag ("randomTerrainPiece");
LandCraft ();
} else {
randomPiece.name = "randomPieceOfLand";
charCraft ();
}
}
}
void LandCraft(){
someExistingLandPiece = (GameObject)pieceList [(int)Random.Range(0.0f,pieceList.Length)];
test = someExistingLandPiece.transform.position;
if (!currentPlacedBlocks.Contains (someExistingLandPiece.transform.position + Vector3.forward)) {
Instantiate (randomPiece);
randomPiece.name = "The" + i++;
randomPiece.transform.position = someExistingLandPiece.transform.position + Vector3.forward;
currentPlacedBlocks.Add (randomPiece.transform.position);
}
}
Turns out, you actually have to instantiate the prefab and "feed" that instance to the script. If you feed the prefab directly, everything you do automatically applies to it..