Hey all! I have been trying to solve this for a day now. Searched everywhere, but couldnt find the answer. Perhaps this is the right place to ask. I have a 2d platformer. I want to create chest that spits out coins when i hit it. But i want the coins to kind of splash out of the chest. I could achieve that, by adding force the the coins when they are created. The coin have both rigidbody2d (in order so that i can use addforce and bouncing and stuff) and Boxcollider2D (so that it will not just fall through the ground and so that it can be detected by player etc).
My problem:
When my player hits the coin he kind of bumps into it. For instance if my character is in the air and hits the coin it will break his momentum. The coin works like an obsticle and i dont want that.
I want the coin just to dissapear when player hits it.
Now i have tried many different things. If you make boxcollider âisTriggerâ the coin will just fall.
I tried to play around with the layer Matrix - to make the coin only be affected by ground layer for instance. But then i cannot register when the player is colliding with it.
It feels like it should be not so complicated but i cant achieve the desired effect. Please help.
This is the code for the coin:
[code=CSharp]using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Coinscript : MonoBehaviour
{
public Player_animation player;
public Rigidbody2D rb;
public int force = 6;
void Start()
{
rb = GetComponent<Rigidbody2D>();
rb.AddForce(new Vector3(0, 1, 0) * force, ForceMode2D.Impulse);
}
void Update()
{
}
void OnCollisionEnter2D(Collision2D col)
{
if (col.gameObject.CompareTag("Player"))
{
print("coin");
player.coins += 1;
Destroy(this.gameObject);
}
}
void OnTriggerEnter2D(Collider collider)
{
if (collider.CompareTag("Player"))
{
print("coin");
player.coins += 1;
Destroy(this.gameObject);
}
}
}
[/code]
Note: The reason why i have both OnTriggerEnter2D and OnCollisionEnter2D is only because i tried both in hope that something would work.
This is the code for the chest:
[code=CSharp]using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Chest : MonoBehaviour, IDamageable
{
private int maxHealt = 10;
public int currentHealth;
public Animator anim;
private int counter = 1;
public bool closed = true;
public GameObject coin;
void Start()
{
currentHealth = maxHealt;
anim = GetComponent<Animator>();
}
public void takeDamage(int damageAmount)
{
if(closed)
{
currentHealth -= damageAmount;
if (currentHealth <= 0)
{
anim.SetTrigger("open");
Open();
closed = false;
}
}
}
public void Open()
{
while (counter < 5)
{
counter++;
Instantiate(coin, transform.position, transform.rotation);
}
}
}
Yo! Just a quick one firstly, if you paste your code into the bit that says âCodeâ itâll format it for you so itâs easier to read
What Iâd do here is Iâd change your Rigidbody2D to a BodyType of Kinematic. Iâd then place a Collider2D (I imagine a circle in this case) and then make that a trigger. In your script youâd then have something like:
void OnTriggerEnter2D(Collider2D other)
{
if (other.CompareTag("Player")) {
// Do stuff here
}
}
You can actually optimize this code using the collision matrix however, this is where the matrix and layers come into play. So say you only want the player to interact with the coin, to pick the coin up, youâd create a âPlayerâ layer and a âCoinâ layer, or âItemâ layer. Youâd configure this in the matrix, so keep it ticked, but untick all others. This way, your code is not constantly checking if itâs a player thatâs walked over the coin. Imagine if you had a bunch of enemies on screen and they were all walking over the coin, itâd be pointlessly checking to see if itâs the player, if the player is the only thing that can interact with a coin
EDIT: I didnât notice that youâre adding forces which wonât work for a Kinematic RB. Perhaps keep a Dynamic one but alter the gravity to 0, if you donât want any gravity
Thanks for the answer, but the problem is that i dont want interact with the coin on âphysicalâ level. I just want to "go right trought it " but still pick it up. I have a separate layer for the coin and for the player.
Dou you mean that i have to create an empty gameobject (with layer other than player) on my player and set up a collider on it?
If you set up a collider with âisTriggerâ active, itâll achieve the effect of going right through it.
so your player should have a RB and a collider, then your coin should have a RB and a collider, but set that collider on the coin to âisTriggerâ and the RB to have a gravity of 0 if you donât want any gravity to effect the coin.
In regards to Layers, these can be used with the matrix to optimize your code. They are tick boxes saying I want these two things to be able to interact with each other. Unticking them will make it so they literally donât care about each other, this is even true for onTrigger events.
This video is excellent for explaining Layers in Unity:
The only issue with this is that if he wants the coins to explode out of chests and collide with the ground, having a trigger collider wonât work unless he codes the movement from scratch.
This is a bit tricky, because you want the collision to be detected and ignored at the same time. However, itâs still doable with a child of the player detecting the coin.
Here is an example setup that Iâve tested and works:
The only object with âIsTriggerâ checked is the âCoin_Detector.â The player and coin objects are set to ignore each otherâs collision in the collision matrix, and the coin detector is what picks up the coins. So the coin passes through the player, but is still picked up by the coin detector.
Thanks man! Yea it did work.
I created a gameobject on the player with âsTriggerâ collider. This do work but now i faced other issue. So the script for the chest that i posted. It only destroys the original coin.
I dragged the original point to the project so it bacame prefab. Then i dragged the prefab to the chest script (I made a public gameObject for the coins that will be destroyed). Any suggestion why it wont work?
Firstly, can you edit your original post so itâs formatted nicely like NeilB133 suggested: Using code tags properly
What do you mean by it destroys the original? In your coin script, you have the line Destroy(this.gameObject). That line will destroy the object the script is attached to. If youâre instantiating coins in the game, each coin instance will destroy itself with that line.
what i meant that i wrote the code for the coin.
then dragged coin to the assets so its created a prefab. Then i dragged the prefab into the chest code (as public gameObject).
but they dont destroy on collision. There is a collision ( i print text with the collision) but they dont destroy
Okay⌠first of all, your code has errors. void OnTriggerEnter2D(Collider collider) should be void OnTriggerEnter2D(Collider2D collider) (missing â2Dâ after âColliderâ). Do you not see red errors in the console when you run your game? That should be the first sign that something is wrong.
You donât need the OnCollisionEnter2D method in your coin script, if youâre unsure which method is the correct one to use, try them both; donât just use both.
I tried the code with the above correction and it works. Try again, and make sure you arenât getting any errors.
Still dont work for me. I restarted Unity and everything. Check this out
This is the code for the coin
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Coinscript : MonoBehaviour
{
public Transform coincollision;
public Rigidbody2D rb;
public Player_animation player;
public int force = 6;
void Start()
{
rb = GetComponent<Rigidbody2D>();
rb.AddForce(new Vector3(0, 1, 0) * force, ForceMode2D.Impulse);
}
void OnTriggerEnter2D(Collider2D collider)
{
if (collider.CompareTag("coincollision"))
{
print("coinamana");
player.coins += 1;
Destroy(this.gameObject);
}
}
}
this is the code for the chest
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Chest : MonoBehaviour, IDamageable
{
private int maxHealt = 10;
public int currentHealth;
public Animator anim;
private int counter = 1;
public bool closed = true;
public GameObject coin;
void Start()
{
currentHealth = maxHealt;
anim = GetComponent<Animator>();
}
public void takeDamage(int damageAmount)
{
if(closed)
{
currentHealth -= damageAmount;
if (currentHealth <= 0)
{
anim.SetTrigger("open");
Open();
closed = false;
}
}
}
public void Open()
{
while (counter < 5)
{
counter++;
Instantiate(coin, transform.position, transform.rotation);
}
}
}
And once again just to be clear. This code works for one coin that i attached coin script to. It doesnt work for prefabs of that coin.
As it stands now, youâd have to have a GameObject with a collider set-up to contact the ground to cause bouncing etc and a child GameObject with a collider (as a trigger) set-up to contact the player only. This is less than ideal.
In 2022.2 this kind of thing will be much easier because you can control in a very fine-grained way, what forces can be sent/received to the pair of objects in contact. In your case above, you could say that you donât want the player collider to receive from the coin layer. This doesnât stop the coins themselves from contacting the player (you still get the expected callbacks), simply that the player wonât have its velocity changed at all. Also, specify/override layers per Rigidbody2D/Collider2D.