Welcome, Guest. Please login or register.
Did you miss your activation email?

Login with username, password and session length

 
Advanced search

876915 Posts in 32839 Topics- by 24277 Members - Latest Member: aetherX

May 18, 2013, 03:42:14 AM
TIGSource ForumsDeveloperTechnical (Moderators: Glaiel-Gamer, ThemsAllTook)Collision in unity ...
Pages: [1]
Print
Author Topic: Collision in unity ...  (Read 2863 times)
Gimym TILBERT
Level 10
*****


ILLOGICAL, random guy on internet, do not trust


View Profile Email
« on: March 25, 2011, 09:34:44 AM »



Hello, I need some help from Unity power user...

I'm making a game in unity and need to register all collision contact with the collider. I'm porting a code originally from Blitz3D.

The problem is that the only code that register collision contact is OnCollisionStay(Collision collision) and only work with Rigidbody.

The twist is that I need to freely move the collider for exotic physic sytem. Kinematic rigidbody does not compute collision and Rigidbody are mess up by internal physics engine. Character controller does not compute more than one contact per collider too (I need multiple contacts).

I need to emulate the sphere to polygon collision from Blitz3D for full effect. Blitz3D also returned the closest triangle from the colliding mesh which allow further computation.

Right now I find unity pretty limiting in term of collision. Collision is the basis of interactivity, if you can't this right you are stuck to a finite number of games.
Logged

PlayMeTape
Guest
« Reply #1 on: March 25, 2011, 10:09:27 AM »

Don't have much time but the cheapest solution would probably be to still rely on the builtin physics but only use rigidbody.MovePosition(Vector3 v); which should make sure the object doesn't move through geometry.

Good luck and I'll check back tomorrow!
Logged
Chris Pavia
Level 10
*****


teknobabel42 aquamanscg
View Profile WWW Email
« Reply #2 on: March 25, 2011, 10:44:42 AM »


Kinematic rigidbody does not compute collision

If I am understanding you correctly, I don't think this is correct. I use kinematic and non-kinematic rigidbodies all the time and don't have an issue with collisions. I don't consider myself a 'power user' though, so you may be dealing with something more complex than what I'm referring to.
Logged

Gimym TILBERT
Level 10
*****


ILLOGICAL, random guy on internet, do not trust


View Profile Email
« Reply #3 on: March 26, 2011, 05:02:42 AM »

Thanks for the response.

@Christoffer
I Thought MovePosition only work for CharacterController which only return one contact per collider. But I need to test it with rigidbody, I used transform.Translate. Thanks.
I have tried the builtin physics and it's a mess, nothing work like I want because it always come in the way of movement, I can't be precise.

@Chris Pavia
When I used a kinectic rigidbody, it goes through wall, even with small increment and never fire OnCollision event, I don't know if I mess something, removing the isKinematic flag allow proper collision event. The manual reference also say so. Maybe you use it differently to make it work? How do you use them?
Logged

Toeofdoom
Level 2
**



View Profile WWW
« Reply #4 on: March 26, 2011, 05:16:19 AM »

Based on the chart at the bottom of this page you can use triggers but you won't get any information apart from what you collided with. The other simple option is to use a rigidbody which as you know will be simulated internally.

If you like, you could manually try using Rigidbody.SweepTest (or the related SweepTestAll) or one of the various Cast functions under the physics class (Spherecast, Raycast etc.)
Logged

Gimym TILBERT
Level 10
*****


ILLOGICAL, random guy on internet, do not trust


View Profile Email
« Reply #5 on: March 26, 2011, 05:59:34 AM »

Yeah thanks Smiley
I'm coding with that open all the time, it's really the contact point that bother me on non convex collider (ie the world).

I wanted to avoid having to perform a whole collision system for that, which pretty much defeat the purpose of using Unity TT_TT

EDIT:
Confirmation move does not work with rigidbody and only with character controller.

You can't move things freely and have all contact point
« Last Edit: March 26, 2011, 07:56:17 AM by GILBERT Timmy » Logged

bateleur
Level 10
*****



View Profile
« Reply #6 on: March 26, 2011, 09:47:22 AM »

Confirmation move does not work with rigidbody and only with character controller.

No, that's not right.

When you mess with transform.position directly as you are doing, you bypass the physics system. Christoffer's recommendation that you use Rigidbosy.MovePosition() is correct. It may not solve all your problems, but it will at least deal with the specific issue of collisions not triggering.
Logged

Gimym TILBERT
Level 10
*****


ILLOGICAL, random guy on internet, do not trust


View Profile Email
« Reply #7 on: March 26, 2011, 03:55:40 PM »

Wait! Huh? I tried it and it send me an error ...try again and more carefully ...
Logged

