Getting an Object Reference for an animation and executing [duplicate] - c#

This question already has an answer here:
Error in C#: "An object reference is required for the non-static field, method, or property"
(1 answer)
Closed 5 years ago.
Doing a quick 2d game to get familiar with Unity and I came across an issue that no one else seems to have a problem with.
This is the Error I was originally receiving:
Assets/scripts/Receiver.cs(33,13):
error CS0120: An object reference is required to access non-static member
`UnityEngine.Animator.SetTrigger(string)'
I have updated the code from Animator.SetTrigger to myAnimator.SetTrigger and it has removed the error and I can test the game, but the animation does not come through.
I am looking to have these objects animate and disappear after being hit, but these are non moving objects and do not have an Idle animation. I set a trigger "IsDead" to activate the animation. I think I missed something or just not 'getting it'. I have tried to find similar problems to try and connect the dots (I'm new to c#) and ended up finding old functions from previous versions of Unity that didn't work or even exist in the same way.
before trying to add the animation, the game worked fine. I just need to see how the animation looks in-game.
I'm not trying to do individual sprite swaps. I am trying to understand how to make a death animation that connects to this prefab script that I can adapt to future prefabs. Also, can I reuse the "IsDead" trigger for separate animators in different prefab objects that have different animators attached to them?
the line in question is :
if(timesHit >= maxHits) *{Animator.SetTrigger ("IsDead");}
would this work as is with the reference?
working with prefabs and similar reacting objects in the future, this is something I want to have a good understanding of.. thank you for your time.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Receiver : MonoBehaviour {
public int maxHits;
private LevelManager levelManager;
private int timesHit;
Animator myAnimator;
void Start () {
var animator = gameObject.GetComponent<Animator>();
timesHit = 0;
levelManager = GameObject.FindObjectOfType<LevelManager> ();
}
void Update () {
}
void OnCollisionEnter2D (Collision2D col) {
timesHit++;
if (timesHit >= maxHits) {Animator.SetTrigger ("IsDead");}
}
void OnCollisionExit2D (Collision2D col) {
if (timesHit >= maxHits) {Destroy (gameObject);}
}
}

There are two kinds of Functions in strictly OOP Languages:
Static Function, that you call on the class. The Console Class functions are textbook examples for this.
Instanc functions, that you call on a specific instance. You want to SetTriggers for this specific instance.
There sometimes are static overrides - usually those require you hand in the instance as one of the arguments.
But thsi all has nothing to do with Unity or game development. That is just basic programming that you could have learned in a simple Console Appliation.

Related

Unity - How to properly reference the GameManager in different scenes [duplicate]

This question already has answers here:
How to pass data (and references) between scenes in Unity
(6 answers)
Closed 1 year ago.
I am new to Unity, and starting on creating my first simple projects. For some days already I've been facing a problem and doing a ton of research but I still cant get it to work, here is it:
As far as I know, it is a smart idea to have a "GameManager" object with a "GameManager" script that holds the main functions of the game (please correct me if it isn't best practice). So lets put as an example I have Scene 1 and Scene 2:
Scene1:
-GameManager
-Label
in GameManager there is a function called ChangeLabelText()
Scene2:
-Button
-Scene2Script
in Scene2script there is a function called ButtonOnClick()
and here is my problem: how do I get ButtonOnClick() to call GameManager.ChangeLabelText()?
I always get a reference error.
I've tried to do it within the same Scene and it works perfectly, but not between different scenes.
Any ideas?
Thank you !
Changing scenes in Unity results in Unity destroying each instance. If you want to keep a specific instance/GameObject across several scenes, you may use the DontDestroyOnLoad method. You can pass the GameObject, this specific GameManager instance is attached to, as the parameter. You'd probably want to use a singleton pattern as well for two reasons:
You may not want to have two or more instances of the GameManager class at once. A singleton will prevent that.
You have to find a way to reference this instance nonetheless, since the components in your other class are totally new instances and they have no idea where this GameManager component is.
Example for a singleton pattern:
GameManager.cs
public static GameManager Instance; // A static reference to the GameManager instance
void Awake()
{
if(Instance == null) // If there is no instance already
{
DontDestroyOnLoad(gameObject); // Keep the GameObject, this component is attached to, across different scenes
Instance = this;
} else if(Instance != this) // If there is already an instance and it's not `this` instance
{
Destroy(gameObject); // Destroy the GameObject, this component is attached to
}
}
Example.cs
private GameManager gameManager;
void Start() // Do it in Start(), so Awake() has already been called on all components
{
gameManager = GameManager.Instance; // Assign the `gameManager` variable by using the static reference
}
This is of course only the basic principle. You may apply that in various slightly different variations if you need to.

Enabling multiple Monobehaviour Components in a game object

So, i'm trying to make a Multiplayer Game here with various game objects and scripts in c# for every object on the scene.
Thing is, when i spawn the player controlled objects every player shares control over scripts for each spawned gameObject on the scene, that means, when somebody presses "s" for example, every player moves backwards, and that's not how i want game to behave.
--So, the only way i know to solve this, is by spawning 'em with all their scripts (the components) disabled and enable 'em with another script on the gameobject, but i had to make a script to enable every component one by one, and it got really time comsuning to create or edit a new script every time i add a new one to new units n' so on, so i figured out i could do something like this script below.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Networking;
public class PlayerNetControl : NetworkBehaviour {
public MonoBehaviour[] components2enable;
public override void OnStartLocalPlayer()
{
foreach (MonoBehaviour cmp in components2enable)
{
cmp.enabled = true;
}
}
}
after doing this, i expected every "monobehaviour component" i added to the script using unity, to be enabled when for the player who controlled the game object only, but it does nothing, i check the components on the gameobject testing this out, they are all still disabled.
Also, is there any way for me to solve this problem in any other way than the one i know? if so, i would love you to illuminate me teaching me how.
Please help, i've started coding recently and i really need help with C#
Check for islocalplayer.
I think this solves all your problems.
https://docs.unity3d.com/ScriptReference/Networking.NetworkBehaviour-isLocalPlayer.html

Unity 5 particle-deleting c# Script

I was following a unity tutorial started on Unity 4 but I am on Unity 5, and when I try to use the script seen (https://youtu.be/vwUahWrY9Jg?t=1337) and I try to use it, it gives an error:
Assets/Scripts/DestroyFinishedParticle.cs(18,17): error CS0246: The type or namespace name `Destroy' could not be found. Are you missing a using directive or an assembly reference?
this is the code:
using UnityEngine;
using System.Collections;
public class DestroyFinishedParticle : MonoBehaviour {
private ParticleSystem thisParticleSystem;
// Use this for initialization
void Start () {
thisParticleSystem = GetComponent<ParticleSystem>();
}
// Update is called once per frame
void Update() {
if (thisParticleSystem.isPlaying)
return;
Destroy (GameObject);
}
}
It can be because C# code for unity changed from 4 to 5? what should I change? The problem seems to be in the Update method.
There are couple of issues with this code.
First, you didn't mention to what exactly is it attached too? I assume it attached to the Particle System.
Secondly, use "gameObject", not "GameObject", since GameObject is the name of the class.
Third, I believe there's a much more efficient way to destroy the gameObject without checking every frame whether the particles system has finished or not, maybe set a small timer? or invoke the function with time?
Depending on how your event is set up would depend on the approach to checking if the particles are running. If you can setup a collider to when you walk in, you can trigger an event to know the particles are on. Upon exiting the collider, the particles will shut off.
I'm not 100% on the syntax of return in C# but seems like it should go after you destroy your game object. I think return works in a similar fashion as the break in that aspect.(Especially since you don't seem to be returning any values anyway why do you need it?)

