- Home /
Extremely Buggy rigidbody collisions [URGENT, DEADLINE 3 DAYS AGO!!!!!!! C#] Please answer. I can't figure it out! (As of 1 Answer)
Please please please please please please help me with this!
My rigidbody collisions are seriously acting up, and I can't figure out why. More info, code, pics, and even a video are here: EDIT: I fixed the bouncing. I added the material to both the object AND the wall. But the stepping issue is still happening. Please help! https://drive.google.com/drive/folders/1BQp_4qqa0_P96joKgimMuwB9Pij_j_yd?usp=sharing
I just checked your files and I have noticed the following:
Your script looks fine and I don't see where anything could go wrong with it.
Your player object does not have a physic material on it in the screenshot despite clai$$anonymous$$g it does in the readme. This seems like what would be causing the problem you demonstrated in the video.
Your falling object has discrete collision detection which can sometimes lead to undesired effects and you should try switching it to continuous.
Also I am not sure what the collider is for in the last screenshot you provided and it doesn't seem to relate to your other gameobjects.
I changed it after the screenshots. I will update it when I get the time.
Try changing the collision detection on your player to continuous. Also you should try putting the friction down on your physic material.
you are disabling input with your cooldown. if(cooldown <= 0.0f)
any time the player uses input you are setting the cooldown to maxcooldown, which you have set to 3.5. that means any time the player presses any of your input buttons theres a delay before they can enter any input.
i also noticed that when you had left pressed nothing was happening. could be the input issue, or it could be whatever you are doing with GlobalVars.GetComponent<GLOBAL_VARIABLES>().timesGravChange++;
as thats the only input that contains that line.
nope. neither of those have anything to do with it. the cooldown is working fine. the timesGravChange is for an achievement in a different script. so you are not correct.
in your video i see nothing wrong with your rigidbody collisions. i see jerky and unresponsive movement. if the point of the game is "gravity moves", ie you only have so many chances to change gravity, then having a cooldown is ok. if youre trying to make the player object fall in the direction of gravity as the controller, the delay interferes. the problem lies elsewhere if it is "set move based". I also see you using a physics material with friction. the object will slow down with friction. your background wall must have a physics material on it, take it off and make the background wall have zero interference
https://docs.unity3d.com/$$anonymous$$anual/class-Physic$$anonymous$$aterial.html
Dynamic Friction The friction used when already moving. Usually a value from 0 to 1. A value of zero feels like ice, a value of 1 will make it come to rest very quickly unless a lot of force or gravity pushes the object. Static Friction The friction used when an object is laying still on a surface. Usually a value from 0 to 1. A value of zero feels like ice, a value of 1 will make it very hard to get the object moving.
with 0.6 as dynamic and 0.6 as static youre saying, it is semi difficult to get this object to move when it is sitting still, but semi easy to get it to slow down. So its slowing down to a stop...stopping....then falling again in the direction youve set gravity to.
by removing the physics material off the background wall...even taking off the collider itself... it is still safe. youve frozen the players rigidbody in the Z direction, so he will not "fall through"
If your rigidbody stops moving for a bit it will go into a 'sleep' state, this is to save a lot of computation power but as changing the gravity does not cause rigidbodies to wake up, you may see some strange behaviour, see this Q/A https://answers.unity.com/questions/543796/gravity-value-changes-has-no-effect.html
There are methods Rigidbody.WakeUp
and Rigidbody2D.WakeUp
that you can call when you change your gravity.
Answer by Tobychappell · Jun 02, 2018 at 01:58 PM
Are you sure physics is definitely the way to go?
As good as physics is.. a custom movement behaviour/system may be better, it may be bit more work but you'd get exactly what you want.
I suggest this because your requirements seem simple and everything is to move perfectly aligned to a grid, IMO, I don't think a physics engine will give good results or at least it's very hard for those without deep understanding to get a physics engine to simulate a non-real environment to such restrictions as it will want to behave organically(?)
Off the top of my head I'd ... id suggest a master/manager class that has a 2d array of Tiles(This could be an enum or an object). This 2d array (aka map) describes the environment, so you'd have terrain definitions and moveable objects on the same map.
Let's say everything is set on the grid and gravity is currently downwards. In the downwards mode the manager would have to scan each column from the bottom going up (if gravity was upwards then it would scan from top to bottom). Whilst it scans it first tries to detect a moveable object. If it finds one it then searches in the line of gravity (downwards) to find the last available empty space. Once it has that it then swaps those tiles and tells that object in the scene to move to that position. The manager will then carry on from where it last detected a moveable object and process anymore moveable objects.
This would only need to be done when the gravity direction is changed. This won't support a diagonal direction of gravity mind.
With this you can then have an animation curve to show a cartoon bounce that will look cool and simulate the physics bounciness with complete control and stuff.
Example video of gameplay: https://youtu.be/xgY1A49NwhU
GridSampler.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Tilemaps;
public class GridSampler : MonoBehaviour
{
public BoundsInt myBounds;
public Tilemap myTileMap;
public bool[,] Map { get; private set; }
public void LoadMap()
{
myTileMap = GetComponent<Tilemap>();
if (myTileMap != null)
{
Map = new bool[myBounds.size.x, myBounds.size.y];
int xIndex = 0;
int yIndex = 0;
for (int x = myBounds.xMin; x < myBounds.xMax; x++)
{
yIndex = 0;
for (int y = myBounds.yMin; y < myBounds.yMax; y++)
{
var tile = myTileMap.GetTile(new Vector3Int(x, y, 0));
if (tile != null)
{
Map[xIndex, yIndex] = true;
}
yIndex++;
}
xIndex++;
}
}
}
}
GridManager.cs and other stuff
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public enum TileType
{
Empty,
World,
Moveable
}
public class TileObject
{
public TileType tileType = TileType.Empty;
public FallableObject obj;
public TileObject(bool isWorld)
{
if (isWorld)
{
tileType = TileType.World;
}
else
{
tileType = TileType.Empty;
}
}
internal void MoveTowards(Vector3 vector3)
{
if (tileType != TileType.Moveable)
{
Debug.LogError("None moveable tile type was told to move!!!");
}
if (obj != null)
{
obj.MoveTo(vector3);
}
}
}
public class GridManager : MonoBehaviour
{
public static GridManager grid { get; private set; }
public GridSampler gridSampler;
private TileObject[,] objectMap;
private void Awake()
{
grid = this;
if (gridSampler != null)
{
gridSampler.LoadMap();
objectMap = new TileObject[gridSampler.Map.GetLength(0), gridSampler.Map.GetLength(1)];
for (int x = 0; x < objectMap.GetLength(0); x++)
{
for (int y = 0; y < objectMap.GetLength(1); y++)
{
objectMap[x, y] = new TileObject(gridSampler.Map[x, y]);
}
}
}
}
public Vector3? WorldObjectSpawned(FallableObject newObj, Vector3 initialPosition)
{
Vector3Int intPos = new Vector3Int(
Mathf.FloorToInt(initialPosition.x),
Mathf.FloorToInt(initialPosition.y),
0);
if (gridSampler.myBounds.Contains(intPos))
{
// need to convert world int space to local absolute space for array
Vector3Int mapPos = intPos + gridSampler.myBounds.position + gridSampler.myBounds.size;
Debug.Log(intPos);
Debug.Log(mapPos);
if (objectMap[mapPos.x, mapPos.y].tileType == TileType.Empty)
{
objectMap[mapPos.x, mapPos.y].tileType = TileType.Moveable;
objectMap[mapPos.x, mapPos.y].obj = newObj;
// Vector3 anchorOffset = gridSampler.myTileMap.tileAnchor;
return intPos + gridSampler.myTileMap.tileAnchor;
}
}
return null;
}
public Vector3 LocalToWorld(int x, int y)
{
Vector3 temp = Vector3.zero;
temp += gridSampler.myBounds.position;
temp += new Vector3(x, y);
temp += gridSampler.myTileMap.tileAnchor;
return temp;
}
// Update is called once per frame
void Update ()
{
Vector2Int? direction = null;
if (Input.GetKeyDown(KeyCode.LeftArrow))
{
direction = Vector2Int.left;
}
if (Input.GetKeyDown(KeyCode.RightArrow))
{
direction = Vector2Int.right;
}
if (Input.GetKeyDown(KeyCode.UpArrow))
{
direction = Vector2Int.up;
}
if (Input.GetKeyDown(KeyCode.DownArrow))
{
direction = Vector2Int.down;
}
if (direction.HasValue)
{
ApplyGravity(direction.Value);
}
}
private void ApplyGravity(Vector2Int dir)
{
if (dir.y != 0) // Up or Down
{
ProcessColumns(dir.y > 0);
}
else
{
ProcessRows(dir.x > 0);
}
}
private void ProcessColumns(bool up)
{
int start = up ? objectMap.GetLength(1) - 1 : 0;
int target = up ? 0 : objectMap.GetLength(1) - 1;
for (int x = 0; x < objectMap.GetLength(0); x++)
{
for (int y = start; up ? (y > target) : (y < target); y = (int)Mathf.MoveTowards(y, target, 1))
{
TileObject selectedObj = objectMap[x, y];
if (selectedObj.tileType == TileType.Moveable)
{
bool spotFound = false;
bool waitingForEnd = true;
int _target = !up ? -1 : objectMap.GetLength(1);
for (
int _y = (int)Mathf.MoveTowards(y, _target, 1);
up ? (_y < _target) : (_y > _target);
_y = (int)Mathf.MoveTowards(_y, _target, 1)
)
{
TileObject scanningObj = objectMap[x, _y];
if (scanningObj.tileType == TileType.Empty)
{
if (!spotFound)
{
spotFound = true;
}
}
if (spotFound && (scanningObj.tileType == TileType.World || scanningObj.tileType == TileType.Moveable))
{
waitingForEnd = false;
}
if (!waitingForEnd)
{
_y = (int)Mathf.MoveTowards(_y, _target, -1);
selectedObj.MoveTowards(LocalToWorld(x, _y));
objectMap[x, _y] = selectedObj;
objectMap[x, y] = new TileObject(false);
break;
}
if (!spotFound)
{
break;
}
}
}
}
}
}
private void ProcessRows(bool right)
{
int start = right ? objectMap.GetLength(0) - 1 : 0;
int target = right ? 0 : objectMap.GetLength(0) - 1;
for (int x = start; right ? (x > target) : (x < target); x = (int)Mathf.MoveTowards(x, target, 1))
{
for (int y = 0; y < objectMap.GetLength(1); y++)
{
TileObject selectedObj = objectMap[x, y];
if (selectedObj.tileType == TileType.Moveable)
{
bool spotFound = false;
bool waitingForEnd = true;
int _target = !right ? -1 : objectMap.GetLength(0);
for (
int _x = (int)Mathf.MoveTowards(x, _target, 1);
right ? (_x < _target) : (_x > _target);
_x = (int)Mathf.MoveTowards(_x, _target, 1)
)
{
TileObject scanningObj = objectMap[_x, y];
if (scanningObj.tileType == TileType.Empty)
{
if (!spotFound)
{
spotFound = true;
}
}
if (spotFound && (scanningObj.tileType == TileType.World || scanningObj.tileType == TileType.Moveable))
{
waitingForEnd = false;
}
if (!waitingForEnd)
{
_x = (int)Mathf.MoveTowards(_x, _target, -1);
selectedObj.MoveTowards(LocalToWorld(_x, y));
objectMap[_x, y] = selectedObj;
objectMap[x, y] = new TileObject(false);
break;
}
if (!spotFound)
{
break;
}
}
}
}
}
}
private void OnDrawGizmosSelected()
{
if (objectMap != null)
{
for (int x = 0; x < objectMap.GetLength(0); x++)
{
for (int y = 0; y < objectMap.GetLength(1); y++)
{
var tile = objectMap[x, y];
if (tile.tileType == TileType.Moveable)
{
Gizmos.DrawWireSphere(LocalToWorld(x,y), 0.4f);
}
else if(tile.tileType == TileType.World)
{
var oldColor = Gizmos.color;
Gizmos.color = Color.red;
Gizmos.DrawWireSphere(LocalToWorld(x, y), 0.4f);
Gizmos.color = oldColor;
}
if (tile.obj != null)
{
var oldColor = Gizmos.color;
Gizmos.color = Color.magenta;
Gizmos.DrawWireSphere(LocalToWorld(x, y), 0.4f);
Gizmos.color = oldColor;
}
}
}
}
}
}
FallableObject.cs
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class FallableObject : MonoBehaviour
{
Transform tran;
public float acceleration;
private float currentVelocity;
Vector3? target;
private void Awake()
{
tran = transform;
}
private void Start()
{
Vector3? newPosition = GridManager.grid.WorldObjectSpawned(this, transform.position);
if (newPosition.HasValue)
{
transform.position = newPosition.Value;
}
else
{
gameObject.SetActive(false);
}
}
internal void MoveTo(Vector3 vector3)
{
target = vector3;
currentVelocity = 0;
}
private void Update()
{
if (target.HasValue)
{
currentVelocity += acceleration * Time.smoothDeltaTime;
tran.position = Vector3.MoveTowards(tran.position, target.Value, currentVelocity * Time.smoothDeltaTime);
if (tran.position == target.Value)
{
target = null;
}
}
}
}
Demo project Link: https://we.tl/pbN04iJpoE
This tickles my curiosity so I'll see if I can get some code that does what I tried to explain.
$$anonymous$$kay.... But artificial gravity didn't work out that well before. Just to let you know.
You might want to point others to the first Question you opened so they can see everything you tried before. The artificial gravity you used before was using force to simulate gravity on rigid bodies ins$$anonymous$$d of using the world gravity. Toby is suggesting movement logic rather than physics which is how you'd do it without a physics engine.
You are still using a 3D box collider and a 3d rigid body on your player, unless you didn't update that picture, you should change both of these to the 2D versions of the components. Have you tried tweaking the drag and mass of the rigid body?
Okay, so this is REALLY GREAT, and THAN$$anonymous$$ YOU for program$$anonymous$$g it! The problem is, I have 30 levels and I don't want to program them all again when I should have had this done two days ago. But thanks a lot!!!!!!!!!!
Thats cool, i can imagine it would take a lot to change, just wanted to give a solid example than just probe at 1 or 2 lines of your code.
Ok. I might use this in a future game though.
Answer by FallingRocketGames · Jun 05, 2018 at 04:43 AM
You're using Vector3 and 3D physics and you have a 2D game you need to consider using Vector2 and 2D physics to fix the issue or check the coordinates but I believe the best way to go is Vector2 and materials to change the behaviour of your character
Your answer
Follow this Question
Related Questions
Absolutely insane rigidbody collisions [URGENT] (C#) 1 Answer
RigidBody collision is so bad SOMETHING is wrong! What did i do? 1 Answer
The Collision and Rigidbody are not working on a model which I've made using pro-builder! 0 Answers
How to make object correctly disperse into physical children on impact. 0 Answers
Player Collision with objects (help) 3 Answers