英文:
How to block one collider behind another in Unity
问题
Is there a way to block one collider object behind the other in a 2D Unity game?
我可以尝试帮助您解决这个问题。
I have colliders for enemies walking on screen but if the enemies walk behind barriers (which have their own colliders), the enemy colliders still respond to the player bullets.
我有敌人的碰撞体在屏幕上移动,但是如果敌人走到障碍物的后面(障碍物有它们自己的碰撞体),敌人的碰撞体仍然会对玩家的子弹做出响应。
So basically i just want to expose the enemies only when they are not behind any barriers.
所以基本上我只想在敌人不在任何障碍物后面时暴露它们。
Currently my bullets go through the barriers and detect the enemies.
目前我的子弹会穿过障碍物并检测到敌人。
I have placed enemies and barriers on separate UI panels and layers but that is just distinguishing them visually. From collision point of view how do i make one (barrier) take priority over the other (enemy)?
我已经将敌人和障碍物放在不同的UI面板和层上,但这只是在视觉上区分它们。从碰撞的角度来看,我如何使一个(障碍物)优先于另一个(敌人)?
英文:
Is there a way to block one collider object behind the other in a 2D Unity game?
I have colliders for enemies walking on screen but if the enemies walk behind barriers (which have their own colliders), the enemy colliders still respond to the player bullets. So basically i just want to expose the enemies only when they are not behind any barriers.
Currently my bullets go through the barriers and detect the enemies.
I have placed enemies and barriers on separate UI panels and layers but that is just distinguishing them visually. From collision point of view how do i make one (barrier) take priority over the other (enemy)?
答案1
得分: 0
You could use Raycast methods. You can cast a ray from the player position to the enemy position, if it detects a wall in the middle you don't allow them to shoot.
public LayerMask wallsLayer;
bool HasPathFreeOfWalls(Transform player, Transform enemy, float reticleRadius)
{
Vector2 direction = enemy.position - player.position;
Vector2 origin = player.position + (direction.normalized) * reticleRadius;
float distance = direction.magnitude - reticleRadius;
RaycastHit2D rayHit = Physics2D.Raycast(origin, direction, distance, wallsLayer);
return rayHit.transform == null; // if does not hit anything, it means that the path is free of walls
}
Edit to match game description
One way of doing this is offsetting all the colliders to be above the pivot points of their respective gameObjects, like this.
Then you cast a CircleCast around the reticle to detect all objects there and check which one has the lowest Y position, meaning the one that is in the front. Like this:
public LayerMask enemysAndWallsLayers;
bool HasEnemyInFront(Vector2 reticlePosition, float reticleRadius)
{
RaycastHit2D[] enemysAndWallsHitted; // holds the results of the circle cast
ContactFilter2D collisionFilter = new ContactFilter2D(); // filter user by the circleCast
collisionFilter.layerMask = enemysAndWallsLayers;
collisionFilter.useLayerMask = true;
Physics2D.CircleCast(reticlePosition, reticleRadius, Vector2.zero, collisionFilter, enemysAndWallsHitted, 0);
GameObject closestGameObject = null;
float closestY = Mathf.Infinity;
foreach(RaycastHit2D objHitted in enemysAndWallsHitted)
{
if(objHitted.transform.position.y < closestY)
{
closestY = objHitted.transform.position.y;
closestGameObject = objHitted.transform?.gameObject;
}
}
return closestGameObject != null && IsGameObjectEnemy(closestGameObject );
}
The IsGameObjectEnemy()
function has to be implemented by you in a way that you can tell if it is an enemy or a wall.
英文:
You could use Raycast methods. You can cast a ray from the player position to the enemy position, if it detects a wall in the middle you don't allow them to shoot.
public LayerMask wallsLayer;
bool HasPathFreeOfWalls(Transform player, Transform enemy, float reticleRadius)
{
Vector2 direction = enemy.position - player.position;
Vector2 origin = player.position + (direction.normalized) * reticleRadius;
float distance = direction.magnitude - reticleRadius;
RaycastHit2D rayHit = Physics2D.Raycast( origin , direction, distance, wallsLayer);
return rayHit.transform == null; // if does not hit anything, it means that the path is free of walls
}
Edit to match game description
One way of doing this is offsetting all the colliders to be above the pivot points of their respectivelly gameObjects, like this.
Then you cast a CircleCast around the reticle to detect all objects there and checks which one has the lowest Y position, meaning the one that is in the front. Like this:
public LayerMask enemysAndWallsLayers;
bool HasEnemyInFront(Vector2 reticlePosition, float reticleRadius)
{
RaycastHit2D[] enemysAndWallsHitted; // holds the results of the circle cast
ContactFilter2D collisionFilter = new ContactFilter2D(); // filter user by the circleCast
collisionFilter.layerMask = enemysAndWallsLayers;
collisionFilter.useLayerMask = true;
Physics2D.CircleCast(reticlePosition, reticleRadius, Vector2.zero, collisionFilter, enemysAndWallsHitted, 0);
GameObject closestGameObject = null;
float closestY = Mathf.Infinity;
foreach(RaycastHit2D objHitted in enemysAndWallsHitted)
{
if(objHitted.transform.position.y < closestY)
{
closestY = objHitted.transform.position.y;
closestGameObject = objHitted.transform?.gameobject;
}
}
return closestGameObject != null && IsGameObjectEnemy(closestGameObject );
}
The IsGameObjectEnemy() fuction have to be implemented by you in a way that you can tell if it is an enemy or a wall
答案2
得分: 0
我已翻译以下内容:
我已经注释了这部分内容,但我认为这可能会解决你的问题,所以我将它提供为答案。
在检查碰撞的函数中,将障碍物检查放在敌人检查之前。例如:
if (collider.gameObject.tag == "Barrier") {//销毁对象}
else if (collider.gameObject.tag == "Enemy") {//伤害敌人}
这样它会先检查是否撞到了障碍物。如果撞到了障碍物,就不会从敌人那里扣除生命值。
希望这有所帮助。愉快编码!
英文:
I commented this, but I thought as it might solve your problem, I would offer it as an answer.
On the function that checks the collisions, place the barrier check before the enemy check. E.g:
if(collider.gameObejct.tag == "Barrier") {//Destroy object}
else if(collider.gameObject.tag == "Enemy") {//Damage enemy}
This way it will check if it hits the barrier first. If it hits the barrier, no life will be taken from the enemy.
Hope this helps. Happy Coding!
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论