Moving a RigidBody2D a specific amount of units - c#

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.

Related

jump pad that uses characterController instead of rigidbody

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

How to make a 2D real-time Strategy camera controller in unity?

I have been looking around for ages about how to do a Real-time Strategy camera for Unity in 2D. What I mean is that you should be controlling the camera with W, A, S, D and where ever I look its only 3D. I have been trying to write my own scripts but the camera never works and I am in dire need for help. I have tried so much but as a beginner on Unity, I really need help with this. If you can give me anything about how to get started in this matter I will be so happy.
Do you think I should use the Force method or that I should use another one that unity already has installed? I also tried using vectors but when I looked around everyone was using Vector 3 which only is for 3D unity.
You can attach a single script to your camera.
public float speed =10.0f;
void Update()
{
Vector3 a = transform.position
if(Input.GetKeyDown("W"))
{
a.position.y += speed *Time.deltaTime
}
if(Input.GetKeyDown("S"))
{
a.position.y -= speed *Time.deltaTime
}
transform.position =a;
}
You can adjust the speed to your needs. You can do this for other keys. Note GetKeyDown is called when a key is being held down. Hope this helps.
Make a direction vector with Vector3 direction = new Vector3();
Manipulate the vector in the directions you want, based on the key:
if (Input.GetKey(KeyCode.A))
direction += Vector3.left;
Adding the "built-in" Vector3.left will point the direction of the vector to the left, and you can add the other keys on top of that to get a final direction.
Then you can use transform.Translate() to move the gameObject (in this case you attached it to your camera) by passing the direction you calculated based on the keys being pressed as a parameter. Then multiply to get direction * speed * Time.deltaTime;

Unity player collision with horizontal small colliders

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.

Unity - Run a loop like sonic without falling down

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!

How do I freeze rotation of a Rigidbody programatically?

I am creating a 2D platformer game, and I already wrote the script that moves the sprite forwards and backwards successfully. However, I am extremely new to Unity and C#, so I have no idea how to freeze rotation of the sprite.
I tried to do it programatically (because the use gravity option did not appear in inspector) like so-
void Update () {
anim.SetBool("Grounded", grounded);
anim.SetFloat("Speed", Mathf.Abs(Input.GetAxis("Horizontal")));
rb2d.freezeRotation.freezeRotation = true;
}
but it obviously doesn't work. How do I correctly freeze rotation of the sprite with c#? Where do I put this code?
Thanks in advance-
George :)
What you could do to constraint the rotation on one axis of your object is:
Create a variable float freezeRotationX = 5.0f; //5.0 is just an example
And write this transfrom.rotation = Quaternion.Euler(freezeRotationX, transfrom.rotation.y, transfrom.rotation.z); This line should be in the Update methode.
This will fix the rotation on the X axis and leave the other ones with their current value.
Of course you can create a variable for each axis.
Hope that helps you.
This is very simple, you really don't have to use C#, you can just set the angular velocity of a rigidbody2D really high, but if that doesn't work, try constantly setting the transforms rotations to 0, (the code would look like this in the update function,
getcomponent<yourgameobject>().transform.rotation.z = 0
getcomponent<yourgameobject>().transform.rotation.x = 0
getcomponent<yourgameobject>().transform.rotation.y = 0
the syntax probably isn't correct, and it might slow down the game, but if your beginning unity it is a simple solution.

Categories