Unity problems with classes C#

I have started learning Unity and already have learned JavaScript for web development so I do have some programming experience.
While programming in unity I came across a few things involving classes that I didn't quite get.
1) When I wright code as a component of a unity object I write it inside the public class shown below. (name Mover is just an example.) However I never create an instance of this class so how does this work? All I see is the class being created.
using UnityEngine;
using System.Collections;
public class Mover : MonoBehaviour {
}
2) Also shown in the code above is MonoBehaviour. I read the api and it said it is a base class. I never came across this in JavaScript. What does this mean and what does it do to the class Mover?
Try this.
Go to your project in Unity, create a c# script, name it whatever you want. Create a cube in your scene. Drag and drop this script onto the object. Open the script and you should see a start method and an update method.
Type Debug.Log("Start"); in the void Start() function, same in the void Update() method but change to the string to whatever. Click play in unity and watch the console.
You should see the console printing stuff.
Anything that is a child of Monobehaviour enables you to do a lot in which I am not going to get into here.
https://docs.unity3d.com/Documentation/ScriptReference/
At the top, you can choose the language. Get used to that page. =D
Hope this leads you somewhere!
For the first question, you may attach the script to a gameobject in the scene to use it.
For example,
public class Mover : MonoBehaviour {
private bool started = false;
void Start () {
Debug.Log ("Mover Started");
started = true;
}
}
If you attach this script to a gameobject in your scene and play the scene. The script will run and print out "Mover Started" and set the private boolean to true.
This are many other ways to interact with other objects or scripts too. Hope it clears things up a little.
If you take a look at Unity's docs for MonoBehaviour you'll see that every JS file associated with your project automatically derives from MB. If you're coding c#, understand that not everything must be a MB. Objects in the game hierarchy may only attach component scripts that inherit from MB objects. Unity handles the construction of these objects, and a MB is actually something that you are forbidden from constructing yourself.
Also, I think you might be better off at unityAnswers for Unity related help.