Gimym TILBERT
Level 10
*****


ILLOGICAL, random guy on internet, do not trust


View Profile Email
« Reply #8 on: March 27, 2011, 07:17:07 AM »

It does not work as expected, it's all jerky with a rigidbody (kinematic just go through floor):
and my bool GroundTest return a float  Facepalm


Collisions code:
Code:
void OnCollisionStay(Collision col)

{

print("-------------------------------------------oncollisionstay");

this.collision=col;

this.TestCollisions ();

}















void TestCollisions ()

{//print("start test collision");

float CeilingTest = -MOTION_CEILING;

float GroundTest = MOTION_GROUND;

float FrontTest = MOTION_WALL_DIRECTION;



float FrontFactor = 0;

bool Align = false;

bool ShouldAlign = false;

bool Result = false;



//create normal vectors for temporaly storing the alignment

Vector3 CollisionNormal;

CollisionNormal = Vector3.zero;

Vector3 GroundNormal;

GroundNormal = Vector3.zero;

Vector3 CeilingNormal;

CeilingNormal = Vector3.zero;

Vector3 SpeedNormal;

SpeedNormal = Vector3.zero;

float DotProduct ;







//Iterate through each collision and

//register all the collision data

//that may occured within the player sphere

print("start interation testcollision");

foreach (ContactPoint contact in this.collision.contacts)

{

print("inside iteration testcollsion");

//Clear current collision normal

CollisionNormal = Vector3.zero;

ShouldAlign = true;

CollisionNormal = contact.normal;

DotProduct = Vector3.Dot (CollisionNormal, this.Motion_Align);



//test for ground collision

if (DotProduct > GroundTest && (this.Motion_Speed.y <= 0.0 || this.Motion_Ground))

{

if (ShouldAlign)

{

Align = true;

GroundNormal = GroundNormal + CollisionNormal;

}

GroundTest = DotProduct;

}



//test for ceiling collision

if (DotProduct < CeilingTest && this.Motion_Speed.y > 0.0)

{

CeilingNormal = CeilingNormal + CollisionNormal;

CeilingTest = DotProduct;

}



//test for front collision

if (DotProduct >= MOTION_WALL_UP && DotProduct <= MOTION_WALL_DOWN)

{

//even though the dot product told us there was a collision

//it may have been everywhere around the player

//check out the orientation of the collision

//with a cross product



CollisionNormal = Vector3.Cross (CollisionNormal, this.Motion_Align);

DotProduct = 1 - Mathf.Abs (Vector3.Dot (CollisionNormal, SpeedNormal));

//finally test for front collision

if (DotProduct > FrontTest)

{

FrontTest = DotProduct;

}

}

print (GroundNormal);

print("beat");

}

print ("end iteration test collision");



//if there is a collsion on the front

//calculate how much the speed should drop

if (FrontTest > MOTION_WALL_DIRECTION)

{

FrontFactor = 1f - Mathf.Min (((FrontTest - MOTION_WALL_DIRECTION) / (1f - MOTION_WALL_DIRECTION)) * Time.deltaTime * 1.2f, 1.0f);

this.Motion_Speed.x = this.Motion_Speed.x * FrontFactor;

this.Motion_Speed.z = this.Motion_Speed.z * FrontFactor;

}





//once we know there's a ground collision for sure

//change alignment

if (GroundTest > MOTION_GROUND)

{

if (Align == true)

{

GroundNormal.Normalize ();

this.Motion_Align = GroundNormal;

}

else

{

this.Motion_Align = this.LocalGravity_Alignment;

}

Result = true;

//if no ground collision was found

//maybe there's ceiling collision

}

else if (CeilingTest < MOTION_CEILING_STOP)

{

//if the ceiling slope is low enough

//Make sonic land on the ceiling

if (CeilingTest < MOTION_CEILING_STOP)

{

this.Motion_Speed.y = 0;

Result = false;

//if not, adjust to new aligmenent

}

else

{

CeilingNormal.Normalize ();

this.Motion_Align = CeilingNormal;

Result = true;

}

}

else

{

this.Motion_Align = this.LocalGravity_Alignment;

Result = false;

}



this.GroundTest = Result;print("end testcollision");print(GroundTest);

}





Motions code:
Code:
void Motion ()

