What I'm trying to do is when it hits a triggered collider I want it to minus an int, but what unity does is minus it with 3 instead, and I have it attached to the player itself
lifecontroller lves;
public GameObject gm;
CoinScript coins;
// Use this for initialization
void Start () {
gm = GameObject.FindGameObjectWithTag("GM");
coins = gm.GetComponent<CoinScript>();
lves = gm.GetComponent<lifecontroller>();
}
void OnTriggerEnter2D(Collider2D other)
{
if(other.tag == "Evil")
{
lves.lives -= 1;
Debug.Log("U hit it");
}
}
// Update is called once per frame
void Update () {
if(lves.lives == 0)
{
Debug.Log("u died");
}
}
Judging from the screenshot, your script is attached to the Player GameObject multiple times. Select your Player GameObject, and remove the duplicate Script.
Make sure there is only one script attached to it. It is probably attached there 3 times.
This problem can also happen if you are instantiating multiple Player GameObjects during run-time as this will duplicate your script too.
EDIT:
With the updated Image in your comment, the problem is that you have 3 Colliders on your Player. It is true that only one of them is made IsTrigger but this is a problem if the GameObject with the Evil tag is marked as IsTrigger too.
You have 2 options to fix this:
1.Select the GameObjects with the Evil tag and make sure that no Collider attached to it is marked as IsTrigger. Unceheck all IsTrigger properties on the Collider of all Evil tagged GameObjects only. This should fix your problem.
2.Only have one Collider on Player GameObject. Remove the other 2. This again should fix your problem.
The trigger is definitly happening 3 times, your screenshot shows that (there is a 3 on the right since duplicate logs get collapsed).
This might occur because of the collider shape I think (circle). Try using a bool that us set on trigger enter and clear on trigger exit (or even Update should be ok for clearing).
This is what I suggested to debug your problem:
void OnTriggerEnter2D(Collider2D other)
{
if(other.tag == "Evil")
{
lves.lives -= 1;
Debug.Log("U hit it", other.gameObject);
}
}
And by looking at your screenshot you are getting 3 log messages.
Always use don't collapse in console window to see whats happening
Related
I am new to using unity and am having a real problem getting trigger collisions to register.
public void OnTriggerEnter2D(Collider2D other)
{
print("collide");
if (other.CompareTag("Fish"))
{
print("Caught");
}
}
I have 2D polygon colliders and a rigid body on both items. I have also got 1 set a trigger(have tried having both as trigger). However one UI item is a sprite and the other is an image.
Both items are also tagged with "fish"
Would really appreciate any help.
Thanks
There are four things I can think of which need to happen so that OnTriggerEnter gets called:
The two objects' colliders need to actually be overlapping. Just because their rendered pixels are overlapping, doesn't mean their colliders are overlapping. This can be checked in the editor. Their colliders are indicated with a green outline in the Scene tab. If you don't see anything, make sure the button labeled Gizmos is turned on.
The two objects need to be in physics layers which are set to collide with each other. You can check this in Edit > Settings > Physics2D > Layer Collision Matrix.
Both objects need to have Rigidbody2D components attached. Make sure these aren't Rigidbody components, as those are for 3D physics.
The object which contains the OnTriggerEnter2D event needs to have isTrigger = true.
I've tried several things to do.
First I've checked recommendations from another post.
In nutshell:
Checked if I have rigid body at least for one of objects
Checked layers
Checked tags
Played with "is trigger".
Finally, the solution was to add script to object via create and add component button and not to drop written script to it. Have no idea, but for me that was the solution. Even it was same script.
Both a Sprite and an Image can collide with another Image. What might be wrong is that your sprite may look like touching the image however in the scene the canvas might be far away, so camera may deceive you. Here is the sample code for my tests:
Script that moves the Sprite:
private Rigidbody2D _rigidbody;
private void Awake() => _rigidbody = GetComponent<Rigidbody2D>();
private void FixedUpdate()
{
if (Input.GetKey(KeyCode.A))
{
var movement = -transform.right * Time.fixedDeltaTime * 250;
_rigidbody.MovePosition(transform.position + movement);
}
if (Input.GetKey(KeyCode.D))
{
var movement = transform.right * Time.fixedDeltaTime * 250;
_rigidbody.MovePosition(transform.position + movement);
}
}
Trigger script on image:
private void OnTriggerEnter2D(Collider2D other)
{
Debug.Log(other.name);
}
Nothing helps for me, but in my case I didn't know there was a place in code that breaks collision layers (that is do not change the collision matrix settings visually):
Physics2D.IgnoreLayerCollision(...
Check that too and make sure it is not called.
So I'm attempting to create a 2D game in Unity where the gameObjects would be destroyed upon hitting the walls. So i decided to use the isTrigger function and add the script to each of the walls. However, I do not know why the gameObjects don't get destroyed. I have tried to set Collision type as both discrete and continuous for the walls and gameobjects and I've also added static rigidbodys to the walls to see if that would help and even tried changing the size of the collisionbodys of the walls.
Here is the code for the wallscript
public class wallScript : MonoBehaviour {
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
}
public void OnTrigger2D(Collider2D other)
{
if (other.tag == "player01")
{
Destroy(other.gameObject);
}
}}
p.s. Even if I remove the conditional statement Destroy() still does not work
You should use void OnCollisionEnter2D(Collision2D other) {...} instead of void OnTrigger2D(Collider2D other).
And uncheck Is Trigger checkbox on your object's Collider.
To Fix The Problem You Are Facing, First Select The Wall Sprite In The Scene, Scroll Down To The Collider And Make Sure Is Trigger Is Checked.
Other Than That Just Check If The Tag You Typed Into The Code Matches The Player You Are Trying To Destroy. Remember, It's Case Sensitive!
After That The Code Should Run Just Fine.
I have an animated sprite which has 8 frames of animation. Each frame has a PolygonCollider2D attached as an element of an array thus providing it with accurate collision detection no matter which frame is playing.
When I had only one collider on the sprite and it passed through the "score" object the player's score increased by 1 point.
private void OnTriggerEnter2D(Collider2D collision)
{
if (collision.gameObject.tag == "Point")
{
score++;
scoreText.text = score.ToString();
return;
}
}
Polygon Collider 2D array in Unity inspector
Each collider in the array becomes active in turn...
public void SetColliderForSprite(int spriteNum)
{
colliders[batColliderIndex].enabled = false;
batColliderIndex = spriteNum;
colliders[batColliderIndex].enabled = true;
}
Now that each frame of the animation has its own collider I find that the score is increasing at an alarming rate as each frame plays multiple times whilst inside the "score" game object, triggering the point scoring logic multiple times, before the player leaves said object.
I'm wondering what the ideal programmatic solution is in order to ensure that on entering the "point" collider object the player only gets a score increment once before exiting the area?
Thanks in advance for any suggestions (and my apologies if this has been answered elsewhere).
EDIT: I was thinking about my post below and I think there is a simpler solution. You should be able to animate your collider shape rather than having 1 collider per animation frame. For example, see this question on How to update 2d colliders with sprite animation.
(And as a side note, you can also have multiple polygon colliders on each part of the sprite, and animate the colliders to move accordingly. For example, see this post on Animating Polygon Collider 2D. This alternative approach might make the suggestion I make in my post below simpler.)
One suggestion I have is to only increment the score when the first "Point" trigger is detected and then not incrementing the score again until the object has fully left. This can be implemented by keeping track of how many colliders (or which specific colliders) have entered and exited the object. Something like the following:
private const string PointTag = "Point";
private int _triggerCount;
private void OnTriggerEnter2D(Collider2D collision)
{
if (collision.gameObject.tag == PointTag)
{
bool firstCollision = (_triggerCount == 0);
if (firstCollision)
{
score++;
scoreText.text = score.ToString();
}
_triggerCount++;
}
}
private void OnTriggerExit2D(Collider2D collision)
{
if (collision.gameObject.tag == PointTag)
{
_triggerCount--;
}
}
However, once a collision is in progress, you will likely have to change the behaviour so that all colliders stay active until the object has fully left the collision area. This is because if you disable the collider, the OnTriggerExit2D event will not fire.
This solution may not be acceptable depending on how accurately you need to detect that the VampireBat has left the collision area.
If it doesn't need to be very accurate, you can simplify the solution by adding a 9th collider with a unique tag that covers the entire area of the sprite's animation. By using this 9th collider to determine when the player has left the collision area, you would not need to worry about affecting the code related to showing the appropriate collider per animation frame. (But note that the code example here would have to be modified so that the OnTriggerExit2D uses this 9th collider object.)
If it needs to be more accurate, I think there is likely a solution similar to what I suggested based on which colliders are currently active, the details of your collider shapes & animation frames, and OnTrigerEnter2D, OnTriggerStay, and OnTriggerExit2D. But note that you may also need to be careful that a collision is not re-triggered immediately. (For example, the object may have fully left the collision area, but the next animation frame might trigger a collision again immediately.)
Thanks for the response. Your edit got me to thinking about child objects. I added a child collider (with an index value of 9) then checked for a collision with that.
child object in inspector
Referenced the child collider in the collider array.
Collider array in inspector
After that it was just a matter of referencing it in the player controller script.
// Update is called once per frame
void Update () {
//Player input
if (Input.GetMouseButtonDown(0))
{
bat.velocity = new Vector2(0, 4);
//ADD BAT FLAP SOUND LATER!!!
}
scoreText.text = score.ToString();
Debug.Log("SCORE: " + score);
}
//Point increment function
private void OnTriggerEnter2D(Collider2D collision)
{
if (collision.gameObject.tag == "Point" && batColliderIndex == 9)
{
score++;
return;
}
}
I now have pixel perfect collision detection against obstacles and a score which increments correctly.
Thanks again.
Let me explain the question first :)
I have a hero and an enemy. It is a fighting game. Both hero and enemy have idle, block, punch and getHit animations and states in the Animation Controller. The hero and enemy have scripts attached to them. The hero is controlled by player and then enemy is controller by AI.
Now I attach the script to hero first and then the enemy. Now when the enemy punches and if hero is not defending the hero takes a hit. But if the enemy is not blocking and the hero hits the enemy doesnt take the hit. This is because the script was attached to hero first.
Now if I remove the script from both and attach the enemy script first to enemy and then attach the hero script to hero. The wiseversa is true. In the enemy the hits will be registered and on the hero the hits wont be registered.
I am not sure why this is happening and I have tried different things and still the problem persists.
I also tried looking everywhere online for solution but none of them addressed my concern.
Thanks :)
below is the enemy script that checks is enemy can take hit
void Update () {
myTick++;
currentTick = myTick;
GameObject player = GameObject.Find("theDude");
Animator pAnim = player.GetComponent<Animator>();
//Getting Hit
if (pAnim.GetBool("tIsPunching"))
{
if (anim.GetBool("bEnemyIsDefending") == false)
{
Debug.Log("enemy got hit");
anim.SetTrigger("tEnemyGotHit");
anim.SetBool("bEnemyIsDefending", true);
}
}
}
And here is the hero script that checks if hero can take hit.
void Update () {
totalTime += Time.deltaTime;
GameObject enemy = GameObject.Find("Enemy");
Animator eAnim = enemy.GetComponent<Animator>();
//Getting Hit
if (eAnim.GetBool("tEnemyIsPunching"))
{
if (anim.GetBool("bIsDefending") == false)
{
Debug.Log("player got hit");
anim.SetTrigger("tGotHit");
}
}
}
Instead of get object I used to have a public GameObject and attached the hero and enemy in the respective classes. But It doesnt make any difference.
I think your problem lies in your use of the triggers tEnemyIsPunching and tIsPunching. Triggers get reset whenever they cause a transition to occur
(see: https://docs.unity3d.com/Manual/AnimationParameters.html).
In your case tIsEnemyPunching or (tIsPunching) is getting reset in the same frame as it gets set. Here is an example of what one update loop may look like in your game if the hero script is added first:
Hero Update()
Check if enemy is punching
He is not, so don't do anything
Enemy Update()
Punch! Set 'bIsEnemyPunching' = true
Animation Update()
bIsEnemyPunching is true so transition to the punching animation
reset bIsEnemyPunching = false
On the next update let's look at what happens in the hero update:
Hero Update()
Check bIsEnemyPunching
bIsEnemyPunching was reset in the previous frame, so it is false
Since the enemy isn't punching don't do anything
So Hero never sees the punch because bIsEnemyPunching got reset before Hero had a change to check it.
This is why the order of adding the scripts matters. Whichever script updates first is able to punch because the second script will see the trigger before it gets reset. However, the second script to update will never be able to punch because the trigger gets reset before the other scripts gets a chance to update.
One solution is to check the name of the animation state instead of the trigger value.
static int punchStateHash = Animator.StringToHash("Punch");
AnimatorStateInfo enemyState = eAnim.GetCurrentAnimatorStateInfo(0);
if (enemyState.nameHash == punchStateHash){
//The enemy is punching!
}
Alternatively, whenever a punch is triggered just call a function on whichever character is getting punched. So when the enemy punches the hero the Punch(...) function on the enemy should call TakePunch(...) on hero (or whatever you want to call those functions). The hero then checks his own state to determine if he is blocking.
Additional Note
You should avoid using the following code in an update function:
GameObject player = GameObject.Find("theDude");
Animator pAnim = player.GetComponent<Animator>();
These functions are very slow because Unity must search all objects for the one called theDude and then search all it's components to find the animator. Do this once and save off the result.
I am trying to make a scoring system for a game that I am making; it's a remake of Flappy Bird.
The issue I am having is, I have set up a sprite with a rigidbody2d and a box collider as the score; I am trying to make it so that when the character passes through that sprite; it will add one to the score however when the character attempts to go through it, it just get's pushed back to the other side of the screen.
This is because of the box collider of course but I am not sure of any other way of doing this without this method. Here is the code which detects if the character hits the pipe or the score line:
void OnCollisionEnter2D (Collision2D hit) {
if(hit.transform.gameObject.name == "Pipe(Clone)") {
die();
Debug.Log("hit");
}
if (hit.transform.gameObject.name == "Score(Clone)") {
Debug.Log("Score");
}
}
Everything logs perfectly fine however the problem is that the bird just faceplants into the score line which isn't what is supposed to happen, please try to help or advise what I should do with this.
P.S. I am a novice programmer; I sort of know what I am doing however not really good at debugging things and fixing them, Thank you.
You should check the "Is Trigger" on your Bird object collider in editor. And use:
void OnTriggerEnter2D(Collider2D col) {
if (col.transform.name == "Score")
Score++;
}
In the bird object script.