Instance object does not work properly with animator in Unity 3d - unity3d

I am making games using Unity and I have some problems and I will ask questions.
The animator of an object instantiated using a prefab does not work properly, and precisely a specific event is a problem. The object placed in the hierarchy is fine. However, certain events do not work for objects instantiated using a script.
this is code.
public Animator guestmove;
public void Jump_motion()
{
if (tag == "Boy")
{
guestmove.SetTrigger("Jump");
}
}
public void Angry_motion()
{
guestmove.SetTrigger("Angry");
}
Here, we implement the event by pressing a button.
I changed the code to work when the tags match, but the objects I placed in the hierarchy also do not work.
This is the code that creates the instance.
if (currentlyObject > 0){
boyObject = Instantiate(boy, tableObject.transform.position, tableObject.transform.rotation);
boyObject.transform.Translate(new Vector3(0, -3, -11));
girlObject = Instantiate(girl, tableObject.transform.position, tableObject.transform.rotation);
girlObject.transform.Translate(new Vector3(1.5f, -3, -11));
}
I kept searching for the relevant data, but I could not find any cases of similar problems. I do not know where the problem is, please help me.
this is link
(https://drive.google.com/file/d/1SKbSIfFQM4-n8l-ZBBvZb_3SuNx-kd5-/view?usp=sharing)

Use the transition to triggers from Any State, this should work.
And where are your functions called?

Related

Unity3D New Input System: Is it really so hard to stop UI clickthroughs (or figure out if cursor is over a UI object)?

Even the official documentation has borderline insane recommendations to solve what is probably one of the most common UI/3D interaction issues:
If I click while the cursor is over a UI button, both the button (via the graphics raycaster) and the 3D world (via the physics raycaster) will receive the event.
The official manual:
https://docs.unity3d.com/Packages/com.unity.inputsystem#1.2/manual/UISupport.html#handling-ambiguities-for-pointer-type-input essentially says "how about you design your game so you don't need 3D and UI at the same time?".
I cannot believe this is not a solved problem. But everything I've tried failed. EventSystem.current.currentSelectedGameObject is sticky, not hover. PointerData is protected and thus not accessible (and one guy offered a workaround via deriving your own class from Standalone Input Module to get around that, but that workaround apparently doesn't work anymore). The old IsPointerOverGameObject throws a warning if you query it in the callback and is always true if you query it in Update().
That's all just mental. Please someone tell me there's a simple, obvious solution to this common, trivial problem that I'm just missing. The graphics raycaster certainly stores somewhere if it's over a UI element, right? Please?
I've looked into this a fair bit and in the end, the easiest solution seems to be to do what the manual says and put it in the Update function.
bool pointerOverUI = false;
void Update()
{
pointerOverUI = EventSystem.current.IsPointerOverGameObject();
}
Your frustration is well founded: there are NO examples of making UI work with NewInput which I've found. I can share a more robust version of the Raycaster workaround, from Youtube:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.InputSystem;
using UnityEngine.UI;
/* Danndx 2021 (youtube.com/danndx)
From video: youtu.be/7h1cnGggY2M
thanks - delete me! :) */
public class SCR_UiInteraction : MonoBehaviour
{
public GameObject ui_canvas;
GraphicRaycaster ui_raycaster;
PointerEventData click_data;
List<RaycastResult> click_results;
void Start()
{
ui_raycaster = ui_canvas.GetComponent<GraphicRaycaster>();
click_data = new PointerEventData(EventSystem.current);
click_results = new List<RaycastResult>();
}
void Update()
{
// use isPressed if you wish to ray cast every frame:
//if(Mouse.current.leftButton.isPressed)
// use wasReleasedThisFrame if you wish to ray cast just once per click:
if(Mouse.current.leftButton.wasReleasedThisFrame)
{
GetUiElementsClicked();
}
}
void GetUiElementsClicked()
{
/** Get all the UI elements clicked, using the current mouse position and raycasting. **/
click_data.position = Mouse.current.position.ReadValue();
click_results.Clear();
ui_raycaster.Raycast(click_data, click_results);
foreach(RaycastResult result in click_results)
{
GameObject ui_element = result.gameObject;
Debug.Log(ui_element.name);
}
}
}
So, just drop into my "Menusscript.cs"?
But as a pattern, this is terrible for separating UI concerns. I'm currently rewiring EVERY separately-concerned PointerEventData click I had already working, and my question is, Why? I can't even find how it's supposed to work: to your point there IS no official guide at all around clicking UI, and it does NOT just drop-on-top.
Anyway, I haven't found anything yet which makes new input work easily on UI, and definitely not found how I'm going to sensibly separate Menuclicks from Activityclicks while keeping game & ui assemblies separate.
Good luck to us all.
Unity documentation for this issue with regard to Unity.InputSystem can be found at https://docs.unity3d.com/Packages/com.unity.inputsystem#1.3/manual/UISupport.html#handling-ambiguities-for-pointer-type-input.
IsPointerOverGameObject() can always return true if the extent of your canvas covers the camera's entire field of view.
For clarity, here is the solution which I found worked best (accumulated from several other posts across the web).
Attach this script to your UI Canvas object:
public class CanvasHitDetector : MonoBehaviour {
private GraphicRaycaster _graphicRaycaster;
private void Start()
{
// This instance is needed to compare between UI interactions and
// game interactions with the mouse.
_graphicRaycaster = GetComponent<GraphicRaycaster>();
}
public bool IsPointerOverUI()
{
// Obtain the current mouse position.
var mousePosition = Mouse.current.position.ReadValue();
// Create a pointer event data structure with the current mouse position.
var pointerEventData = new PointerEventData(EventSystem.current);
pointerEventData.position = mousePosition;
// Use the GraphicRaycaster instance to determine how many UI items
// the pointer event hits. If this value is greater-than zero, skip
// further processing.
var results = new List<RaycastResult>();
_graphicRaycaster.Raycast(pointerEventData, results);
return results.Count > 0;
}
}
In class containing the method which is handling the mouse clicks, obtain the reference to the Canvas UI either using GameObject.Find() or a public exposed variable, and call IsPointerOverUI() to filter clicks when over UI.
Reply to #Milad Qasemi's answer
From the docs you have attached in your answer, I have tried the following to check if the user clicked on a UI element or not.
// gets called in the Update method
if(Input.GetMouseButton(0) {
int layerMask = 1 << 5;
// raycast in the UI layer
RaycastHit2D hit = Physics2D.Raycast(Camera.main.ScreenToWorldPoint(Input.mousePosition), Vector2.zero, Mathf.Infinity, layerMask);
// if the ray hit any UI element, return
// don't handle player movement
if (hit.collider) { return; }
Debug.Log("Touched not on UI");
playerController.HandlePlayerMovement(x);
}
The raycast doesn't seem to detect collisions on UI elements. Below is a picture of the Graphics Raycaster component of the Canvas:
Reply to #Lowelltech
Your solution worked for me except that instead of Mouse I used Touchscreen
// Obtain the current touch position.
var pointerPosition = Touchscreen.current.position.ReadValue();
An InputSytem is a way to receive new inputs provided by Unity. You can't use existing scripts there, and you'll run into problems like the original questioner. Answers with code like "if(Input.GetMouseButton(0)" are invalid because they use the old system.

Destroy specific child object of prefab object in c# / Unity

I search a lot but couldn't find any answer. My problem: I instantiate several Gameobjects of a Prefab, each consists of two child objects: an obstacle and a scorezone. I want to destroy the scorezone (only of that specific instance), when the player touches the obstacle. So in Runtime my hierarchy looks like this:
-ObjectPrefab(clone)
---Scorezone
---Obstacle
-ObjectPrefab(Clone)
---Scorezone
---Obstacle
...
So I need to find ONE child gameobject (not the Transform) to then destroy it. I tried several codes but none worked. Here is the code with the three alternatives I tried, but none of them worked.:
private void OnCollisionEnter2D(Collision2D collision) {
if (collision.gameObject.tag == "obstacle") {
Alternative 1:
Destroy(GameObject.FindWithTag("scorezone"));
Alternative 1 comes really close, but it destroys all scorezones of all instantiated objects.
Alternative 2:
Destroy(collision.gameObject.transform.parent.gameObject.FindWithTag("scorezone"));
Alternative 2 would sound logic to me but I get the error message "Transform does not contain a definition for "FindWithTag".
Alternative 3:
foreach (Transform child in collision.gameObject.transform)
{
if (child.tag == "scorezone")
{
Destroy(child.gameObject);
}
}
}
Alternative 3 does not give an error but actually does nothing at all when the player hits the obstacle.
I really appreciate some help, thanks in advance!
Store the reference!
If it is really a "prefab" so meaning you have it as an asset and instantiate it on runtime the best way (in my eyes and performance wise) would actually be to use a serialized field:
// Put this component on your obstacle
public class ObjectController : MonoBehaviour
{
// Drag the according object here via the Inspector in the prefab
// => when the prefab is Instantiated this field is already referenced
[SerializeField] private GameObject _scoreZone;
// Read-only access to the reference
public GameObject ScoreZone => _scoreZone;
}
This field reference is stored together with your prefab asset. So every instance of the prefab already has its own child references set up.
and then do
private void OnCollisionEnter2D(Collision2D collision)
{
// Rather use CompareTag which is slightly more efficient
// and adds some security (== silently fails if typo, CompareTag throws an exception instead)
if (collision.gameObject.CompareTag("obstacle"))
{
var controller = collision.gameObject.GetComponent<ObjectController>();
if(controller)
{
Destroy(controller.ScoreZone);
}
}
}
By Index
Alternatively but error prone you could simply use the index. You already know that there are only 2 childs, the first one being the Scorezone with index 0 so you can also do
if (collision.gameObject.CompareTag("obstacle"))
{
var scoreZone = collision.transform.parent.GetChild(0);
Destroy(scoreZone);
}
By Name
Using the name you could also use Find - I would not recommend this! It is error prone and slow
if (collision.gameObject.CompareTag("obstacle"))
{
var scoreZone = collision.transform.parent.Find("ScoreZone");
Destroy(scoreZone);
}

Unity3D: Custom UnityEvent AddListener not firing

I have my own custom UnityEvent and am trying to add a listener.
I have used AddListener on numerous other UI objects, such as buttons, dropdowns, toggles, etc. so I understand the process. However, when I Invoke my UnityEvent, it simply doesn't fire.
I'm receiving no error messages, and after doing reading and research, everything looks correct. So, not sure what to do further.
This is an object that emits when it's rotated.
This is the basics of my code:
using UnityEngine.Events;
public class Rotator: MonoBehaviour
{
public UnityEvent OnRotate;
int angle = 0;
int newAngle = 0;
void Start()
{
OnRotate = new UnityEvent();
}
void Update()
{
newAngle = (int)transform.rotation.eulersAngles.z;
if (newAngle != angle)
{
print ("Actual Instance ID: " + GetInstanceID());
print ("Invoking!");
OnRotate.Invoke();
angle = newAngle;
}
}
}
and
public class Owner: MonoBehaviour
{
public Rotator rotator;
void Start()
{
print ("Rotator Instance ID: " + rotator.GetInstanceID());
rotator.OnRotate.AddListener(
() => UpdateRotation()
);
}
void UpdateRotation()
{
print ("Invoked!");
}
}
When the Rotator has it's angle changed, I get this in the console:
Actual Instance ID: 11234
Rotator Instance ID: 11234
Invoking!
The instance ID is to make sure I'm working with the same objects and not going in circles for nothing. They match, so I'm listening to the object that's firing.
However, the listener isn't firing. I've tried different combinations with delegates, etc. but it's all the same. No errors. It just doesn't invoke.
Obviously, I'm doing something wrong, but what is it?
Thanks for any help.
Somehow your answered your new edited version of the question with exactly the code you previously provided in the First Version of your Question!
As I tried to tell you ... if you anywhere in your code do OnRotate = new UnityEvent() of course you thereby erase any persistent callbacks and any runtime callbacks added before that moment!
In short
Simply leave it as
public UnityEvent OnRotate;
and you don't even have to think about it anymore.
For understanding why it also works if you put it in Awake please simply have a look at the Order of Execution for Event Functions
&rightarrow; First Awake and OnEnabled is called for every GameObject/Component. Then all Start methods are called as soon as the GameObject/Component is active.
Within each of these blocks (Awake + OnEnable) and (Start) the order of execution between different component types is not guaranteed unless you explicitly configure it via the Script Execution Order Settings where you could define that Owner is simply run before Rotator .. then having both in Start would also work again.
Why does it also work if you do it on the public field?
&rightarrow; Because this field is serialized. That means it is initialized automatically in the Inspector and then stored together with the Scene or prefab asset including any persistent callbacks.
And then Later Unity re-uses the serialized Version of the field so actually you can completely remove the new UnityEvent(); since it doesn't have any effect on a serialized field! It will always be initialized automatically anyway!
Ok, I found out what the issue was.
My question now is "why?".
I changed my code from:
public UnityEvent OnRotate;
void Start() {
OnRotate = new UnityEvent();
}
to
public UnityEvent OnRotate = new UnityEvent();
void Start() {
}
And now it works.
Although, now that I think about it, Awake() is the method where they all fire before initialization, whereas Start() is when the object is created. So the Start() of the Rotator is probably getting called after the Owner is adding a listener.

Unity: Weird scene transition bug after adding a "Persistent-Scene" with a GameManager

I made a pretty basic 2D game to learn. I have 2 Scenes, and switching between them worked great. I used empty gameObjects as Start/Exit point of the Scene, so that the game would know to put player on point X after exiting through point X (for example exit outside house if I walk out the door).
Then I added a "Scene0", to use for persistent general scripts like GameManager, Sounds, Music, etc. With just one object called "Controller" that I DontDestroyOnLoad().
After adding this Scene and then just switching Scenes right away to my MainScene, all of a sudden the game starts acting really strange;
the first time I move from my MainScene (Scene1), to my secondary Scene (Scene2), it works fine, but then when I leave Scene2 to go back to Scene1, the player spawns in the middle of nowhere.
And this ONLY happens if I launch the game from my Persistent Scene.
I have no idea what is wrong, I don't add anything that interferes with my scene transitions, all I've added so far is playerHealth, for testing.
Scripts attached to my (persistent) Controller:
DDOL:
public class DDOL : MonoBehaviour {
// Use this for initialization
void Awake () {
DontDestroyOnLoad (gameObject);
}
}
GameManager:
public class GameManager : MonoBehaviour {
public static GameManager manager;
public int playerMaxHealth;
public int playerCurrentHealth;
void Awake(){
if (manager == null) {
manager = this;
} else if (manager != this) {
Destroy (gameObject);
}
}
// Use this for initialization
void Start () {
SceneManager.LoadScene("test_scene");
}
// Update is called once per frame
void Update () {
}
}
Scripts attached to my StartPoint:
PlayerStartPoint:
public class PlayerStartPoint : MonoBehaviour {
private PlayerController thePlayer;
private CameraController theCamera;
public Vector2 startDir;
public string pointName;
// Use this for initialization
void Start () {
thePlayer = FindObjectOfType<PlayerController> ();
if (thePlayer.startPoint == pointName) {
thePlayer.transform.position = transform.position;
thePlayer.lastMove = startDir;
theCamera = FindObjectOfType<CameraController> ();
theCamera.transform.position = new Vector3(transform.position.x, transform.position.y, theCamera.transform.position.z);
}
}
}
And finally ExitPoint:
LoadNewArea:
public class LoadNewArea : MonoBehaviour {
public string levelToLoad;
public string exitPoint;
private PlayerController thePlayer;
// Use this for initialization
void Start () {
thePlayer = FindObjectOfType<PlayerController> ();
}
void OnTriggerEnter2D(Collider2D other){
if (other.gameObject.name == "Player")
{
SceneManager.LoadScene(levelToLoad);
thePlayer.startPoint = exitPoint;
}
}
}
EDIT:
After moving all my DDOL gameObject to the Pre-Scene, it worked. So, I can assume the fault is inside Player or Cameras Start() functions since when they start in Scene1 they get called every time I enter the Scene (only DDOL).
I tried adjusting their Start()functions like follows:
Original camera:
void Start () {
Debug.Log("Starting camera");
if (!cameraExists) {
cameraExists = true;
DontDestroyOnLoad (gameObject);}
else{
Destroy (gameObject);
}
}
Changed Camera:
void Start () {
DontDestroyOnLoad (gameObject);
}
The exact same changes was made in Player.
Obviously this doesnt work because it creates a new Camera/Player every time I enter Scene1 (btw why does it not try to create them when I enter Scene2?, is it because they start in Scene1?). HOWEVER, the new player/camera do start at the correct position, and if I zoom out I can see the old player/camera at that same wrong position as before. So something weird happens when their Start() is called a second time it seems.
You've now mentioned that you had code something like this,
void Start () {
Debug.Log("Starting camera");
if (!cameraExists) {
cameraExists = true;
DontDestroyOnLoad (gameObject);}
else{
Destroy (gameObject);
}
}
Note that this is unfortunately just "utterly incorrect", heh :)
The issues you mention in the question (preload scenes etc) are just totally unrelated to the problem here.
In Unity if you have a character C that persists between scenes a, b, c as you load those scenes, you must kick-off C in it's own (perhaps otherwise empty) scene, you can not use "a" as a matter of convenience to kick off C.
The pattern is, in each of a, b, c just have a line of code like p = FindObjectOfType<Player>(); which runs when the scene loads, and position C as you wish.
Now, regarding your specific puzzle about the unusual behavior you are seeing.
I understand that you want to know why you are observing what you do.
It is a combination of confusion over the following issues: 1 - difference between Awake and Start, 2 - confusion over script execution order {but see below1} 3 - confusion about Destroy versus DestroyImmediate 4 - Not using Debug.Log enough, and not using gameObject.name in there (it's a common in Unity to be wildly confused about which object is talking in Debug.Log) 5 - where you mention you see the other object "off to the side", it's common to drastically confuse which one is which in such situations 6 - confusion between the computer programming concept of "instantiation" (ie, of a class or object) and "instantiating" (confusingly, it's the same word - utterly unrelated) game objects in nity.
If you fiddle around with all those issues, you'll discover an explanation for the behavior you're seeing!
But it doesn't amount to much; in Unity in the "C .. a b c" example you have to create C separately beforehand.
1 {aside, never fiddle with the script execution ordering system in Unity in an effort to solve problems; it's only there for R&D purposes; however it could in fact help you investigate the behavior at hand in this problem, if you are particularly keen to fully understand why you're seeing what you're apparently seeing}
Use the debugger. Have breakpoints at the relevant spots, like PlayerStartPoint.Start() and LoadNewArea.OnTriggerEnter2D() and check that they are executed
At the right time
The right number of times
With the expected values
This should make you see where things get out of hand.
If you use Visual Studio, install https://marketplace.visualstudio.com/items?itemName=SebastienLebreton.VisualStudio2015ToolsforUnity to be able to debug Unity from within Visual Studio.
If you are not using Visual Studio, you probably should.
Is player persistent between scenes (does he have DontDestroyOnLoad)? If no then this might be the reason - you can either try loading the scenes by using the additive mode or by instantiating the player on scene load in correct position.

Simplest way to iterate over all GameObject childrens from a script at runtime

In my Unity3D project I got a complex GameObject of a truck that his hierarchy looks like this.
+ Truck
+FrontPivotPoint
+LeftWheel
Tire
Rim
Hindge
+RightWheel
Tire
Rim
Hindge
+CenterPivotPoint
+Body
Arm
Screw
Pin
Basically what's happening is I got a lot of complex parenting and I want to go trough every child and add to him a RigidBody.
I think it should be something nested but I don't have something in mind.
Any help would be appreciated!
Unity3d allows you to easily automate every routine. You may consider to add custom menu item.
public class MakeRigidBodies : EditorWindow
{
[MenuItem ("Make rigid bodies %&r")]
private static void Execute()
{
var selectedObject = UnityEditor.Selection.activeObject;
if( selectedObject && selectedObject is GameObject )
{
// for all children of selectedObject
{
// add rigid body
}
}
}
}
From what I can see, the structure of your game objects is like a tree data structure. Truck as its parent / root node, and the others as its child. So, you must traverse all the objects / nodes in your structure with tree traversing algorithm, the best that I know is Depth-First-Search (DFS) algorithm.
DFS work like nested loop, the main algorithm are:
Start from the root node
Find its node children
Visit the child
Back to step 2 until all children is visited
This algorithm can be implemented in Unity3d since GameObject stores its child information in transform properties (see http://answers.unity3d.com/questions/416730/get-the-child-gameobject-of-a-parent-and-not-the-t.html). And last, we can add RigidBody to the GameObject with the AddComponent() method (see http://answers.unity3d.com/questions/19466/how-do-i-add-a-rigidbody-in-script.html).
Here is my script to answer your question:
using UnityEngine;
using System.Collections;
public class AddRigidBody : MonoBehaviour {
private void addRigidBody(GameObject gameObject)
{
Rigidbody rigidBody = gameObject.AddComponent<Rigidbody>();
foreach(Transform t in gameObject.transform)
{
addRigidBody(t.gameObject);
}
}
void Start () {
addRigidBody (this.gameObject);
}
}
This script attached to the parent / root GameObject. The AddRigidBody() method is called when this script start (as in Start() method), and this method will traverse all child and add a RigidBody through it.
If I'm not mistaken, and bear with me since it's been a while since I've worked with Unity3D, this could fix it:
* Drag your model onto the stage
* Your entire model should now be selected; parent and its underlying children
* Select the option to add a rigidbody and it should add it to all selected objects.
* Make a prefab of the model and you should be done.
Once again, don't trust me on this. It's been a while and since I don't have access to Unity3D right now, I am unable to check this method myself.
If it's the code approach you want, try this (C#, methods may vary for Boo or Java):
Getting a child: http://forum.unity3d.com/threads/get-child-c.83512/ (see second reply)
Adding a rigidbody: http://answers.unity3d.com/questions/19466/how-do-i-add-a-rigidbody-in-script.html
I hope this helps.