One line stops script C# Unity - c#

Some part of the code works (hp1 -= damage1;), but the second part doesn't work.
Where did I make a mistake?
Here are parts of two scripts:
Player1.cs
private Bullet1 b1;
void Start()
{
b1 = FindObjectOfType<Bullet1>();
}
void OnCollisionEnter2D(Collision2D col)
{
if (col.gameObject.tag == "Bullet1")
{
hp1 -= damage1; // it works, my player loses hp
Destroy1(); // doesn't work
}
}
void Destroy1()
{
b1.hit1 = true; // hit for bullet1.cs
}
Bullet1.cs
public bool hit1;
void Update()
{
if (hit1)
{
hit1 = false;
Destroy(gameObject);
}
}
If I switch bool hit = true in real time in Unity, destroying works. It means that Bullet1.cs can't recieve hit = true;
If I swap lines hp1 -= damage1; and Destroy1();, my player can't get damage. So, Destroy1(); stops my code and then can't activate other lines. Also if I change Destroy1(); to b1.hit1 = true; nothing new happens.

Just destroy the bullet through the collision instead of using the boolean. It's creating unnecessary resource usage. Of the given code, this is all you need to do to destroy the bullet using the player script. The parts of the bullet script shown are unnecessary. If you want additional logic handled inside the bullet when destroyed then use a OnDestroy function to handle it.
void OnCollisionEnter2D(Collision2D col)
{
if (col.gameObject.tag == "Bullet1")
{
hp1 -= damage1;
Destroy(col.gameobject);
}
}

Related

Multiple collisions happening at the same time

