Avoid Pushing between rigidbody - unity3d

I have a issue with my 2D game in unity (pokemon style), I'm using transform.position to move the gameobjects.
I have a player and enemies that follow him, all is ok. But when the enemies make a collision, they begin to push each other
I need that nobody to be pushed when the enemies and player get a collision.
I tried to use kinematic in enemies, but the player can push them.
I tried to add a big amount of mass to the player, but he can push the enemies.
I tried to detect the collision in code with OnCollision, but when I cancel the enemy movement, they don't return to move.
----UPDATE----
I need the collision but without pushing between them, here is a video to illustrate the problem
https://www.youtube.com/watch?v=VkgnV1NOxlw
Just for the record, i'm using A* pathfinding script (http://arongranberg.com/astar/) here my enemies move script.
void FixedUpdate () {
if(path == null)
return;
if(currentWayPoint >= path.vectorPath.Count)
return;
Vector3 wayPoint = path.vectorPath [currentWayPoint];
wayPoint.z = transform.position.z;
transform.position = Vector3.MoveTowards (transform.position, wayPoint, Time.deltaTime * speed);
float distance = Vector3.Distance (transform.position, wayPoint);
if(distance == 0){
currentWayPoint++;
}
}
----UPDATE----
Finally I'll get the expected result,changing the rigidbody2D.isKinematic property to true when the target was close and stop it
Here is a video https://www.youtube.com/watch?v=0Zm0idUU75s
And the enemy movement code
void FixedUpdate () {
if(path == null)
return;
if(currentWayPoint >= path.vectorPath.Count)
return;
float distanceTarget = Vector3.Distance (transform.position, target.position);
if (distanceTarget <= 1.5f) {
rigidbody2D.isKinematic = true;
return;
}else{
rigidbody2D.isKinematic = false;
}
Vector3 wayPoint = path.vectorPath [currentWayPoint];
wayPoint.z = transform.position.z;
transform.position = Vector3.MoveTowards (transform.position, wayPoint, Time.deltaTime * speed);
float distance = Vector3.Distance (transform.position, wayPoint);
if(distance == 0){
currentWayPoint++;
}
}

You can do this in several ways,
You can use Physics2D.IgnoreCollision
Physics2D.IgnoreCollision(someGameObject.collider2D, collider2D);
Make sure that you do the IgnoreCollision call before the collision occurs, maybe when objects instantiate.
or alternatively you can use, Layer Collision Matrix
Unity Manual provides information on using this. This simply does the collision avoidance by assigning different GameObjects to different layers. Try:
Edit->Project Settings->Physics
Or if you want it to just stop moving, You can easily do it like,
bool isCollided = false;
// when when OnCollisionEnter() is called stop moving.
//maybe write your move script like
void Move() {
if(!isCollided) {
// move logic
}
}

Related

Force occasionally being applied twice with OnCollisionEnter

I am creating a first person rocket jumping game, with the premise of shooting a rocket launcher at the players feet to move around.
I am having problems with my OnCollisionEnter function which stores all colliders in a radius and applies explosion force to them. When the player is completely on top of the explosion, force is being applied twice. Here is the code:
private void OnCollisionEnter(Collision collision)
{
if (collision.gameObject.tag == "Player")
{
}
else
{
GetComponent<AudioSource>().Stop();
Instantiate(explosionPrefab, transform.position, transform.rotation);
Vector3 explosionPos = transform.position;
//Use overlapshere to check for nearby colliders
Collider[] collidersToDestroy = Physics.OverlapSphere(explosionPos, radius);
foreach (Collider hit in collidersToDestroy)
{
//searches for what needs to be destroyed before applying force, this is for destructable objects
Destructible dest = hit.GetComponent<Destructible>();
if (dest != null)
{
dest.DestroyWall();
}
ExplosiveBarrel barrel = hit.GetComponent<ExplosiveBarrel>();
if (barrel != null)
{
barrel.BarrelExplode();
}
}
Collider[] collidersToMove = Physics.OverlapSphere(explosionPos, radius);
foreach (Collider hit in collidersToMove)
{
Rigidbody rb = hit.GetComponent<Rigidbody>();
//Add force to nearby rigidbodies
if (rb != null)
{
rb.AddExplosionForce(power * 5, explosionPos, radius, 3.0F);
if (hit.gameObject.tag == "Player")
{
//if player is hit
UnityEngine.Debug.Log("Hit");
}
}
Destroy(gameObject);
}
}
}
I can tell the force is being applied twice to the player by using UnityEngine.Debug.Log("Hit"); , which appears twice in the console. Furthermore, I am pretty sure this is happening on the same frame, as putting Destroy(gameObject); within the if (player hit) statement yields the same results.
This only occurs when the player is right next to the explosion, if the player is a small distance away the force is only applied once. I would very much like to solve this problem and have the force only applied once.
All help is greatly appreciated, thank you in advance.
I solved it!
OnCollisionEnter was being called twice because I had two colliders perfectly stacked on one another, so the projectile was hitting the 2 colliders on the same time step.

Unity - Object hiting soon the other object