How to randomly generate GameObjects programmatically?

I'd like some help with the following issue. I'm making a simple game where you have a character running and he has to jump over obstacles coming at him.
And I'm currently stuck when it comes to creating GameObjects and randomly generating them within the game scene at run time.
I've written a class to help accomplish this:
using UnityEngine;
using System.Collections;
public class randomObstacles : MonoBehaviour {
public GameObject myCube;
public Vector3 spawnLocation = new Vector3(0,2,0);
// Use this for initialization
void Start () {
GameObject SpawnLocation = (GameObject)Instantiate(myCube, spawnLocation, Quaternion.identity);
}
// Update is called once per frame
void Update () {
}
}
The above code is what I wrote to simply create Objects, one after the other. But when I run the game, it comes up empty -_- !
Can anyone please tell me where am going wrong, and from the look of it my code doesn't seem to do what I am hoping to achieve :(
I've attached the above script into an empty GameObject as I saw in a tutorial from the Unity Community forum, but that did not help either.
(I've looked around and it seems like no one has come across such an issue - I could bee wrong)
It would seem that your myCube variable is the root of your problems, having tested it in a scene of my own. By subsituting
(GameObject)Instantiate(myCube, ...
with
(GameObject)Instantiate(GameObject.CreatePrimitive(PrimitiveType.Cube), ...
I was able to produce a cube at (0,2,0) with no qualms. Perhaps your myCube GameObject is missing a Mesh Renderer, in which case it would appear in the Hierarchy during runtime even though it would not appear visible in Game View. Perhaps you are not assigning it in the Inspector before you run the game, in which case the myCube variable would refer to null and thus not be created. Additionally, though you may be assigning the GameObject you instantiate to SpawnLocation, it is an unused local variable (something MonoDevelop or your code editor should notify you of). Make sure you either provide a reference to a myCube GameObject in the Inspector before runtime or through script referencing to a loaded prefab/GameObject during runtime. It would also be helpful to provide a fallback (say, to PrimitiveType.Cube perhaps?), which will make your code more robust and able to handle errors in referencing should they arise.
Regardless, in order to achieve the functionality you have described, first make sure yo have properly prepared whatever you would desire myCube to be. Also, for future posterity, you may want to initialize your spawnLocation in the Start routine, and assign the variable coordinates by substituting Random.value * yourValueCeiling in for each random coordinate you would like myCube to spawn on. You could even go as far to make a helper method externalized and thus independent from the start routine, such that you will not have to have a hundred instances of a single script to create a hundred instances of what you need; rather, you can call the method through a single script, and save yourself trouble in this way. If you would so appreciate it, here is my implementation of your objective, hope this helps!
using UnityEngine;
using System.Collections;
public class randomObstacles : MonoBehaviour {
public Vector3 spawnLocation;
public GameObject myCube;
// Use this for initialization
void Start () {
if (myCube != true) {
Debug.Log("myCube not set");
myCube = GameObject.CreatePrimitive(PrimitiveType.Cube);
}
if (myCube.renderer.enabled == false) {
Debug.Log("myCube not rendered");
myCube = GameObject.CreatePrimitive(PrimitiveType.Cube);
}
CreateCube();
}
// Update is called once per frame
void Update () {
}
void CreateCube() {
spawnLocation = new Vector3(0, Random.value * 10, 0);
Instantiate(myCube, spawnLocation, Quaternion.identity);
}
}
It may be worth pointing out that you're creating your object in the Start method, which means your code will only run once: from the name of your class, I'd assume you want to create more than one object using this code.
If you move the code into Update you'll create one object per frame, which is most likely too many. My guess would be that you want something like a coroutine that will run on a random interval, and then spawn cubes repeatedly over time, something like this:
void Start () {
StartCoroutine("SpawnObjects");
}
IEnumerator SpawnObjects()
{
while (keepAddingObjects) // a boolean - could just be "true" or could be controlled elsewhere
{
GameObject SpawnLocation = (GameObject)Instantiate(myCube, spawnLocation, Quaternion.identity);
float delay = Random.Range(1f, 5f); // adjust this to set frequency of obstacles
yield return new WaitForSeconds(delay);
}
}
Taken from my own code in a game that auto generate mazes:
public class Cell
{
private GameObject instance;
public void CreateVisual()
{
// Load a GameObject that exist inside the "Resources" folder.
GameObject prefab = (GameObject)Resources.Load("Models/Walls/3W1");
// Create an instance of the prefab
instance = (GameObject)GameObject.Instantiate(prefab);
instance.transform.position = myPosition;
}
}
I think the part you are missing is the Resources.Load() method.

Categories

Resources