I'm making a Balloon Fight style game and I'm having trouble with object collision. Each character has two balloons on top of his head and each balloon has an on trigger Box Collider. I want to make it so only one balloon can be hit at a time so you can't destroy both balloons at the same time. In order to do this I added a boolean called isAttacking to prevent it from destroying more than one balloon at the same time.
Hello, I'm making a Balloon Fight style game and I'm having trouble with object collision. Each character has two balloons on top of his head and each balloon has an on trigger Box Collider. I want to make it so only one balloon can be hit at a time so you can't destroy both balloons at the same time. In order to do this I added a boolean called isAttacking to prevent it from destroying more than one balloon at the same time.
public bool isAttacking = false;
private void OnTriggerEnter(Collider collision)
{
if (collision.GetComponent<Collider>().gameObject.layer == 7 && collision.GetComponent<Collider>().gameObject.tag != this.gameObject.tag)
{
if (!isAttacking)
{
Destroy(collision.GetComponent<Collider>().transform.parent.gameObject);
transform.parent.gameObject.GetComponent<Jump>().jump = true;
isAttacking = true;
}
}
}
void LateUpdate()
{
if (isAttacking)
{
isAttacking = false;
}
}
While it does prevent two collisions from registering I still found this solution to be insufficient, since the balloon that is destroyed is not necessarily the one closest to the character destroying it. How could I improve the collision code in order for it to only register the collision happening closer to the character?
Within one frame afaik there is no reliable order of OnTriggerEnter calls (it is somewhat based on the instanceID of objects but that won't really help you).
What you could do instead would be comparing distances, somewhat like e.g.
private readonly HashSet<GameObject> hittingObjects = new();
[SerializeField] private Jump jump;
private void Awake()
{
if(!jump) jump = GetComponentInParent<Jump>(true);
}
private void OnTriggerEnter(Collider collision)
{
if (collision.layer == 7 && !collision.CompareTag(gameObject.tag))
{
hittingObjects.Add(collision.transform.parent.gameObject);
}
}
private void LateUpdate()
{
if (hittingObjects.Count > 0)
{
var closestHit = hittingObjects.OrderBy(hit => (transform.posiion - hit.transform.position).sqrMagnitude).First();
Destroy(closestHit);
jump.jump = true;
hittingObjects.Clear();
}
}
Note: This still doesn't prevent this object from colliding with the other balloon in the very next physics update. If you wanted to track this as well you could make it slightly more complex and only allow collisions if you are newly entering the trigger => You have to exit the object again before you can hit it again.
Somewhat like maybe
private readonly HashSet<GameObject> hastoExitFirstObjects = new();
private readonly HashSet<GameObject> newHittingObjects = new();
[SerializeField] private Jump jump;
private void Awake()
{
if(!jump) jump = GetComponentInParent<Jump>(true);
}
private void OnTriggerEnter(Collider collision)
{
if (collision.layer == 7 && !collision.CompareTag(gameObject.tag))
{
var hit = collision.transform.parent.gameObject;
if(!hastoExitFirstObjects.Contains(hit))
{
newHittingObjects.Add();
}
}
}
private void OnTriggerExit(Collider collision)
{
if (collision.layer == 7 && !collision.CompareTag(gameObject.tag))
{
var hit = collision.transform.parent.gameObject;
hastoExitFirstObjects.Remove(hit);
}
}
private void LateUpdate()
{
if (newHittingObjects.Count > 0)
{
var closestHit = newHittingObjects.OrderBy(hit => (transform.posiion - hit.transform.position).sqrMagnitude).First();
newHittingObjects.Remove(closestHit);
Destroy(closestHit);
jump.jump = true;
foreach(var hit in newHittingObjects)
{
hastoExitFirstObjects.Add(hit);
}
newHittingObjects.Clear();
}
}
First, check if your OnTriggerEnter is executing for both balloons. It probably is?
Then in the moment OnTriggerEnter executes, compare the position of collision with the position of your balloons and see which one is the closest, then destroy the closest balloon and maybe set a variable isInvulnerable as true, so that if it is true, no balloon can be destroyed inside OnTriggerEnter.
I'd just enable only one balloons box collider at once, and when it gets popped enable the other balloon after 1 second delay.

How do I make it so if the player wants they can hold the animation but if they don't hold it, it completes.. (physics based)

so here is the scenario,
i want the player to be able to perform a trick, and then be able to hold the trick for a longer duration if they want to, but if they don't hold the input then they instead just continue the animation until completion as i haven't actually tried implementing too much and its not giving me the desired result i figured i'd just ask if people have already done it so i don't spend the next 2 hours down a rabbit hole, any and all help is appreciated thanks! :D
(Unity Script)
{
[Header("Trick Attributes")]
public string GroundTagName; // Tag used for all the platforms
public KeyCode stuntKey;
public float AnimationFreezeTime = 0.75f;
public SpriteAnimator anim; // Put the Sprite animator here
public Animator spriteAnimator; // Put the Animator here
private bool isGrounded;
public bool stunting = false;
private void Start()
{
}
private void Update()
{
if (Input.GetKeyDown(stuntKey) && !isGrounded)
{
anim.StartAnimation("FlyingSquirrel");
stunting = true;
Invoke("FreezeAnimation", AnimationFreezeTime);
}
if (Input.GetKeyUp(stuntKey))
{
stunting = false;
spriteAnimator.speed = 1;
}
}
void FreezeAnimation() {
spriteAnimator.speed = 0;
}
private void OnCollisionEnter(Collision collision)
{
if (collision.gameObject.tag == GroundTagName)
{
isGrounded = true;
}
else
{
isGrounded = false;
}
if (stunting && collision.gameObject.tag == GroundTagName)
{
Destroy(gameObject);
}
}
private void OnCollisionExit(Collision collision)
{
isGrounded = false;
}
}
FlyingSquirrel needs to be broken up into 3 different animations. This can be done in Maya, Blender, uMotion, or even Unity's animation importer:
You need 3 Animator states:
Start_FlyingSquirrel // Player moves into position
Idle_FlyingSquirrel // Player is "holding" the trick
End_FlyingSquirrel // Player let go, return to normal
When the player presses button to start the trick, play the Start animation. For the transition, use "has exit time" to proceed to the Idle State. The Idle state will be true (use a boolean Animator parameter) while the trick is "held". Uncheck "has exit time" for the transition to the End state- you want this to happen instantly.

Unity OnTriggerEnter2D

Anyone can help me how to fix this problem i'm having?
*1st script:
public static bool attacking;
public Collider2D attackTrigger;
private void Awake()
{
attackTrigger.enabled = false;
}
private void Update()
{
if (attacking == true)
{
Debug.Log("Box Collider Enabled");
attackTrigger.enabled = true;
StartCoroutine(DisableCollider());
}
}
IEnumerator DisableCollider()
{
yield return new WaitForSeconds(1);
attacking = false;
attackTrigger.enabled = false;
Debug.Log("Box Collider Disabled");
}
*2nd script:
public float damage = .10f;
private void OnTriggerEnter2D(Collider2D collision)
{
if(collision.isTrigger!=true && collision.CompareTag("Enemy"))
{
Debug.Log("Enemy is Damaged");
EHealthBar.TakeDamage(damage);
}
}
i'm trying to get my player character to attack an enemy using collision, well it does work and the player does damage the enemy but it will only work if the enemy's box collider enters my attack again.
if the enemy is already in my area of attack which has a box collision 2d attached, the enemy doesn't get damaged and that's not what i was going for.
I can change it to OnTriggerStay2D but the enemy will keep on getting damaged till the collider is disabled again. care to help?
I think the problem is
IEnumerator DisableCollider()
{
yield return new WaitForSeconds(1);
attacking = false;
...
which causes that your IF statement in your update is still occuring for 1 second and starting a lot of coroutines. The easiest solution would be moving attacking = false; before yield, but i guess you want to use that variable to be aware if user is in attack state. So i suggest to use another bool variable.
if (invokeAttack)
{
attacking = true;
invokeAttack = false
Debug.Log("Box Collider Enabled");
attackTrigger.enabled = true;
StartCoroutine(DisableCollider());
}
Anyway, you didn't show us how you invoke attack, but maybe instead of changing variable (attacking/invokeAttack in your case) to true and checking it in Update you just invoke a method which enables collider and starts coroutine?

Unity 2D: Collision trigger

So here it is, Iam making a game for my thesis. The game is called hacky sack, Iam having a problem when my trigger is true because the collision for my character and the object is passing through and if idon`t have a trigger it was just basically hitting it even when my Player is running.
And can you guys help me on how the Object/Sack going up randomly when it hit. So here is my code :
public void Sipa()
{
if (canSipa == true)
{
_pitcha.GetComponent<Rigidbody2D>().AddForce(new Vector2(-400, 1000));
}
}
}
And here is for my object
private void OnTriggerEnter2D(Collider2D collision)
{
if(collision.gameObject.tag == "Player")
{
_player.GetComponent<PlayerManager>().canSipa = true;
}
}
private void OnTriggerExit2D(Collider2D collision)
{
if (collision.gameObject.tag == "Player")
{
_player.GetComponent<PlayerManager>().canSipa = false ;
}
}
}
add a second collider, slightly larger then the first, mark it trigger. leave the smaller inner collider for physics. you "foot" should enter the trigger and activiate it, then collide with the inner collider. make sure the collider marked trigger is the larger one.

Unity 2D Platforms Show on Collision

How can I make a group of platforms appear when colliding with it's trigger?
I would like to walk into the trigger, which will turn on the 'StarPlatforms' in the inspector, revealing every thing that is a child of it. I have only got it to do the exact opposite:
Before collision
After Collision
Children of StarPlatfroms
The script on the StarPlatforms:
public class AppearTrigger : MonoBehaviour {
private GameObject StarPlatforms;
void Start() {
StarPlatforms = GameObject.Find("StarPlatforms");
StarPlatforms.gameObject.SetActive (true);
}
void OnTriggerStay2D (Collider2D col) {
if (col.gameObject.tag == "Player") {
StarPlatforms.gameObject.SetActive (false);
}
}
}
I have tried swapping the .SetActives too false then true and it unchecks in the inspector on Play but stays hidden on collision with the trigger.
Thank you for your time.
ps: this is my first go at Unity & C#
SetActive just sets whether it is part of the main game loop or not. To make a platform invisible or visible use it's Renderer component and deactivate that instead.
gameObject.GetComponent<SpriteRenderer>().enabled = false;
I would like to walk into the trigger, which will turn on the
'StarPlatforms' in the inspector. I have tried swapping the .SetActives too false then true
You seem to be guessing which one works. This is how SetActive work:
To turn on or activate an object, pass true to SetActive. To turn it off or deactivate it, pass false to it. Also, this should be done in the OnTriggerEnter2D function not OnTriggerStay2D.
The OnTriggerStay2D function is called when collision each frame collision is still touching. The OnTriggerEnter2D function is called when there is a collision. OnTriggerExit2D is called when there is no longer a collision.
void OnTriggerEnter2D (Collider2D col)
{
if (col.CompareTag("Player"))
{
StarPlatforms.gameObject.SetActive (true);
}
}
If you also want to turn it of or de-activate it when they no longer touch, pass false to the SetActive function in the OnTriggerExit function.
void OnTriggerExit2D(Collider2D col)
{
if (col.CompareTag("Player"))
{
StarPlatforms.gameObject.SetActive (false);
}
}
Not related to your issue but it's a good practice to use CompareTag instead of gameObject.tag.
This is what worked:
public class AppearTrigger : MonoBehaviour {
GameObject[] StarPlatfromArray;
void Start() {
StarPlatfromArray = GameObject.FindGameObjectsWithTag("Cave");
for (int i = 0; i < StarPlatfromArray.Length; i=i+1) {
StarPlatfromArray [i].gameObject.GetComponent<BoxCollider2D> ().enabled = false;
StarPlatfromArray [i].gameObject.GetComponent<SpriteRenderer> ().enabled = false;
}
}
void OnTriggerEnter2D (Collider2D col) {
StarPlatfromArray = GameObject.FindGameObjectsWithTag("Cave");
for (int i = 0; i < StarPlatfromArray.Length; i++) {
StarPlatfromArray [i].gameObject.GetComponent<BoxCollider2D> ().enabled = true;
StarPlatfromArray [i].gameObject.GetComponent<SpriteRenderer> ().enabled = true;
}
}
}

Categories