I'm new to unit and i'm making this hack and slash game.
I'm having trouble with making one unit deal damage to another, though
EDIT: i forgot to mention the hit() method is being called from the animator.
public GameObject obj;
(...)
void OnTriggerEnter2D(Collider2D collider)
{
if(!collider.gameObject.GetComponent<floor>())
{
obj=collider.gameObject;
print(obj);
}
}
void hit()
{
print(obj);
if(kicked&&obj)
{
obj.GetComponent<health>().DealDamage(damage);
print(obj.GetComponent<health>().value);
}
}
the hit() method is being called by the animation (when the kick animation is performed). by the way, when you kick, the bool kicked becomes true. The hit method has been printing (null) every single time.
Change
GameObject obj=collider.gameObject;
to
obj=collider.gameObject;
You're declaring a second "obj" variable in your OnTriggerEnter2D method, local to that method, which is overriding the one you declared in your class. I should probably mention that your code (while it may work) is very poorly written. You should read up on OO design patterns.
multiple variable with same name .you have declare "obj" as public and than again want to Declare as local variable .change the name of obj if it is same remove "Gameobject" from inside function .
obj=collider.gameObject;
Related
so i've got this problem thats bugging me for hours now.
I try to use OnTriggerEnter2D(); to get the data of other.DataHolder.itemType.
But Unity states that other does not contain whatever I'm trying to access.
My first Question is, how should unity know that? As in the moment I write the code there's nothing colliding with my player so the code inside of OnTrigger2D(); shouldn't be executed and therefore not asking for components of nothing that obviously not exist.
void OnTriggerEnter2D(Collider2D other)
{
other.gameObject.GetComponent<DataHolder>();
if(other.DataHolder.itemType == "bagCoins")
{
goldCount++;
other.GameObject.SetActive(false);
}
}
How should unity know that?
Well this is c# and any compiler will know the existing types and that a Collider2D has no member called DataHolder.
As in the moment I write the code there's nothing colliding with my player so the code inside of OnTrigger2D(); shouldn't be executed and therefore not asking for components of nothing that obviously not exist.
I'll try it in simple words: As with any other application your entire code is/has to be compiled by Unity before you can even enter the PlayMode/execute it!
So if there is an error in your code of course you will get the according compiler error before it is actually executed since the compiler doesn't even understand how to compile your code for running it.
What you speak about would be a runtime error that only occurres e.g. because some reference is null but principally means that your code structure itself is correct.
GetComponent returns a reference. Just calling
other.gameObject.GetComponent<DataHolder>();
itself does nothing. And in particular it does not change the type of other which still is a Collider2D and has no such member like a .DataHolder!
Instead you have to store that returned reference and use it like
void OnTriggerEnter2D(Collider2D other)
{
// no need to go through the gameObject here btw.
// the Collider2D inherits from Component which also implements GetComponent directly
var dataHolder = other.GetComponent<DataHolder>();
if(dataHolder.itemType == "bagCoins")
{
goldCount++;
// Here you want the property gameObject not GameObject
other.gameObject.SetActive(false);
}
}
I have a car in my game with 4 wheels(Unity3D):
Also i have a trigger of EndLevel:
But after when im going throght the trigger its trying to work 4th times
How can i change it?
I tried to add my "Player(car)" inside EndGame object but its didnt fix my problem.
using UnityEngine;
public class EndTrigger : MonoBehaviour
{
public GameManager gameManager;
void OnTriggerEnter()
{
gameManager.CompleteLevel();
}
}
First of all note that OnTriggerEnter(Collider other) requires a parameter of type Collider otherwise it wouldn't get called at all.
Flag
The simplest solution might be adding a bool flag as already mentioned by Eric Warburton's answer.
Layers
I would prefer to rather tackle the origin of the issue and suggest using different Layers and then configure the Layer-based collision detection via the Edit→ProjectSettings→Physics→ Layer Collision Matrix.
Create a Layer e.g. END and assign it to your goal collider object. Make this object not Is Trigger and rather attach your script checking for OnTriggerEnter here.
Create a Layer e.g. Player create a new dedicated invisible object with a collider and enable Is Trigger here. This object has the only purpose of colliding with the goal collider nothing else. Assign the Player layer here.
Configure the collision matrix thus that END only collides with Player and nothing else. And Player only collides with END and nothing else - or maybe later another effect layer like e.g. PowerUps ;)
You can create up to 24 custom layers and make use of the already existing ones so this should hold up a while
Tags
Another alternative to the Layers is using Tags
As previously I would make the END object not a trigger but rather use one on the Player.
Then you can simply compare the tag using CompareTag
void OnTriggerEnter(Collider other)
{
if (!other.CompareTag("Player")) return;
gameManager.CompleteLevel();
}
in very very complex games this might be sometimes better since you can create a lot more Tags than Layers.
Well there are a few things that I can think of trying.
You can make sure that only one of your colliders is a trigger. There should be a bool check in the properties to uncheck for your wheels.
You can also do something like creating a counter or a bool that prevents the OnTriggerEnter() from firing multiple times if you only want it to fire once. You can reset it at the start of levels if needs be.
Something like
void OnTriggerEnter()
{
if (!gameManager.IsLevelComplete)
gameManager.CompleteLevel();
}
Inside the gameManager script
public bool IsLevelComplete { get; set; }
public void CompleteLevel()
{
IsLevelComplete = true;
//Do stuff
}
Destroy() method is not accessible in static method
public static void Die()
{
Destroy(gameObject);
}
But Destroy() is only accessible if:
public void Die()
{
Destroy(gameObject);
}
You can't call a non static function from a static function but you can do the opposite.
I need to make it accessible on another scripts
Make the Die function to be a non static function. Let's say that this script is named OtherScript.
public void Die()
{
Destroy(gameObject);
}
Then from another script, you can access it by finding the GameObject the OtherScript script is attached to with the GameObject.Find function then use the GetComponent function to get the OtherScript reference from the GameObject:
OtherScript otherScript;
void Awake()
{
GameObject obj = GameObject.Find("NameOfGameObjectOtherScriptIsAttachedTo");
otherScript = obj.GetComponent<OtherScript>();
}
You can now call the Die function with otherScript.Die(). Note that you must replace "NameOfGameObjectOtherScriptIsAttachedTo" with the name of GameObject the OtherScript script is attached to.
From your comments it looks more like you actually want to do what Programmer's answer shows.
I'm just adding this because your title asks How to Destroy Object from static method in Unity C#
If you really need it to be static (e.g. in a static class) you could use it like this
using UnityEngine;
public static class SomeStaticClass
{
public static void Die(GameObject obj)
{
Object.Destroy(obj);
}
}
but to be honest this is needed in very few cases. It might be helpful e.g. in an Editor script where you don't have any Component executing your code.
cannot kill a single static object, it dosnt work that way. please refer to the answer here.
the following excerpt is from the above link, and should explain for you...
*I think perhaps you've misunderstood the 'static' keyword a little bit.
To clarify, a bit... Imagine you have a class called 'Vehicle'.
A none-static variable means 'every vehicle has its own copy of this variable'. We might say 'every instance of vehicle has its own copy of the variable.
A static variable means 'there is only 1 of this value shared by all vehicles'. Here we'd say 'all instances of vehicle share the variable.
Following on from that, functions are a little harder to picture, but they work in much the same way:
A none-static function operates on an instance of the vehicle. The result is that it can use the 'this' operator (it makes sense!) and access both none-static member variables of it's instance, and the shared static ones
A static function isn't tied to an individual instance of a vehicle, so the 'this' operator doesn't make any sense (what would 'this' be?). It still makes sense for it to be able to access static variables, but again none-static ones don't make any sense - who's version of the variable would it be referring to?
Your 'Die' function looks like it is designed to operate on a given instance of your enemy. i.e. you are expecting calling 'Die' to mean 'kill this please'. As a result it should not be static. You'll also need to access the 'gameObject' variable, not the 'GameObject' type.*
public void PlaceIconToSlot() //gets called by a button
{
GameObject IconClone = Instantiate(Icons[properIconIndex], Slots[properSlotIndex].transform.position, Quaternion.identity);
}
Icons and Slots are Arrays. The first one tells the program what to instantiate and the second one where to instantiate. Quaternion.identity just means no rotation.
What I am trying to do: Duplicate an image and place it in a slot, then if another image is placed on top of the old one, the old one should be destroyed.
What is happening: Everything works, except that the old one doesn't get destroyed and the new one sits on top of the old. I mean of course it doesn't get destroyed since I didn't program that, but this is my question. How can I Destroy(OldClone) when there is only an IconClone? How can I introduce to the function the concept of an OldClone?
Since you call the function PlaceIconToSlot I'd guess, you might have a Slot component. If so, you can add a member variable to it that holds the current icon (assuming it's one icon per slot) and just work with that.
Something like this:
public class Slot
{
public GameObject Icon;
public void PlaceIconToSlot()
{
// If you overwrite it, the garbage collector will destroy it a some point anyways,
// but it doesn't hurt to do this destroy call
Destroy(Icon);
Icon = Instantiate(...);
}
}
Potentially pass the parameters (the new icon to instantiate) to this function if you above function at some centralized spot. Something like SpotXYZ.PlaceIcon(icon) or SpotXYZGameObject.GetComponent<Slot>().PlaceIcon(icon).
An idea would be to set a tag (let's say oldImage) to your original image. When you instantiate, destroy the object with that tag and then add the oldImage tag to the new image so that it will then be destroyed when another image is instantiated.
public void PlaceIconToSlot() //gets called by a button
{
GameObject IconClone = Instantiate(Icons[properIconIndex], Slots[properSlotIndex].transform.position, Quaternion.identity);
Destroy(GameObject.FindWithTag("oldImage"));
IconClone.gameObject.tag="oldImage";
}
I haven't tried this but it's worth a go!
I'm having a bit of trouble with Unity 3D's Component-based design model.
Here's an example that demonstrates my problem:
class MyComponent : MonoBehaviour
{
MyType entity;
void Start()
{
entity = (MyType)FindObjectsOfType(typeof(MyType)).First();
}
void MyMethod()
{
var x = entity.SomeProperty; // <= NullReference exception
}
}
// ....
var clone = (GameObject)Instantiate(original);
clone.GetComponent<MyComponent>().MyMethod();
Sometimes, not always though, MyMethod executes before Start so what I end up doing is move all the initializations I usually have in Start to MyMethod which is quite an ugly workaround:
void Start() { }
void MyMethod()
{
entity = (MyType)FindObjectsOfType(typeof(MyType)).First();
var x = entity.SomeProperty; // <= now it's fine.
}
My question is, what is the correct way of working with this pattern (without a constructor)?
That probably happens when you call MyMethod from the Awake of another Component, because Awake is called before the game starts. The only solution I see is to make sure that you don't call methods on other components (in this case MyMethod) in the Awake() event, but rather in the Start() event.
The Unity documentation says "Awake is called before the game starts" but this is not precise. A component's Awake method is called when in a scene the gameobject becomes active which carries the component.
Some gameobjects will be active by default when a scene is loaded, but other gameobjects might be activated later. Then there is the possibility of dynamically adding components via AddComponent.
This aspect should be kept in mind when relying on dependencies between Awake and Start methods. Another example for a race condition is to enable a component from the Update method. While enabling a component implies that its Start method will be called, this will not happen in the running update cycle, so that other components cannot rely on the first component's ".enabled" property to determine wheter it has been started or not.