Why is my character passing through the object even though I have configured box colliders and rigidbody for them? - unity3d

Check inspection for: Blocking wall
Check inspection for: character
It still passes through the blocking wall.
In Script in character:
if (Input.GetKey(KeyCode.UpArrow))
{
transform.Translate(Vector3.forward * 15 * Time.deltaTime);
}
if (Input.GetKey(KeyCode.DownArrow))
{
transform.Translate(-Vector3.forward * 15 * Time.deltaTime);
}

You components are correctly set: one rigidbody at the character and colliders in both the character and the wall.
As said by Greg: if you want to move your character in a more realistic way(based in the unity physics) you may want to change your code to use AddForce instead. However, its not mandatory. If you're doing something like a space invaders game, move the character the way you are doing is ok.
Another thing you should consider is the possibility of the wall collider be too thin. If that is the case, unity could not be able to detect the collision properly.

If your object is moving quickly you might want to change Collision Detection: Descrete to a Continuous one in the inspector. Also, you might want to modify the rigidbody velocity for movement instead.
Also. Make sure you're not using 3d objects and 2d objects combined. They don't match. A 2D object wont collide with a 3D object.
RigidBody rb;
void Start() {
rb = GetComponent<RigidBody>();
}
void Update() {
if (Input.GetKey(KeyCode.UpArrow))
{
rb.velocity = Vector3.forward * 15 * Time.deltaTime;
}
if (Input.GetKey(KeyCode.DownArrow))
{
rb.velocity = -Vector3.forward * 15 * Time.deltaTime;
}
}
Disclaimer: Might need to adjust the values a bit!

Use the rigidbody.AddForce function to move your player/object.
Translating the transform is more like teleporting than moving. So your object teleports to the other side of the wall with transform.Translate.
Check this link for the rigidbody.AddForce movement method: Unity - Moving the player
Update 1
You should also set the collision detection to continuous instead of discrete.

First of all. You do need Rigid body component on your wall at all. Collider itself will cause the collision.
For Unity physics to work properly you should not modify transform position directly but move your character by using forces.
Try this:
void FixedUpdate() {
Rigidbody rb = this.GetComponent<Rigidbody>();
if (Input.GetKey(KeyCode.UpArrow))
{
rb.AddForce(Vector3.forward * 15f);
}
if (Input.GetKey(KeyCode.DownArrow))
{
rb.AddForce(-Vector3.forward * 15f);
}
}

Related

Raycast2D hits only one side of Collider

I want to make sure that various objects moving at high speed cannot pass through walls or other objects. My thought process was to check via Raycast if a collision has occurred between two moments of movement.
So the script should remember the previous position and check via Raycast for collisions between previous and current position.
If a collision has occurred, the object should be positioned at the meeting point and moved slightly in the direction of the previous position.
My problem is that works outside the map not inside. If I go from inside to outside, I can go through the walls. From outside to inside not.
Obviously I have misunderstood something regarding the application with raycasts.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ObsticalControll : MonoBehaviour
{
private Vector3 positionBefore;
public LayerMask collisionLayer = 9;
private Vector3 lastHit = new Vector3(0, 0, -20);
// Start is called before the first frame update
void Start()
{
positionBefore = transform.position;
}
private void OnDrawGizmos()
{
Gizmos.DrawCube(lastHit, new Vector3(.2f,.2f,.2f));
}
// Update is called once per frame
void Update()
{
Vector3 curruentMovement = transform.position;
Vector2 dVector = (Vector2)transform.position - (Vector2)positionBefore;
float distance = Vector2.Distance((Vector2)positionBefore, (Vector2)curruentMovement);
RaycastHit2D[] hits = Physics2D.RaycastAll((Vector2)positionBefore, dVector, distance, collisionLayer);
if(hits.Length > 0)
{
Debug.Log(hits.Length);
for (int i = hits.Length -1 ; i >= 0 ; i--)
{
RaycastHit2D hit = hits[i];
if (hit.collider != null)
{
Debug.Log("hit");
lastHit.x = hit.point.x;
lastHit.y = hit.point.y;
Vector3 resetPos = new Vector3(hit.point.x, hit.point.y, transform.position.z) + positionBefore.normalized * 0.1f;
transform.position = new Vector3(resetPos.x, resetPos.y, transform.position.z);
}
}
}
positionBefore = transform.position;
}
}
Theres a better way to deal with this that unity has built in.
Assuming the object thats moving at a high speed has a RigidBody(2d in your case) you can set its Collision Detection to Continuous instead of Discrete.
This will help collisions with high speed collision, assuming that its moving at high speed and the wall is not moving.
If for some reason you cannot apply this to your scenario, Ill try to help with the raycast solution.
However, I am still wondering about the collision behavior of my raycast script. That would be surely interesting, if you want to calculate shots or similar via raycast
Alright, so your initial idea was to check if a collision had occurred, By checking its current position and its previous position. And checking if anything is between them, that means a collision has occurred. And you would teleport it back to where it was suppose to have hit.
A better way todo this would be to check where the GameObject would be in the next frame, by raycasting ahead of it, by the distance that it will travel. If it does hit something that means that within the next frame, it would have collided with it. So you could stop it at the collision hit point, and get what it has hit. (This means you wouldn't have to teleport it back, So there wouldn't be a frame where it goes through then goes back)
Almost the same idea but slightly less complicated.
Problem would be that if another object were to appear between them within the next frame aswell, it could not account for that. Which is where the rigidbody.movePosition shines, And with OnCollisionEnter you can detect when and what it collided with correctly. Aswell as without the need to teleport it back

