How to check which objects collide - collision

i have an example : player object, obstacle_1 object and obstacle_2 object. How do I check which one player collides with? I mean I want to do script_1 for colliding player with obstacle_1 and do script_2 when player collides with obstacle_2. Example:
private void OnTriggerEnter2D(Collider2D collision)
{
//script 1 when this object(player) collides with obstacle_1;
//script 2 when this object(player) collides with obstacle_2;
}

It seems like you're asking how to differentiate between objects. There are many ways of doing so, and it's hard to say which will work best for you since you didn't give a lot of context. Here are some ideas:
One of the simplest ways would be comparing the object's names:
private void OnTriggerEnter2D(Collider2D collision)
{
if(collision.gameObject.name == "Obstacle_1"){
//React to obstacle 1
}
else if (collision.gameObject.name == "Obstacle_2"){
//React to obstacle 2
}
}
I really wouldn't encourage this though, since the name of the objects can be changed quite easily.
You could add Tags to obstacle_1 and obstacle_2, and compare tags, like:
private void OnTriggerEnter2D(Collider2D collision)
{
if(collision.gameObject.CompareTag("Obstacle 1")){
//React to obstacle 1
}
else if (collision.gameObject.CompareTag("Obstacle 2")){
//React to obstacle 2
}
}
This is a bit better, since changing tags is not as easy as changing names, but there's still room for spelling errors. Comparing strings is not very efficient either, especially if done frequently.
You could create different components for obstacle_1 (BouncyObstacle) and obstacle_2 (SpikeObstacle), and then have your player try to get these components, like:
private void OnTriggerEnter2D(Collider2D collision) {
if(collision.gameObject.TryGetComponent(out BouncyObstacle bouncyObs){
// React to bouncy obstacle
}
else if(collision.gameObject.TryGetComponent(out SpikeObstacle spikeObs)
{
//React to spike obstacle
}
}
This is a little bit better, but every time you want to add a new obstacle, you need to add an if to your player code.
Again, it's hard to say which solution would be best. From your snippet, it seems like the player class is responsible for reacting to the obstacles, and this means that every time you want to add a new obstacle, you need to open the player class and change the OnTriggerEnter method. Perhaps it would be better to move this responsibility to separate components. That way you'll be able to add as many obstacles you want without changing any of the previous classes you made. Something like:
public class BouncyObstacle : MonoBehaviour
{
void OnTriggerEnter2D(Collider2D other)
{
if(other.TryGetComponent(out Player player))
{
player.Bounce();
}
}
}
public class SpikeObstacle : MonoBehaviour
{
void OnTriggerEnter2D(Collider2D other)
{
if(other.TryGetComponent(out Player player))
{
player.Kill();
}
}
}
// etc..

Related

How to ignore one OnTrigger Collider in an Object?

I have 3(Three) BoxCollider2D components where 2(two) have OnTrigger checked in my Object and both have different functions. Due to having OnTrigger on both, the projectiles I am casting collide with the wrong collider and instead activate that function. Is there a way to ignore 1(one) OnTrigger collider?
I have already tried Layer-based collision detection and set up a layer. Unfortunately, the object now collides with the collider which eliminates the player on collision
However, there are several ways to solve this problem. All kinds of physics.checks as well as raycasts but this code helps you to ignore the obstacle collider.
public Collider2D playerCollider;
public Collider2D obstacleCollider;
public void Start() => Physics2D.IgnoreCollision(playerCollider, obstacleCollider);
I have a very simple script I use to handle collisions in my games.
It's very easy to setup because it makes everything drop and draggable, which is a much easier way to program.
Below is the script and below that is instructions on how to use. Note it is a layer based system, but you can select multiple layers.
[System.Serializable]
public class TriggerEvent : UnityEvent<Collider> { }
[System.Serializable]
public class CollisionEvent : UnityEvent<Collision>{ }
public class EnterEvent: MonoBehaviour
{
public TriggerEvent TriggerEnteredEvent;
public CollisionEvent CollisionEnteredEvent;
[SerializedField]private LayerMask validLayers;
// Initalize Event System
void Awake()
{
if (OnTriggerEnter == null)
{
TriggerEnteredEvent = new TriggerEvent();
}
if (OnCollisionEnter == null)
{
CollisionEnteredEvent = new CollisionEvent();
}
}
// Called if transform is a trigger
void OnTriggerEnter(Collider collider)
{
if (validLayers == (validLayers | 1 << collider.gameObject.layer))
{
TriggerEnteredEvent?.Invoke(collider);
}
}
// Called if transform is not a trigger
void OnCollisionEnter(Collision collision)
{
if (validLayers == (validLayers | 1 << collision.gameObject.layer))
{
CollisionEnteredEvent?.Invoke(collision);
}
}
}
This is how it would work, and in this example I will be "coding" it from the perspective of a Bullet.
Basically I want to check if I (The Bullet) hits either the terrain or an enemy then call the relevent funcitons in the Bullet class respectively.
Obviously if I hit an enemy I want to deal damage.
So this will be my example bullet class
public class Bullet : MonoBehaviour
{
public int BulletDamage = 10;
public int BulletSpeed = 5;
void FixedUpdate() => transform.position = Vector3.Lerp(transform.position, transform.position + transform.forward * speed * Time.deltaTime, 1f);
public void OnEnemyHit(Collision collision)
{
// Try to get the enemy script
Enemy enemy = collision.gameObject.transform.GetComponent<Enemy>();
if (enemy != null)
{
enemy.DealDamage(this.BulletDamage);
}
}
public void OnTerrainHit(Collision collision)
{
Destroy(this.gameObject);
}
}
Add the EnterEvent script to the bullet.
Add the Bullet Script to the bullet.
There will be a space on the Inspecter where you can add your events. It should have a Plus and Minus in the top right corner. Press the plus.
From the inspector drag the bullet in game GameObject to the open space provider.
In the dropdown to the right, click on it, look for the Bullet Script, and select the OnEnemyHit function from it.
Create another event, do the exact same, but this time select the OnTerrainHit funciton instead - now but would be called in the order you added them.
Just underneath the event system should be the be able to see a dropdown for the Layers. Select all the layers you want your bullet to interact with. In this case it will be the Enemy and Terrain.
Finally remember to setup your layers properly. Ensure the Enemy has an Enemy Layer, the Terrain has a Terrain Layer, Bullet bullet layer and Player has a Player Layer

Play a particle system when Time.timeScale = 0?

I have a particle system explosion that I want to play when the player dies. The idea that is that everything else pauses but the explosion continues, like the Pacman animation when you die (everything freezes and the pacman death animation plays).
Trouble is, it won't work. I know Time.timeScale = 0 pauses everything, and I've tried using this script to combat that, but it doesn't seem to be working:
void Update()
{
if (Time.timeScale < 0.01f)
{
particleSystem.Simulate(Time.deltaTime, true, false);
}
}
I have also tried this, but it doesn't work either:
private ParticleSystem pSystem;
public void Awake()
{
pSystem = gameObject.GetComponent<ParticleSystem>();
}
public void Play()
{
pSystem.Simulate(Time.unscaledDeltaTime,true,true);
}
public void Update()
{
pSystem.Simulate(Time.unscaledDeltaTime,true,false);
}
I have tried this code with a script that is attached to my explosion particle system prefab, which is instantiated at the player's position when you die.
Thanks!
UPDATE:
Turns out I had tried using particleSystem.Simulate(Time.unscaledDeltaTime, true, false);, but I was calling it in FixedUpdate() rather than Update().
However, the Asteroid Base post below posted by Garfty is really interesting and is probably worth doing in the long run!
One way you could do it is by using Time.unscaledDeltaTime
Another way you could approach something like this is by creating your own time manager, but it requires some discipline to stick to. The people at Asteroid Base wrote a nice article on something like this here.
I hope this helps!

Is there a better readable way to write this if statement chain?

I have the following code:
Creature::cancelWalk()
{
Player* player = getPlayer();
if (!player) {
if (getMonster() && getMonster()->getMaster() && getMonster()->getMaster()->getPlayer()) {
player = getMonster()->getMaster()->getPlayer();
}
}
if (player) {
player->sendCancelMessage(ret);
player->sendCancelWalk();
}
}
After a brief analysis, it's easy to understand I want to achieve something simple:
If the creature is the player itself, then sendCancelMessage and sendCancelWalk. Else, if the creature is a monster that also has a master that is a player, send the same stuff to the client.
Is there a better way to write this code without adding other methods on Monster, Creature and Player classes?
Monster and Player both are "siblings" deriving from Creature.
Assuming the various functions don't have different effects on multiple calls, try introducing some temporaries.
Player* player = getPlayer();
if (!player)
{
Monster monster = getMonster();
if (monster)
{
Master *master = monster->getMaster();
if (master) player = master->getPlayer()) {
}
}
if (player) {
player->sendCancelMessage(ret);
player->sendCancelWalk();
}
Beyond that, you might want to look more carefully at your design. If you have lots of nested pointers that you need to sequentially check for NULL before dereferencing, it might be worth specifying and enforcing invariants that the pointers are not NULL (which means only construct parent objects if all the component parts can be created, and never construct objects if they can only be partially constructed).
For example, if we assume that getMonster() returns non-NULL which guarantees that getMaster() and getPlayer() also don't return NULL ....
Player* player = getPlayer();
if (!player)
{
player = getMonster()->getMaster()->getPlayer());
}
if (player)
{
player->sendCancelMessage(ret);
player->sendCancelWalk();
}

modules contract by interface, diagram, logic, general informations

Here is my question, I hope that I'll write it correctly because it is a precise question.
I wonder how to use the interfaces as a contract between two modules. When I draw the module diagrams I never knows which of the modules as the circle and which has the half-open circle. A clear way on how to make the distinction would be very appreciated!
I don't want an example on how to use an interface because I know the properties of the interfaces (behaviors, etc).
Let's say that I got 2 modules, one contains the Bussiness logic, so I'll call it "Model", the other contains the GUI so I'll call it "View".
The view needs a Treeview and a Matrix on each nodes. So we got a tree-like hierarchie that the Model knows about, and for each node we want to fill a matrix of values.
root
- node1
-- leaf1
-- leaf2
- node2
- node3
-- leaf3
-- leaf4
My guts are telling me that I should do something like this:
interface IModelHierarchicMatrix {
void setTreeViewValues(TreeViewModel treeview);
void getMatrixValues();
void setMatrixValues(int[] values);
}
class Model implements IModelHierarchicMatrix {
// the code where I override the interface's function
}
So nice, we can call the needed function for the GUI at the Model. But how can we tell the GUI's class that we need that kind of behaviors (class, etc)...
I find myself often doing this kind of thing:
interface IModelHierarchicMatrixGlue {
void acceptModel(IModelHierarchicMatrix model);
}
class Gui implements IModelHierarchicMatrixGlue {
private IModelHierarchicMatrix model;
...
#Override
public void acceptModel(IModelHierarchicMatrix model) {
if (this.model == null) {
this.model = model;
}
}
}
But I always wonder if it's a good way of creating the contract between the Model and the View.
If I got to create a bi-directional contract between the Modules, how should I do that? Because it might create a cyclic logic between the interfaces...
I hope my question was clear enough, thanks in advance.

Condition check inside a function or before its call?

Which of these 2 programming styles do you prefer? Why? Are there particular advantages to one over the other?
// Style 1
if (doBorder)
doTheBorder();
if (doFrame)
doTheFrame();
if (doDraw)
doTheDraw();
void doTheBorder()
{
// ...
}
void doTheFrame()
{
// ...
}
void doTheDraw()
{
// ...
}
// Style 2
doTheBorder();
doTheFrame();
doTheDraw();
void doTheBorder()
{
if (!doBorder)
return;
// ...
}
void doTheFrame()
{
if (!doFrame)
return;
// ...
}
void doTheDraw()
{
if (!doDraw)
return;
// ...
}
The first. The second seems to be... lacking in confidence. Why call doTheBorder() if you don't even know if you want the border to be done? IMO, you should assert that the border really needs doing, and then call doTheBorder() with confidence!
...Also, from a more technical point of view: if doTheBorder() is in a closed API, a developer in the distant future might call it and if the second style is employed, they may wonder why the border didn't get done, despite their call to doTheBorder(). Of course, sometimes certain circumstances or restrictions or limitations may dictate that the second style be used, but I'd avoid it when possible.

Resources