In my scene I am instantiating at runtime a prefab, which has a dynamic Rigidbody2D and a BoxCollider2D;
It also has a script with an OnTriggerEnter2D method, that runs the following function:
/* ... */
public Rigidbody2D rigidbody;
private void StopMovement()
{
rigidbody = GetComponent<Rigidbody2D>();
rigidbody.velocity = Vector2.zero;
Debug.Log(rigidbody.velocity);
}
Basically I want the object to stop when he collides with the trigger. The problem is it doesn't stop, and even if the console message says (0.0, 0.0) the rigidbody's inspector looks like this:
And as you can see, its velocity isn't actually zero.
I tried adding
rigidbody.constraints = RigidbodyConstraints2D.FreezeAll;
but all it does is freezing the position on the prefab, not on the actual gameObject instance. And I don't get how that's possible, also considering that the Rigidbody field on the script is occupied by Ball(clone), which is the name of the gameObject that's in the scene.
I also tried using GetComponent in Awake/Start instead of there, but the result was the same.
I've already looked up a bunch of other posts, both here and on UnityAnswers, but none of them could help me. What is happening exactly?
You are accessing the prefab and not the actual gameObjecy and so the rigidbody. When you instantiate the ball use a
'GameObject ballClone = Instantiate(ballpref, pos, quaternion);'
In this way you can access to ballClone.getcomponent() and it will work fine
Turns out that what caused that strange behaviour was related to a custom Event System, that's why it has taken so long to figure out.
Basically I was assigning the prefab as the target object in the Event Listener's inspector, thinking that its effect would be automatically applied to all the instances of that prefab, but in the end it doesn't work like that.
If anyone has the same issue, I solved it by putting the Event Listener component onto the vary target object, so basically it references itself and causes the expected behaviour.
Thanks for everyone's time, this can be closed now.
Related
I am a newbie in Unity and game development. I want to make a mobile stack jump game with primitives. I have a player in the center of the screen. The enemy is approaching the player from the right and left of the screen. The player tries to sit on the enemy by jumping as in Mario Game. If the enemy hits the player from the side, the game is over. I create enemies with a SpawnMan. There is a prefab for an enemy game object. SpawnMan creates them at certain time intervals with the Instantiate() method. I want to store data on whether the enemy is approaching from right or left. I even want to store this information by creating an enum type. In summary, I want to have enemy objects with the left and the right types. How do I set this property (left enemy or right enemy) when calling the Instantiate() method in SpawnMan as in OOP constructor with parameters.
enum EnemyType
{
Left,
Right
}
// ...
Instantiate(enemyPrefab(EnemyType.Left), spawnPos, enemyPrefab.transform.rotation);
Assign a GameObject while instantiating first :
GameObject enemy1 = Instantiate(...)
Then, we can use the player transform and the enemy transform vectors to get a direction (+ value and a minus value)?
As Chandradhar said, addition to that, you can use Mathf.Sign(player.position.x- enemy.position.x); to see if the enemy comes from the left or the right of the player.
You can't really pass it in exactly that way, as Instantiate doesn't call a constructor on the instantiated prefab's scripts. Or I guess enemyPrefab could be a method that returns an actual prefab object with set script values, but that would be a somewhat odd way to get what you want.
But presumably you just want the enemy object to have that information about left/right, in that case the easiest would be to get the attached script and then assign the left/right property. So you would add something like this to your enemy script (the one that is attached to enemy prefab)
public class MyEnemyScript : MonoBehaviour
{
public EnemyType Type;
... your enemy code here...
}
And then use it like that:
var enemyGameObj = Instantiate(enemyPrefab, spawnPos, enemyPrefab.transform.rotation);
enemyGameObj.GetComponent<MyEnemyScript>().Type = EnemyType.Left;
Note that this is not really good practice, as GetComponent is an expensive call, but then again neither is Instantiating all those enemies - it would be nicer to use pooling.
I'm assuming an enum for left and right is overkill, but if you have some design reason that the enemies need to do have some special logic depending on what side they're on, you can still handle that in a simpler fashion.
In your MyEnemyScript(), you have Awake() and OnEnable() methods that will be automatically called by Unity just like Start and Update. In one of them (use OnEnable if you use object pooling), put something like this:
public EnemyType type;
private void Awake()
{
if (transform.position.x > PlayerInfo.playerPosition.x)
type = EnemyType.right;
else
type = EnemyType.left;
}
Now you can just spawn enemies as normal without thinking about it. PlayerInfo can be a static class or a singleton or however you prefer making that information available.
Then in your update loop, just have two logic paths (which I assume is similar to what you're doing anyway).
private void Update()
{
if(type = EnemyType.left)
//do left enemy stuff
else
//do right enemy stuff
}
why do we have to access a component from our script using GetComponent method ?
can we make its object instead?
e.g
instead of
Rigidbody rb;
rb = GetComponent<Rigidbody>();
can we use
Rigidbody rb = new Rigidbody();
and use methods based on that.
will the be result same ?
Thankyou.
P.s : I am new to unity
NO!
For your usecase though see the very last lines of this answer. ;)
It is completely illegal in Unity to use new for creating instances of a Component! You will also get a warning about it in the console.
For some stupid reason Unity still "allows" to do it though and does only throw a warning instead of an exception. However, that instance just will not "work" since most of things will not be initialized correctly.. and how should it? There is no GameObject related to it so what would the use of a Rigidbody without according GameObject be? - Right, it is absolutely useless ;)
A Component can only exist correctly if it is attached to a GameObject. Thus, there are only three valid ways of creating instances at runtime:
Use the constructor of GameObject like e.g.
var obj = new GameObject("SomeName", typeof(Rigidbody));
var rb = obj.GetComponent<Rigidbody>();
This creates a new GameObject called SomeName with only the Transform and a Rigidbody component attached.
Use Instantiate to either clone an existing GameObject or create an instance from a prefab.
[SerializeField] private Rigidbody prefab;
...
var rb = Instantiate (prefab);
Use AddComponent to add a new instance of given component type to an existing GameObject. The example from the constructor can also be implemented as
var rb = new GameObject("SomeName").AddComponent<Rigidbody>();
or in your use case to add that component to the same object your script is attached to
var rb = gameObject.AddComponent<Rigidbody>();
which probably comes closest to what your code tries to do
I am working on a game and came to a point where I had nothing in my mind. want to take reference of an object by collider frequently. I don't know how to make so please help.
Thanks in advance
Take Object A with script As and script 2As and collider Ac
Object B with script Bs and collider Ac
Their might be 3 different things you are looking to achieve here:
Reference Script Bs from script As:
First you need to reference the Game Object that Bs is on (B) from script As
At the very top of script As you would add:
public GameObject objectB;
Then later in your code when you want to reference the script on objectB you can do:
int value = objectB.GetComponent<Bs>().score;
Where score is a variable in Bs
Reference Script 2As from As:
In this case we already are on the same gameobject so we can simply do
int value = gameObject.GetComponent<2As>().Score;
Where Score is a integer in the Script 2As
The reason we can just say gameObject.GetComponent here instead of having to reference the other object is because gameObject with a lower case g refers the object that the script is sitting on. So effectively we just say "get the other script on this gameobject"
Lastly (I think you are trying to do this maybe?)
Take a collider and get the GameObject on this collider then get the script on that GameObject:
public Collider coll;
int val = coll.GameObject.GetComponent<script>().value;|
I hope that helps, I didn't really understand your question so if this doesn't answer your question let me know :)
Also join my discord if you have any other questions: discord.io/gamedev
We really need more info about what you're trying to accomplish. Are you trying to know what an object collided with recently? trying to raycast? Depending on what you want to do with it, you might need to reference different components on the gameobject. etc.
But here's an example:
//Component on a gameobject with a collider attached.
public class RefByCollision : MonoBehaviour
{
[SerializeField] //makes it show in inspector
private GameObject lastCollisionGO;
//Called everytime this gameobject collides with another that has a collider (non trigger)
private void OnCollisionEnter(Collision other)
{
lastCollisionGO = other.gameObject; //replaces reference with the newly collided object.
}
}
This component on a gameobject with a collider attached will replace the reference stored in lastCollisionGO everytime the object collides with another object.
Note: If you try to query the value of lastCollisionGO before it collides with something, it will be empty and give you a null reference exception.
This question already has answers here:
How to find child of a GameObject or the script attached to child GameObject via script
(4 answers)
Closed 4 years ago.
I want to access the animator component of my player character. The character is spawned under the GameObject Character position, which it self is the child of Game Manager.
The character prefabs have various names, so I cannot find them through exact name. So its easier to just get the only child of Character position.
Game Manager
Character position
Player Prefab
Ive searched online and tried GetChild by index and GetComponentInChildren. None of them work. Below is the script I wrote for this:
private Animator archerAnimator;
private float startSpeed;
GameObject charPos;
GameObject archer_;
// Use this for initialization
void Start () {
charPos = GameObject.Find("Game manager/Character position");
Debug.Log(charPos);
archer_ = charPos.transform.GetChild(0).gameObject;
archerAnimator = charPos.GetComponentInChildren<Animator>();
Debug.Log(archerAnimator);
}
charPos is found, but for archer_ I get the error, Transform child out of bounds. The player archer is not there but is spawned at run time when the scene starts, is this the reason it cannot find it so quickly?
Some guidance would be appreciated.
Thank you
I think you're scanning for the player too early. You should reverse your discovery logic. Instead of scanning for the player and its Animator, you should put a script on the player itself that runs after it is created and reports itself to the game manager or whatever object needs access to it, something like this:
void Start() { GetComponentInParent<GameManager>().OnPlayerSpawned(this); }
I'll also mention that some script finding an object by name and accessing its components is a generally bad idea. Here's a design guideline to always keep in mind: You should traverse Unity's object hierarchy as infrequently as possible, and even if you do, you should only traverse objects that don't have other scripts attached. In this case, you should also put the logic to control the Animator inside your Player script. Then, you wouldn't need to get a reference to the Animator in the first place.
so i have my player standing next to a cube. the player has a script, which is empty aside from an int which is 43. the same applies to the cube except the int in the cube's script is 42. how do i get(or detect) the int in the cube's script and print it in the console using OnCollisionEnter(or OnTriggerEnter if it is better) like this: ("the cube has the number 42")?
Well you should definitely go through some tutorials before continuing since you don't seem to know even very basic stuff, but to at least point you in the right direction, you would do something like this (assuming C#, not UnityScript):
void OnCollisionEnter(Collision collision)
{
int numberOfCollidedObject = collision.gameObject.GetComponent<objectsScriptNameHere>().variableNameHere;
Debug.Log(numberOfCollidedObject);
}
How did I know how to do that? I looked at the documentation. I can see that when OnCollisionEnter is called it's passed a variable of type Collision. It's hyperlinked in the documentation, so I clicked on Collision and found that it contains a variable called gameObject that contains a reference to the game object of the collider we just hit. I happen to know that to get into another script, you called GetComponent<scriptName>(), and from there any public variables and functions can be accessed.
if you got two collider (player and object who collide the player) you can convex the collider and set isTrigger to true
Then call the function OnTriggerEnter()
void OnTriggerEnter(Collider other) {
Debug.Log(other.name);
}