{

//test out collisions with scenery since last update.

//While doing this, calculate if character's on the ground

//if so set the alignement

// >> this is handle by OnCollisionStay



print("start motion");



//Once we know if the character's on the ground,

//check for the ground flag and change motion speed in consequence.

switch (this.GroundTest)

{

case true:

this.Align ();

print("align motion");

if (!this.Motion_Ground)

{

//if character just landed

//transpose air speed to ground

this.ConvertAirToGround ();

this.Motion_Ground = true;

//change alignment

this.Animation_Align.x = this.Motion_Align.x;

this.Animation_Align.y = this.Motion_Align.y;

this.Animation_Align.z = this.Motion_Align.z;

}

break;



case false:

//if character just jumped

//transpose ground speed to air

if (this.Motion_Ground)

{

this.ConvertGroundToAir ();

this.Motion_Ground = false;

}

this.Align ();

break;

}



//smoothly change animation alignment to the one of the player

Vector3.Lerp (this.Animation_Align, this.Motion_Align, (0.01f + Motion_Speed.magnitude * 0.07f) * Time.deltaTime);

Animation_Align.Normalize ();



//change direction of the mesh

this.Objects_Mesh.transform.position=this.transform.position;

Vector3 eulerMesh=new Vector3(0,this.Animation_Direction,0);

this.Objects_Mesh.transform.eulerAngles=eulerMesh;

AlignToVector(this.Objects_Mesh,this.Animation_Align,"Y",1);



//Now, just move over the character to the new position

//based on it's speed

Vector3 MoveController;

if (this.Motion_Ground)

{

//adapt to character controller//this.rigid.transform.Translate (this.Motion_Speed.x * Time.deltaTime, this.Motion_Speed.y * Time.deltaTime - (0.015f + (this.Motion_Speed.magnitude * 0.33f * Time.deltaTime)), this.Motion_Speed.z * Time.deltaTime);

MoveController=new Vector3 (this.Motion_Speed.x * Time.deltaTime, this.Motion_Speed.y * Time.deltaTime - (0.015f + (this.Motion_Speed.magnitude * 0.33f * Time.deltaTime)), this.Motion_Speed.z * Time.deltaTime);

MoveController= transform.TransformDirection(MoveController);



Displace=MoveController+Displace;

this.body.MovePosition(Displace);



Debug.DrawLine(transform.position,transform.position+(transform.TransformDirection(MoveController*100)),Color.blue);

}

else

{

//adapt to character controller//this.rigid.transform.Translate (this.Motion_Speed.x * Time.deltaTime, this.Motion_Speed.y * Time.deltaTime, this.Motion_Speed.z * Time.deltaTime);

MoveController=new Vector3 (this.Motion_Speed.x * Time.deltaTime, this.Motion_Speed.y * Time.deltaTime, this.Motion_Speed.z * Time.deltaTime);

MoveController= transform.TransformDirection(MoveController);



Displace=MoveController+Displace;

this.body.MovePosition(Displace);



Debug.DrawLine(transform.position,transform.position+(transform.TransformDirection(MoveController*100)),Color.red);





}print("end motion");



}

What's the hell is wrong  Huh?
groundtest: 0.9411346
UnityEngine.MonoBehaviour:print(Object)
tPlayer:TestCollisions() (at Assets/script/tPlayer.cs:534)
tPlayer:OnCollisionStay(Collision) (at Assets/script/tPlayer.cs:370)

result: False
UnityEngine.MonoBehaviour:print(Object)
tPlayer:TestCollisions() (at Assets/script/tPlayer.cs:535)
tPlayer:OnCollisionStay(Collision) (at Assets/script/tPlayer.cs:370)


Huh?
Logged

Gimym TILBERT
Level 10
*****


ILLOGICAL, random guy on internet, do not trust


View Profile Email
« Reply #9 on: March 27, 2011, 09:03:46 AM »

fixed the bool problem
Logged

Gimym TILBERT
Level 10
*****


ILLOGICAL, random guy on internet, do not trust


View Profile Email
« Reply #10 on: March 27, 2011, 09:44:50 AM »

http://dl.dropbox.com/u/24530447/input_Script.cs
http://dl.dropbox.com/u/24530447/tPlayer.cs

Full code free of use

set up:
- You need a ground mesh with a collider
- create an empty gameobject above the ground (higher than 2.4 unit in distance
- attach the tplayer script
- Attach a camera is in the Objects_cam field
- Attach a random mesh in the Objects_mesh field (create a cube for exemple)

The goal is to position precisely the mesh wherever I want and still get collision DATA right. So I could have exotic physics later one.


I guess that's the same type of problem who killed the 3D version of "Marian"


edit:
http://www.youtube.com/watch?v=SKvPO_Og2IQ
result should be similair to that, it's port I do as an exercise (because it have the right collision requirement, if I can't do this simple game, I will have to dwarf seriously my action games ideas)
« Last Edit: March 27, 2011, 10:16:05 AM by GILBERT Timmy » Logged

Gimym TILBERT
Level 10
*****


ILLOGICAL, random guy on internet, do not trust


View Profile Email
« Reply #11 on: March 27, 2011, 11:47:29 AM »