Camera follow player issue (2d)

I am working on a 2D space game, similar to Roid Rage. I have a space shuttle in it. The shuttle will move around freely and will avoid obstacles. I have made the movement and rotation part of the shuttle successfully (using rigidbody2d). But now I am unable to make the camera follow the shuttle.
First I tried making the camera a child of shuttle. In this way, the camera followed the shuttle. But it didn't show any rotation of shuttle because I guess the camera also rotates with the shuttle in this case.
Then I did this:
public Transform shuttle;
private Vector3 offset;
void Start() {
offset = transform.position;
}
void LateUpdate() {
transform.position = shuttle.transform.position + offset;
}
In this case, the camera followed the shuttle but when I tap the screen and the shuttle is supposed to take a turn (in an orbit like path), it just rotates around its own axis.
Finally, I used this instead:
void LateUpdate() {
transform.position = Vector3.Lerp(transform.position, shuttle.position + offset, 0.125f);
}
Now, the result is that the shuttle is very shaky. Any solution to this problem?
Does something very simple like this not work? This is in the camera script, not attached to the GameObject.
public GameObject MyShuttle;
void LateUpdate() {
this.transform.position = MyShuttle.transform.position;
}
Found a solution after searching on forums. Since I was using Rigidbody2D to move the shuttle, I had to turn on its Interpolate property from None to Interpolate. The shaking was fixed by this.

OnCollisionEnter() not functioning with rigid-body and continuous detection while bouncing..?

So, as the title implies, my OnCollisionEnter is not being called. I'm not sure why. The objects are bouncing off surfaces they contact.
Here's the relevant code:
static Rigidbody m_ProjectileRigidbody;
internal void FireProjectile(GameObject projectile, float speed)
{
projectile.transform.position =
State.PlayerTransform.position + State.PlayerTransform.forward;
projectile.transform.rotation = State.PlayerTransform.rotation;
m_ProjectileRigidbody = projectile.GetComponent<Rigidbody>();
m_ProjectileRigidbody.AddForce
(State.PlayerTransform.forward * speed, ForceMode.Impulse);
if (State.PlayerState.Consumes)
{
State.PlayerState.ConsumeCellEnergy(EnergyConsumption);
State.PlayerState.GenerateCellHeat(HeatProduction);
}
}
void OnCollisionEnter(Collision collision)
{
Debug.Log("Collided With: " + collision.gameObject.name);
}
If you are working with 2D colliders and rigidbodies, use OnCollisionEnter2D instead of OnCollisionEnter.
And make sure in Edit -> Project Settings -> Physics the collision matrix is properly set.
And also, double check that:
Both objects have collider, rigidbody properly set up.
Both objects are active.
You do not accidentally disable collider, rigidbody or set
isKinematic, isTrigger from your script.

Prevent Collision Forces in Unity Physics in Collision Callback

