Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Break gameobject on collision when button pressed?

Discussion in '2D' started by j7stin, Jan 22, 2020.

  1. j7stin

    j7stin

    Joined:
    Jan 7, 2020
    Posts:
    22
    Hi everyone,

    I made a thread similar to this one not very long ago but I've changed my system a bit.

    upload_2020-1-22_16-54-54.png

    upload_2020-1-22_16-55-11.png

    Basically, I want the player to be able to break the block underneath them when the 'Dig' button is pressed.

    The following is what I am using at the moment (credits to @APSchmidt lol)
    When I bind the script to my button, nothing happens though. Please help :)

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class ButtonHandler : MonoBehaviour
    6. {
    7.     // Start is called before the first frame update
    8.     void Start()
    9.     {
    10.  
    11.     }
    12.  
    13.     public void OnCollisionEnter2D(Collision2D other)
    14.     {
    15.         GameObject player = GameObject.FindGameObjectWithTag("Player");
    16.  
    17.         Vector3 hitPosition = player.transform.position + new Vector3(0f, -0.5f, 0f);
    18.  
    19.  
    20.         if (other.gameObject == other.gameObject)
    21.         {
    22.             Destroy(other.gameObject);
    23.         }
    24.     }
    25. }
     
  2. Deleted User

    Deleted User

    Guest

    So that the script works, your player must be on the tile that is over the place where the tile must be removed.

    Your player must have the "Player" tag.
     
  3. j7stin

    j7stin

    Joined:
    Jan 7, 2020
    Posts:
    22
    Hey thanks for the quick reply and sorry to keep on having to bother you. I have the player assigned to the player tag and the script was working with tiles but I want it to only break a tile when my player is colliding with a tile AND when a button is pressed and I would just use an if statement for that but that doesn't work as far as I'm aware
     
  4. Deleted User

    Deleted User

    Guest

    Could you post your code please, with the if statement and all and provide an image of the button? :)
     
  5. j7stin

    j7stin

    Joined:
    Jan 7, 2020
    Posts:
    22
    I did above, the 2nd picture shows the button in the bottom right and then the code that I used is at the bottom of the thread, I didn't use an if statement I was just thinking about an alternate solution. I then just did this to the button
    upload_2020-1-22_17-22-37.png

    Inside of the ButtonHandler script is the code above. I tried to add the Button Handler as a component and then drag the Button in instead of the script like this

    upload_2020-1-22_17-24-5.png

    But when I do that I can't call any functions and the button is useless.
     

    Attached Files:

  6. Deleted User

    Deleted User

    Guest

    Your button OnClick event doesn't have any function added; that's why it's not working. Adding the game object is not enough, you must also add the function that the button must use.

    Try adding the OnCollisionEnter2D function to the button and see if it works. If it doesn't you'll have to rewrite your script, create a public function that contains OnCollisionEnter2D and add that function to the OnClick function of the button.

    The documentation about the button explains it all: https://docs.unity3d.com/Packages/com.unity.ugui@1.0/manual/script-Button.html
     
  7. j7stin

    j7stin

    Joined:
    Jan 7, 2020
    Posts:
    22
    That's what I've been trying to do for like 2 hours but I don't know why I can't call the OnCollisionEnter2D function :(
     
  8. Deleted User

    Deleted User

    Guest

    If it doesn't you'll have to rewrite your script, create a public function that contains OnCollisionEnter2D and add that function to the OnClick function of the button.
     
  9. ShervinM

    ShervinM

    Joined:
    Sep 16, 2017
    Posts:
    67
    This is the key. Always great when you can think about the logic at a high level first. Like you said, a block should only break if:
    1. The player is above it (ie touching it)
    2. The player clicks the dig buttons while (1) is true.

    To answer why you cant select
    OnCollisionEnter2D 
    from the functions list: Acceptable function signatures that can be selected from this drop down menu must be:
    1. public
    2. accept 0 or 1 arguments (only of type float, int, string, bool or unity object).

    OnCollisionEnter2D 
    unfortunately doesn't fit that requirement as it takes a Collision2D object as it's one argument.

    That said, if you think about it a bit more, you might see that your
    OnCollisionEnter2D 
    function shouldn't be the function handling the deletion/block breaking in the first place. Now theres many ways you can do this, but let me suggest one approach.

    Let
    OnCollisionEnter2D 
    simply turn on a flag that indicates your player is touching the ground (if indeed it is)

    Code (CSharp):
    1. public void OnCollisionEnter2D(Collision2D other)
    2. {
    3.  
    4.     if (other.gameObject.tag == "Ground"
    5.     {
    6.         touchingGround = true;
    7.     }
    8.  
    9. }
    10.  
    Additionally, don't forget to flip this flag to false whenever your player is not touching some breakable ground (or jumping).


    where
    touchingGround 
    is a boolean defined as a class member.

    Now, create another function called
    OnDigButtonPressed 
    that you can hook up to your button. Now everytime the button is pressed, this function will check if the player is touching the ground. If they are, then go ahead and find/destroy the object below you.

    Code (CSharp):
    1. public void OnDigButtonPressed()
    2. {
    3.     if (touchingGround)
    4.     {
    5.         <<code to delete the tile/block/object right below the player>>
    6.     }
    7. }
    Alternatively, if you dont want to search / get the object below you everytime, you could cache it on the
    OnCollisionEnter2D 
    call, and the try and destroy it in the
    OnDigButtonPressed
    .
     
  10. j7stin

    j7stin

    Joined:
    Jan 7, 2020
    Posts:
    22
    Hey thank you so much for the reply! :)

    I'm trying to get everything together now and make it work, I haven't checked the forum for the past few days because I kinda forgot it existed but oh well. Anyways, I'll let you know how it goes :D
     
  11. Deleted User

    Deleted User

    Guest

    I had to rewrite my script entirely because OnCollisionEnter2D works only on the current frame. This is probably why your button didn't work.

    In my case, I'm using a raycast to make sure the player is near the wall and then I play a function in Update().

    In your case, you would need only one line using Vector2.down.
    Code (CSharp):
    1. RaycastHit2D bodyContactDown = Raycast(new Vector2(0f, 0f), Vector2.down, contactOffset);
    2.    
    3. if(bodyContactDown)
    4.     isBodyContact = true;
    where contactOffset is a float representing the length of the raycast on the y axis.

    Then, replacing OnCollisionEnter2D by Update() so that your button works even if you have waited before clicking on it. I use Invoke() so that the tiles disappear after the animations have finished playing.

    In your case, hitPosition would take only one line that could be:
    Code (CSharp):
    1. hitPosition = player.transform.position + new Vector3(0, -1f, 0f);
    And in Update():
    Code (CSharp):
    1. private void Update()
    2. {
    3.     if(isBodyContact && Input.GetKeyDown(KeyCode.X))
    4.     {
    5.         Invoke("ClearTheWay", 1.5f);
    6.     }
    7. }
    8.  
    9. public void ClearTheWay()
    10. {
    11.     hitPosition = player.transform.position + new Vector3(0, -1f, 0f);
    12.     map.SetTile(map.WorldToCell(hitPosition), null);
    13. }
     
    Last edited by a moderator: Jan 25, 2020
  12. j7stin

    j7stin

    Joined:
    Jan 7, 2020
    Posts:
    22
    Raycast is not recognised on the RaycastHit2D bodyContactDown = Raycast
    My game is based on sprites now, not a tilemap anymore meaning I can't use the map.SetTile line and I have to use Destroy and I don't really know how to use it with the rest of the code.
    I feel really dumb for not being able to figure this out myself it seems like it should be so easy..
     
    Last edited: Jan 25, 2020
  13. Deleted User

    Deleted User

    Guest

    Maybe you should go back to the version of your game where you used tilemaps, now that you have the code that works. Or post your entire code and explain what you are doing exactly and what you want to do. :)
     
  14. j7stin

    j7stin

    Joined:
    Jan 7, 2020
    Posts:
    22
    I could post a video if it helps but I'll try just sending you some scripts I currently have.

    My DestroyTile script which I want to be attached to a button. I am currently just using this to constantly dig down and have it attached to the player so I at least have my digging working.

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using UnityEngine.UI;
    5. using UnityEngine.EventSystems;
    6.  
    7. public class DestroyTile : MonoBehaviour
    8. {
    9.  
    10.     public void OnCollisionEnter2D(Collision2D other)
    11.     {
    12.         GameObject player = GameObject.FindGameObjectWithTag("Player");
    13.  
    14.         Vector3 hitPosition = player.transform.position + new Vector3(0f, -0.5f, 0f);
    15.  
    16.         if (other.gameObject.GetComponent<TileData>() != null)
    17.         {
    18.             GetComponent<Inventory>().Add(other.gameObject.GetComponent<TileData>().tileType, 1);
    19.             Destroy(other.gameObject);
    20.         }
    21.     }
    22.  
    23.     public void onDigButtonPressed()
    24.     {
    25.      
    26.     }
    27.  
    28. }
    The game uses prefabs for its map. Every prefab has a script called TileData attached to it where I give them a TileData ID (0 = Grass, 1 = Dirt, 2 = Coal etc..)

    My DestroyTile script has to destroy the tile underneath the player when they press dig and also grab the TileData from the tile destroyed so that it can be stored in my Inventory script which then shows what ores the player has mined in total.

    I don't really know if this is helpful and I've tried actually adding things to onDigButtonPressed() and doing the things that you've told me to do but it didn't work in the end so I kept it like that but I am still trying my best to fix it so that the onDigButtonPressed() function can be called on the button. Like I said, I can record a video of my Unity and everything if you'd like me to. Thanks again :)

    I would use tiles instead of sprites/prefabs but I don't know how to add scripts to tiles..

    EDIT: I deleted my map and am trying to switch to a tilemap system but like I said, I don't know how to add scripts to tilemaps for my inventory
     
    Last edited: Jan 26, 2020