I am currently working on a football game(American) and im working on a tackle mechanic. Now just having 2 things bumping into each-other did not work because the character would continue to move after being forced sideways on the ground. To make the character stop after making contact with the other rigid body, I thought the best way would be to use Time.Timescale = 0; . However the problem with this is the fact that the 2 rigid body's then just go through each-other.to solve this I think the best way would be to set time scale to 0 after 1 second of collision. How can I do this?
Feedback is always appreciated ;)
to invoke a method delayed within unity presuming it is a monobehaviour.
the Invoke method apears to be what you are after
http://docs.unity3d.com/ScriptReference/MonoBehaviour.Invoke.html
however please be aware that Time.Timescale effects everything and is not local and would more than likely not get the effect you are after. setting the Velocity of the gameObject to zero should get the desired outcome.
var rb = GetComponent<Rigidbody>();
rb.velocity = Vector3.zero;
Time.Timescale would effect your whole game.
Actually Time.Timsescale is
The scale at which the time is passing. This can be used for slow motion effects.
When timeScale is 1.0 the time is passing as fast as realtime. When timeScale is 0.5 the time is passing 2x slower than realtime.
When timeScale is set to zero the game is basically paused if all your functions are frame rate independent.
From Unity Documentation
Well, what you can do is,
In script attached to Rigidbody's GameObject you can implement OnCollisionEnter.
Rigidbody _rb;
void Start()
{
_rb = GetComponent<Rigidbody>();
}
void OnCollisionEnter(Collision col){
_rb.velocity = Vector3.zero;
}
It will stop your player even after collision with ground. :)
So you can further modify collision condition like if body strikes to some specific object, you can detect it by tag or some other properties.
void OnCollisionEnter(Collision col){
if (col.gameObject.tag == "TAG_OF_SPECIFIC_OBJECT")
_rb.velocity = Vector3.zero;
}
Related
now, ive ben searching for I while, and I cant seem to find a simple answer. what is a simple way to make a jump pad that uses a character controller and not a rigidbody? (written in C#) I want my character to get boosted into the air when he collides with a specific game object. the script my character is using already has gravity so all I need is an upward boost. does anyone know how to do this? I dont have any code I dont know where to start, so please help!
Did you try Dotween functions? or did you try to change transform.position in Update using your skills.first I would try Dotween functions like Dojump or DoMove, Secondly I would try this ; transform.position + = Vector3.up * Time.deltaTime;
So, you have a player, he has movement and you want him to jump when he touchs a jump pad. So you need to have a CollisionScript for the player as well as a Impulse on the jump pad. My simplistic way to this, is...
Before you use this script you need to create a tag called probably jumpPad and then add it to your jump pad in the scene.
Then I would do the Collision Script, that will detect the collision when the player collides with the jump pad. And get the impulse towards y-axis on collision.
Collision Script:
public Rigidbody playerRb;
public float jumpForce = 10f;
private void OnCollisionEnter(Collision collision)
{
if (collision.gameObject.CompareTag("jumpPad"))
{
playerRb.AddForce(Vector3.up * jumpForce, ForceMode.Impulse);
}
}
Then you just need to drag the player Rigidbody for the CollisionScript.
It will look like this
I have a kill zone at the bottom of my level in my 3D platformer, but when my rolling ball get respawned using transform.position I keep my momentum. How do I cancel all momentum after position is overridden?
I've tried looking around already but everyone seems to have asked the question at least 5 years ago, and when I try to change rigidbody.velocity or rigidbody.angularVelocity, it says 'Component.rigidbody' is obsolete.
Thanks in advance!
Have a look at the docs: neither Rigidbody.velocity nore Rigidbody.angularVelocity are "obsolete" ...
From a comment I saw you actually mean the Component.rigidbody which is obsolete -> You have to get it using GetComponent as any other component.
so simply go ahead and use
var rigidbody = GetComponent<Rigidbody>();
// or in case you get it from another object or component
//var rigidbody = otherObjectOrComponent.GetComponent<Rigidbody>();
rigidbody.velocity = Vector3.zero;
rigidbody.angularVelocity = Vector3.zero;
btw you should also set the position not via the Transform component but rather using Rigidbody.position
You can cancel momentum via velocity. It is not obselete:
Rigidbody rb = GetComponent<RigidBody>();
rb.velocity = Vector3.zero;
Setting the velocity to Vector3.zero after the collision will work. If you want to completely reset the ball, I would consider destroying the old ball and instantiating a new ball prefab.
I know the title isnt very explanatory, but here's my problem:
I have a player (merely a cube with a rigidbody, a collider and a movement script), and I have a floor made of small 1 by 1 by 1 cubes (cubes with box colliders).
For some reason unknown to me, when my player cube falls and tries to collide horizontally with the floor, he just phases through... But want him to get blocked by the cubes just like it does vertically. Any help would be greatly appreciated ;)
heres how the scene looks like
heres a cube object
heres the player object
Here's a gif of the player going through the floor
Here's my c# player movement script (I know its very bad, but I prefer to put this here just in case its linked to my problem) :
void ApplyMovement()
{
transform.position += new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical"));
}
If you need any more info to help me just tell me, I'll provide it as fast as I can.
The value of
new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical"))
is framerate-dependent. This means the faster the framerate the faster your object will move. This is usually not what you want. Instead use Time.deltaTime
// Adjust the speed in the inspector
public float speedMultiplicator = 1;
//...
new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical")) * speedMultiplicator * Time.deltaTime
to get a framerate-independent movement. Also see the example in Input.GetAxis.
When dealing with RigidBody never change the transform.position (and rotation) directly!
If you would want to make the RigidBody jump to a certain position rather use
rigidBody.position = transform.position + ...;
However what you want is a smooth movement in order to keep the collision detection intact. So you should use RigidBody.MovePosition instead
rigidBody.MovePosition(transform.position + ...);
You don't have to deal with force etc.
Also add a RigidBody component to the floor objects. Even ifnthe object is not moving this improves the collision detection (at the cost of performance in the Physics engine ofcourse). And since the objects are not supposed to move set
isKinematic -> true
use Gravity -> false
you can also set freeze position and freeze rotation.
On both floor and player objects set Collision Detection -> Continous Dynamic. This improves the collision detection and looks for collisions also between frames.
Be aware, however, that dynamic detection is quite expensive so use it only if there is still trouble with too fast objects.
On the player you might want to also use interpolate as well.
Finally
Note that continuous collision detection is intended as a safety net to catch collisions in cases where objects would otherwise pass through each other, but will not deliver physically accurate collision results, so you might still consider decreasing the fixed Time step value in the TimeManager inspector
to make the simulation more precise, if you run into problems with fast moving objects.
For more information see the RigidBody manual and the Colliders manual
I recreated the scenario you described on my end. I put your "ApplyMovement" code in "Update". I was basically able to reproduce your results.
It seems to me that the issue might be Freezing Position X/Z on the Player. I think since you are doing that, you're telling the Rigidbody component that it is not allowed to modify the X/Z positions of the objects as part of it's collision resolution and physics simulation. When I turn those two off, I get results that are (I think) closer to what you're looking for.
One note: your "ApplyMovement" code is frame-locked, meaning your player will move at different speeds at different frame rates. To solve this, you'd need to multiply your Input.GetAxis values by Time.deltaTime.
Also, if your player moves too fast, it'll still be able to pass through collisions and cause odd behavior, so be sure to limit the max movement rate of the player to some reasonable value.
You should be applying a force to the Rigidbody of the character instead of directly manipulating the transform.position (this is preventing the physics engine from resolving the collisions). You're also freezing the X and Z position on the Rigidbody; you don't want that because it entirely prevents the Rigidbody from manipulating those values.
Instead of transform.postion += ... first get a reference to the Rigidbody somewhere in your script (best done in an Awake() method):
private Rigidbody _body;
private void Awake() {
_body = GetComponent<Rigidbody>();
}
Then make sure the vector built from your inputs is being applied to the object's "movement," not its position:
Vector3 inputVector = new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical"));
// You can multiply this vector by a float to adjust "speed"
_body.ApplyForce(inputVector, ForceMode.VelocityChange);
Finally, you should read up on the different ForceMode options and decide which one fits your preferences: https://docs.unity3d.com/ScriptReference/ForceMode.html
Don't forget this should happen in a FixedUpdate(), not an Update() (all physics operations should be done in FixedUpdate())
As a side note, there is also the possibility your rigidbodies still up moving too quickly and passing through each-other. Even when you're using forces and velocities, this is possible so if your run into this case down the line, investigate Collision Detection Modes. TLDR; they're settings for performance vs accuracy trade-offs.
I am making this 2D platform game for a freelance, and I have to do a sonic mechanic, I have to make the character run through a full loop without falling down, I realised that to do this first I would have to rotate the character conform he runs through the loop, but the second part is where I am stuck.
So, basically, how can I make the character run the loop without falling down.
private void OnCollisionEnter2D(Collision2D coll)
{
Vector3 collRotation = coll.transform.rotation.eulerAngles;
if (coll.gameObject.tag == "Ground")
{
//in this part i rotate the player as he runs through the loop
transform.eulerAngles = new Vector3(transform.eulerAngles.x, transform.eulerAngles.y, collRotation.z);
//this is the part that i am stuck, trying to figure out how to make the character stay in the loop without falling, i tried collision detection,
//i tried raycasting but nothing seems to work
if (IsGrounded)
{
GetComponent<Rigidbody2D>().AddForce(Vector2.down, ForceMode2D.Impulse);
}
}
}
The trick that is most commonly used for remakes and similar is getting the speed of the player character on entry.
// Feel free to adjust this to whatever works for your project.
const float minimumAttachSpeed = 2f;
// This should be your characters current movement speed
float currentSpeed;
// You need a Rigidbody in this example, or you can just disable
// any custom gravity solution you may have created
Rigidbody2D rb;
If the speed of the character is excelling the minimum attachment speed, you can then allow them to follow a predefined path at that speed.
bool LoopAttachmentCheck()
{
return minimumAttachSpeed <= currentSpeed;
}
And now you can check to see if you're moving fast enough! I assume for this example you are using a Rigidbody2D...
(this check should only be run when you're either entering or currently on the loop)
void Update()
{
if( LoopAttachmentCheck() )
{
// We enable this to prevent the character from falling
rb.isKinematic = true;
// Here you write the code that allows the character to move
// in a circle, e.g. via a bezier curve, at the currentSpeed.
}
else
{
rb.isKinematic = false;
}
}
It's up to you to implement the actual rotational behaviour. If I were you, a good way to do this would (assuming it is a perfect circle) use RotateAround from the center of the circle.
If you have more complex shapes, you can use waypoints for movement, and just iterate through them at your speed.
The moment you fail to keep up speed, your character will fall off (so if a player decided to stop running for example) and the Rigibody2D will become kinematic.
Hope this helps!
In my 2D side-scrolling game I move my character using the built-in physics engine by manipulating the rigidbody.velocity.
I would like to add some sort of dodge (roll) ability, where the character moves 3 units in its direction.
Here is the code I used:
void FixedUpdate() {
if (Input.GetKeyDown(KeyCode.A) ) {
Vector2 pos = rb.position;
pos.x -= 5;
rb.MovePosition (pos);
}
}
This method works but the character kind of jumps to the position rather than moving to it (Lerping?) and also doesn't detect collisions despite the body type being dynamic.
Then I tried this:
if (Input.GetKeyDown(KeyCode.A)) {
rb.AddForce(new Vector2(-50, 0));
}
I found the AddForce way isn't accurate at all.
Is there a proper way of doing this?
Maybe you could change the Transform.pos inside Vector2.Lerp to make it look smooth? (Sorry, not enough experience with 2D in unity.)
Just increase rigibody.velocity for a set time. Your chararter object could then play a fitting aniamtion. If The player should not be able to cancle midrole jsut block the controls for that time.