SMALL WIN:

Get rid of the collider in the random mesh (i use a create cube)
encapsulate the "for each contact" loop with a if (collision !=null)

Still get strange behavior "move through wall" and "walk upside down" the other surface
Logged

Gimym TILBERT
Level 10
*****


ILLOGICAL, random guy on internet, do not trust


View Profile Email
« Reply #12 on: May 09, 2011, 08:03:52 AM »

EPIC WIN:

The problem is solved, I share it so anybody can have the same level of flexibility.


Why using this instead of character controller?

It gives you more data about your collision and how you want to process them. Rigidbodies return a structure that return all collision around the collider, it allow you to process angle of collision for example from multiple collision. If you want you character to be aware of the world around him (putting his hand on wall while still moving along them) it's the faster way. Collision is more solid too and feel better. Other solution may involve listening to get and listen to every collider you where in collision with, and ven with that you may not be able to listen more than one collision with one collider. For world like mesh, it's the better way.


How does it work?

Currently My code is organize like this:

UPDATE loop
-state selection (process input and state transition)
-update output

FIXEDUPDATE
-reset the collision position based on last collision
-Call collision and process motion code based on state
-perform motion into space

OnCOLLISIONstay listener
-create collision structure to pass to collision processing

Details:

I have (oups click post instead of preview ... wait)

Code:
//Collision
Collision collision;
Rigidbody body;
Vector3 Displace;

First I have I declare some variable to use and pass collision information. You need a type collision to hold the structure of collision data. Rigidbody is the physic controller that will return the collision data. Displace is the virtual position of your motion processing. I also use a sphereCollider but any collider is fine.


Code:
void OnCollisionStay(Collision col)
{
this.collision=col;
}

In OnCOLLISIONstay you put a code to gather collision data and pass it to your custom collision handling with the member collision you created. You need this as you can't access easily collision data from anywhere else.

Code:
[Type] TestCollisions()
{
//variable to process data
...
//check if the structure exist
//It won't be create until there is a collision
if (collision != null)
{
foreach (ContactPoint contact in this.collision.contacts)
{
//access elements of contact structure
//process here each data (local collision) and passed it with some variable
}
}
//here process the result from the loop you passed (overall collision)

return result

}

Collision data is then process in a testCollision method. Result is then passed to outside world through direct manipulation of member data and return. In my case I return a OnGround bool and manipulate some motion and alignment data. Why this code is not in OncollisionStay? Because I want it to run even when there is no collision.


ON fixed Update

Code:
//reset position to last collision position
this.Displace=this.transform.position;

I have a code that reset the virtual position to the current real position. When I move the object to the next position, I don't know if there is a collision. But I use a particular unity command who truncate any movement, as soon it detect a collision, to the collision point. In order to keep the custom space and the real space in check I need that.


Code:
void Motion ()// collision handle and aplication of movement in space
{
//test out collisions with scenery since last update.
//if so set the alignement
this.collisionTest = this.TestCollisions();

//Now, just move
//to the new position
//based on it's speed
Vector3 MoveController;

if (this.collisionTest)//for different flag data
{
this.Align();
//some other code
...

//adapt to controller May alter
MoveController=new Vector3 (this.Motion_Speed * Time.deltaTime * [some other data]);

MoveEntity(body,MoveController);
}
}

Then I move the rigidbody into real space by converting the virtual space based on some flags.


Code:
void MoveEntity (Rigidbody body, Vector3 MoveController)//move the custom space in to unity space
{
MoveController= this.body.transform.TransformDirection(MoveController);
this.Displace=MoveController + this.Displace;
this.body.MovePosition(this.Displace);
}

MoveEntity is a custom method that handle the conversion from one space to another. It add the virtual motion (moveController) to real space (displace) with TransformDirection and let unity truncate the real movement with MovePosition (which is update with the reset code). Generally Virtual space are made respective to some object space and handle through align to current object space.


Code:
//take input data and turn it into speed, friction and direction control along motion vector
void Handle()
{}

Then I process Motion code in my custom space. and the loop start again.


Why it's better

It allow you to have physics along cylinder or spline (or any warp space you can imagine) and still interact with original unity physics.

You can have very precise physics that are tied to the bound you want and non physical or natural movement.

It's stronger than Character controller and allow more precise control and interaction with scenery.

With iskinetic flag you no longer detect collision but other collider still react to the collider, cool for going through floor and still influence the scenery along your path.

It allow you to switch to unity physics on the fly.

No noise from unwanted physic influence. You can discard any data that does not fit the desired behavior.
« Last Edit: May 09, 2011, 09:37:02 AM by Gimmy TILBERT » Logged

Pages: [1]
Print
Jump to:  

Theme orange-lt created by panic