I made a replica project to the game Knife Hit. And I'm having trouble with the following question, is my knife hitting the target before it hits it, or the target is detecting the hit before the knife even arrives. What causes the knife to fly around the target, where it should be stuck on the target. As shown in the image below. Consequently, the spawn of the knives that stay on the target, which is to hinder the gameplay, happen the same, are born and are flying around the target.
The code i use is this:
void Update()
{
if (shoot)
{
lastPosition = transform.position;
transform.position += Vector3.up * speed * Time.deltaTime;
RaycastHit2D hit = Physics2D.Linecast(lastPosition, transform.position);
if(hit.collider != null)
{
shoot = false;
if (hit.transform.tag == "Knife")
{
Level.Instance.HitWrong();
rigidbody.bodyType = RigidbodyType2D.Dynamic;
rigidbody.AddTorque(10, ForceMode2D.Impulse);
}
else
{
transform.position = new Vector3(transform.position.x, hit.point.y, transform.position.y);
transform.parent = hit.transform;
collider.enabled = true;
Level.Instance.HitSucced(rigidbody);
}
}
}
}
You need to make sure your 2D colliders are properly "cutout" outlined... My guess is that your 2D collider is really big around the knife or target

2DTopdown Shooter : Shotgun Shoot problem How can i using multiple raycast2D as same time

I create raycast2d script on my game for the HandGun and that works well when the near enemy on distance, taking damage to the enemy.
if (getShop.isPistol)
{
directionShoot = transform.up;
RaycastHit2D hit = Physics2D.Raycast(transform.position, directionShoot, shootDist, mask.value);
if (hit.collider != null)
{
Debug.DrawLine(transform.position, hit.point, Color.green);
hit.collider.gameObject.SendMessage("Damaged", damageTaken);
}
else
{
Debug.DrawLine(transform.position, directionShoot, Color.red);
}
GameObject bullet = Instantiate(bulletPrefab[0], firePoint[0].position, firePoint[0].rotation);
Bullet bulletScript = bullet.GetComponent<Bullet>();
bulletScript.velocity = firePoint[0].up * bulletForce * 10;
bulletScript.player = gameObject;
Destroy(bullet, 2f);
}
else if (getShop.isShotgun)
{
the shotgun
}
and for the shotgun, I recently use same as the Handgun instantiating one by one but I don't want to that so my question is can I use multiple raycast2d without raycastAll on the shotgun and how to add a spread bullet on it in topdown.
If your question is "can i make multiple raycasts per frame" the answer is yes, you can.
You would do something like
List<RaycastHit2D> hits = new List<RaycastHit2D>();
for(int i = 0; i < numberOfBulletsInShotgunShot; i++){
// modify your direction by some small amount here
RaycastHit2D hit = Physics2D.Raycast(transform.position, directionShoot, shootDist, mask.value);
if (hit.collider != null){
hits.Add(hit); // add hits to your list
}
}
// loop through deal with your hits here
Altering the direction slightly to spread your bullets out

Unity3D RayCasting in 4 directions only

I am trying to create a maze game where the player can move only when it can see a sweet.
Currently the raycast is searching in every direction (360 degrees) But I only want the raycast to look directly Up,Left,Down,Right (instead of 360 degrees)... This way the player can only move when a sweet is placed in direct line of sight.
public function setTargetSweet(target:GameObject)
{
too = target.transform.position;
targetSweet = target;
var fwd = too - transform.position;
Debug.Log("Setting target sweet: " + target.name);
Debug.DrawRay(transform.position, fwd, Color.red, 5f);
Physics.Raycast (transform.position, fwd, hit);
if ( hit.collider.tag == "MoveToSweet") {
print ("Can See Sweet");
gotoSweet = true;
}
else
{
Debug.Log(hit.collider.name);
Debug.Log(hit.collider.tag);
gotoSweet = false;
}
}
You're doing ray casts in the direction of any sweet every time. You want four calls like Physics.Raycast(transform.position, Vector3.forward, hit) and check the hit between calls.

How does velocity works?

hey guys i've something here to ask about how does really the velocity on unity works ??? i've been working on a project recently, i want to create the bouncing ball games, so whenever the ball hit the collider, it will be bounced depends on the position that have been hit.
i'm using the getComponent().velocity, but somehow the ball doesn't bounce really well, and whenever the ball hit the middle of collider, it should be bounced back without changing the direction .. please help !!! any help would be grateful ... here's my code :
float getBallPos(Vector2 ballPos, Vector2 boxPos, float boxWide ){
return (ballPos.x - boxPos.x)/boxWide ;
} ---> to get the bounce direction
void OnCollisionEnter2D (Collision2D other){
isHit = true;
if (other.gameObject.tag == "up") {
float x = getBallPos (transform.position, other.transform.position, other.collider.bounds.size.x);
Vector2 dir = new Vector2 (x, 1).normalized;
Debug.Log ("normalized : " + dir);
GetComponent<Rigidbody2D> ().velocity = dir * 5f;
}else if (other.gameObject.tag == "down") {
float x = getBallPos (transform.position, other.transform.position, other.collider.bounds.size.x);
Vector2 dir = new Vector2 (x, -1).normalized;
Debug.Log ("normalized : " + dir);
GetComponent<Rigidbody2D> ().velocity = dir * 5f;
}
}
You should create a Physics Material 2D with a high bounciness and low friction and apply it to your collider2D (you should see the values until you feel comfortable with it.
You create them in Assets->Create->Physics2D Material.
What you are trying yo do is simulate physics and it requires a somewhat complex mathematical model.