How do I prevent a collision from applying forces in Unity? I am using 2D physics and want an arrow to stick into a crate. I can easily remove the rigid body and collider in the collision callback, but it seems that a frame of collision force is still applied to the arrow, causing slight jumps in position and rotation. Settings isKinematic on the rigid bodies in the collision callback also appears to not prevent this one frame of force being applied.
I am hoping to tell Unity to not apply physics for the collision.
Using kinematic for the life time of the arrow is not an option because the arrow needs to fly realistically until it hits something.
Here is the code for the crate object that handles the collision:
protected virtual void HandleCollision(ArrowScript arrow, Collision2D coll)
{
StickArrow(arrow, coll);
if (DestroyAfterSeconds >= 0.0f)
{
Destroy(arrow.gameObject, DestroyAfterSeconds);
}
}
private void OnCollisionEnter2D(Collision2D coll)
{
ArrowScript script = coll.gameObject.GetComponent<ArrowScript>();
if (script != null)
{
HandleCollision(script, coll);
}
}
private bool StickArrow(ArrowScript arrow, Collision2D coll)
{
Vector2 surfaceNormal = coll.contacts[0].normal;
float surfaceAngle = Mathf.Atan2(surfaceNormal.y, surfaceNormal.x);
float arrowAngle = Mathf.PI + (arrow.transform.eulerAngles.z * Mathf.Deg2Rad);
float angleDifference = Mathf.Abs(BowAndArrowUtilities.DifferenceBetweenAngles(surfaceAngle, arrowAngle));
float penetration = arrow.PercentPenetration * PenetrationPercentageModifier * (1.0f - angleDifference);
if (penetration <= MinimumPenetrationPercentage)
{
arrow.PercentPenetration = 0.0f;
return false;
}
// Make the arrow a child of the thing it's stuck to
arrow.transform.parent = transform;
arrow.gameObject.transform.Translate(new Vector3(-penetration * arrow.Length, 0.0f, 0.0f));
SpriteRenderer thisSpriteRenderer = GetComponent<SpriteRenderer>();
if (thisSpriteRenderer != null)
{
arrow.GetComponent<SpriteRenderer>().sortingLayerID = thisSpriteRenderer.sortingLayerID;
arrow.GetComponent<SpriteRenderer>().sortingOrder = Mathf.Max(0, thisSpriteRenderer.sortingOrder - 1);
}
BowAndArrowUtilities.PlayRandomSound(arrow.CollisionAudioClips, penetration * 5.0f);
// destroy physics objects from the arrow (rigid bodies, colliders, etc.). This unfortunately doesn't prevent this frame from apply force (rotation, position) to the arrow.
arrow.DestroyPhysicsObjects();
return true;
}
Unity version is 5.3.4.
I ended up making the arrow head a trigger. Inside of OnTriggerEnter2D, I then perform a circle cast in the direction the arrow is pointing with a width of the arrow head sprite. Triggers do not get affected by Unity physics calculations.
private void OnTriggerEnter2D(Collider2D coll)
{
ArrowScript script = coll.gameObject.GetComponent<ArrowScript>();
if (script != null)
{
Vector2 dir = -script.ArrowHead.transform.right;
// ray cast with the arrow size y value (thickness of arrow)
RaycastHit2D[] hits = Physics2D.CircleCastAll(script.ArrowHead.transform.position, script.Size.y, dir);
foreach (RaycastHit2D hit in hits)
{
// collider2d is a member variable assigned in Start that is the Collider2D for this object
if (hit.collider == collider2d)
{
HandleCollision(script, hit.normal);
break;
}
}
}
}
Your problem is that OnCollisionEnter and OnTriggerEnter are called after all the collisions are resolved.
The simplest way to solve this without affecting anything would be to change the weight of the box, arrow, or both.
Set the weight of the crate to a high value, and the weight of the arrow to a low value.
Another way is to use trigger colliders, as you have done. However trigger colliders have problematic side-effects. For example, it doesn't call OnCollisionEnter or OnTriggerEnter on the crate. You will have to do all the logic inside the arrow script, which is not much of a problem.
There are a lot of other ugly hacks however. You could set the velocity of the box to 0 after impact, but it would freeze the crate if you hit it as it was moving. You could use the collision information to cancel the force applied to the crate to solve the collision. You could save the last velocity of the crate every frame, and reapply it to the rigid body during the OnCollision call.
I wouldn't suggest any of these, but they are possible.

How to make wall push the player in unity3d?

How to make wall push the player ?
i had tried to use transform.translate, however i found out directly manipulating transform
component of an object ignores physic, and someone suggest me to use force instead.
however, when i use force, the wall
just stop when it hit my player, as if my player can't be moved.
Below are my code.
using UnityEngine;
using System.Collections;
public class left : MonoBehaviour {
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
rigidbody.AddForce (-40 * Time.deltaTime, 0, 0);
if (transform.position.x < -14) {
transform.position = new Vector3(15,15,908);
}
}
}
Increase the mass of the wall or reduce the mass if the player
First of all, you should put a collider on both the box and the player. Then create a script on the player. Something that would tell it that when the box collided with the player, it would move to the destined position, depending on the force applied.
something like
OncollideO(){
player.transform.position.x -= Time.deltaTime * 1;
}
you do not have to set the vectors manually to be able to move them.
you may also use left, right, up, and down in moving gameobjects.
might as well as tell you to research about LERP which may be able to help you in coding it.