Please look at the photo. There are two objects.
left circle object = circle colider2D + rigidbody2D(freeze Rotation Z, script for move )
Rigidbody2D rigid;
float moveX;
void Start()
{
rigid = gameObject.GetComponent<Rigidbody2D>();
}
void PlayerMove(){
moveX = Input.GetAxisRaw("Horizontal");
rigid.velocity = new Vector2(moveX * 5f, rigid.velocity.y);
}
void Update(){
PlayerMove();
}
right square object = square colider2D + rigidbody2D(freeze positionY, freeze positionX, freeze Rotation Z)
I can move the circle from side to side.
While I press the keyboard and push the circle to the right wall, gravity doesn't work.
I don't know why. I hope gravity will work even if the circle hit the wall.
How can I prevent the problem?
Looks like physics material that's applied to that rigidbody has too much friction and slows down too much when hugging the wall. Try reducing friction value on the material (you can create the physics2D material from the assets panel).
Related
My game is 2D from a top down-ish perspective, my character movement vector2 being fed into the animator blend to determine which direction my sprite faces: (example sprite)
Vector2 movement = new Vector2(Input.GetAxis("Horizontal"),
Input.GetAxisRaw("Vertical"));
anim.SetFloat("hor", movement.x);
anim.SetFloat("ver", movement.y);
However, I would like my sprite to rotate to it's new target vector2 rather than instantly switch to it. So if I was facing right, and I pushed left, the movement vector2 would travel over time to a new movementTarget vector2, the sprite changing from facing right, to up, to left.
I cannot figure or find a way to do this and have been on it many hours. I've tried things like Vector3.RotateTowards and angles, but each approach I can't get what I'm looking for as this aspect of math just confuses me.
Could someone point me in the right direction?
Vector2 targetMovement = new Vector2(Input.GetAxis("Horizontal"),
Input.GetAxisRaw("Vertical"));
if (targetMovement != movement) coroutine?????
I don't want to rotate the sprite image, or the object transform, just the movement Vector2 variable over time. So if I am facing right (1,0) and press left, I want the Vector to travel through (0,1 - up) then finally to (-1,0 - left) but gradually.
Managed to do it like this. Unsure if best way?
float currAngle, targAngle;
Vector2 movement = new Vector2(Input.GetAxis("Horizontal"),
Input.GetAxisRaw("Vertical"));
if (movement != Vector2.zero)
targAngle = Mathf.Atan2(movement.y, movement.x) * Mathf.Rad2Deg;
if (Mathf.Abs(currAngle - targAngle) > 1f) {
currAngle = Mathf.LerpAngle(currAngle, targAngle, 10f * Time.deltaTime);
Vector2 newVec = new Vector2(Mathf.Cos(currAngle * Mathf.Deg2Rad),
Mathf.Sin(currAngle * Mathf.Deg2Rad));
anim.SetFloat("hor", newVec.x);
anim.SetFloat("ver", newVec.y);
}
I wrote a simple player movement script which moves my player like this:
private void MovePlayer()
{
// Initialize Directions For Player Movement
movement = transform.right * horizontal * playerSpeed + transform.forward * vertical * playerSpeed;
// Move Player
rb.AddForce(movement, ForceMode.Acceleration);
}
and I am trying to rotate my player towards the axes, for example if the player is pressing a the horizontal will be -1 and I want to rotate my player left horizontal * 90f, now when I try this, my horizontal axis is acting like my vertical, if I press A it will bring my player backwards, if I press D it will do the same thing, this is how I rotate the player:
// buggy code:
private void RotatePLayerTowardsAxis()
{
// Rotate PLayer Horizontaly
transform.rotation = Quaternion.Euler(0f, horizontal * 90, 0f);
}
is there a way I can do this?
Edit:
The vertical is still pushing me up and down.
First, it is important to check if you are looking at the scene in Local or Global view. Check your axes in Local mode:
If your character model faces towards the blue axis, then everything should be okay.
If you want to rotate your character only by 90 degrees all the time, then it can be done somehow like this:
transform.rotation = Quaternion.Euler(0, 90, 0);
You can use the following as well, but this might not fit your needs:
transform.Rotate(transform.up, 90);
This will make your character rotate by 90 degrees AROUND the up axis. If you want it to rotate always around the world up axis:
transform.Rotate(Vector3.up, 90);
However, transform.rotation = Quaternion.Euler(0, 90, 0); might be better for you, as it always "resets" the rotation when you overwrite it. This will make the character fixed to a direction. So if you press left, the charater will always look into the left by 90 degree. And if you press right after the left turn, your character will do a 180° turn instead of looking forward. I hope you get what I'm trying to say. This means, that your character will be bound to the world axis instead of its own. To modify this (if you want to), write something like this:
transform.rotation += Quaternion.Euler(0, 90, 0);
Hope I could help!
My ball can only bounce on the y axis. X and Z movement as well as all rotation are locked in the rigidbody component. Originally I was planning to handle this using a combination of the two methods below. I'm adding my own faux-gravity to the object in FixedUpdate and bouncing the ball upwards when it collides with a platform in OnCollisionEnter. Esentially sending it bouncing up and down forever.
void OnCollisionEnter(Collision collision)
{
ball.AddForce(Vector3.up * force, ForceMode.Impulse);
}
void FixedUpdate()
{
Vector3 gravity = globalGravity * Vector3.up;
ball.AddForce(gravity, ForceMode.Acceleration);
}
The problem is that if I place an angled platform under the ball, it no longer bounces vertically with the same force. I believe this is because Unity Physics is calculating the angle/force the object should bounce in a 3D space, and then because of my script only applying the upward force of that calculation. However, I'd like my ball to bounce with a consistent vertical force regardless of the angle of the platform placed under it.
This could be achieved using a coroutine and Lerp to a certain height, which I tried using the script below, using Physics gravity this time, but it didn't have the same natural bouncing feel as Unity Physics. I'd like to go back to using the Physics system but I don't know how to stop Unity from doing the angular calculation and just launch my ball vertically with the force I want.
IEnumerator MoveBall(Vector2 newPos, float time)
{
ball.useGravity = false;
float elapsedTime = 0;
Vector2 startingPos = transform.position;
while (elapsedTime < time)
{
transform.position = Vector2.Lerp(startingPos, newPos, (elapsedTime / time));
elapsedTime += Time.deltaTime;
yield return null;
}
ball.useGravity = true;
}
It sounds like you want your collider to be setup as a trigger. On your ball's collider, set isTrigger to true and then use OnTriggerEnter instead of OnCollisionEnter. This will prevent Unity's physics engine from creating and resolving a Collision between the ball and whatever it hits.
If you'd also want the ball to bounce off other objects in way that uses Unity's Physics, you'll need to then get creative with which colliders are/arent' triggers, and which physics layers they belong to.
This is the image of what I'm trying to achieve, in a 3D space. I want the object to follow my finger within the green zone, but stay on the edge of the green zone if I move my finger outside of it. I have achieved this with the code below, but when moving my finger around the red zone a lot of jitters and clipping occurs as the object keeps snapping back within it's bounds. The jitters I'm seeing are caused when holding my finger in the red zone out of the players circle bounds. Instead of being "stuck" in the bounds the player is trying to continue and then being positioned back within the bounds, causing jitters. I'm looking for a way to limit the movement of the player within the bounds without having to reset it's position. My main camera is attached to the moving object so it's important that I eliminate the jitters. How can I smooth this out?
public class Player : MonoBehaviour
{
public Camera movementCam;
readonly float radius = 0.45f;
readonly float speed = 3f;
Ray firstTouchPos;
Vector2 playerPos;
[SerializeField] Vector3 targetPosition;
readonly float followDelay = 20f;
void Update()
{
if (Input.GetMouseButtonDown(0))
{
firstTouchPos = movementCam.ScreenPointToRay(Input.mousePosition);
playerPos = transform.position;
}
if (Input.GetMouseButton(0))
{
Ray currentTouchPos = movementCam.ScreenPointToRay(Input.mousePosition);
Vector2 direction = currentTouchPos.origin - firstTouchPos.origin;
float distance = Vector3.Distance(transform.position, Vector3.zero);
targetPosition = distance >= radius ? (Vector3) . (direction.normalized * radius) : (Vector3)(playerPos + direction * speed);
}
transform.position = Vector3.Lerp(transform.position, targetPosition, followDelay);
}
}
Your issue is incorrectly clamping, a simple fix would be:
if (Input.GetMouseButton(0))
{
Ray currentTouchPos = movementCam.ScreenPointToRay(Input.mousePosition);
Vector2 direction = currentTouchPos.origin - firstTouchPos.origin;
float distance = Vector3.Distance(transform.position, Vector3.zero);
targetPosition = (Vector3)(playerPos + direction * speed);
if (targetPosition.sqrMagnitude > radius * radius) //if our calculated position is greater than the radius...
targetPosition = targetPosition.normalized * radius; //set our calculated position to be exactly on the radius.
}
The jitter was caused by your object leaving the radius one frame, and on the next frame would be clamped back to the radius, only for it to attempt to move outside the radius again the next frame.
This way removes the ternary operator, which means it will behave consistently across frames, rather than switching between clamp and movement each frame.
Here are some additional pieces of advice for this issue, once you fix the above problem:
You should multiply speed and followDelay by time.deltaTime in order to smooth them across frames correctly.
You should probably apply your camera motion during LateUpdate() instead of Update(), LateUpdate() happens after all your updates happen, what can happen is during Update() objects can move around before and after your camera code is called, causing it to behave slightly inconsistently from frame to frame, applying the motion in LateUpdate() to the camera means your camera moves only when all your objects have 'settled' into place after their update, making it behave more consistently.
Additionally you're technically using Lerp() wrong here, it shouldn't cause jitter but it's not exactly how lerp should be used. Are you sure you don't want Vector3.MoveTowards() instead?
I am making a 2D game in Unity. I have added a 2D box collider and a circle collider as trigger on my sprite character. The platform on which the character is standing also have a 2D box collider. So, when my character moves near edge of platform, it experiences a force or something that pulls it away from the edge. You can think it as a protective force that helps your character not falling down the plane but the problem is that this force is not part of game and that's why it should not be there. Following is the code I am using to move my character:
// call this method to move the player
void Move(float h)
{
// reduces character velocity to zero by applying force in opposite direction
if(h==0)
{
rigidBody.AddForce(new Vector2(-rigidBody.velocity.x * 20, 0.0f));
}
// controls velocity of character
if(rigidBody.velocity.x < -topSpeed || rigidBody.velocity.x > topSpeed)
{
return;
}
Vector2 movement = new Vector2 (h, 0.0f);
rigidBody.AddForce (movement * speed * Time.deltaTime);
}
Here is image of properties.
If I keep pushing the character it will fall off the edge but if I stop just by edge the unwanted protective force pulls it back on plane.
Also, if the character bumps into another 2D box collider, it bounces back instead of just falling down.
EDIT- Bouncing effect arises mostly when player bump into other objects while jumping. Code for jumping is
void Update()
{
// The player is grounded if a linecast to the groundcheck position hits anything on the ground layer.
grounded = Physics2D.Linecast(transform.position, groundCheck.position, 1 << LayerMask.NameToLayer("Ground"));
// If the jump button is pressed and the player is grounded then the player should jump.
if(Input.GetButtonDown("Jump") && grounded)
jump = true;
}
void Jump()
{
if (jump)
{
jump = false;
rigidBody.AddForce (Vector2.up * jumpSpeed * Time.deltaTime);
}
}
The problem lies in how you're implementing the "drag" force that slows your player down to zero. Because game physics happens in steps rather than continuously, your opposing force can overshoot and briefly cause the character to move in the opposite direction.
In this situation your best bet is to multiply your speed by some fraction each frame (likely between 0.8 and 0.95), or to use Mathf.Lerp to move your X velocity towards zero.
rigidbody.velocity += Vector2.right * rigidbody.velocity.x * -0.1f;
OR
Vector3 vel = rigidbody.velocity; //Can't modify rigidbody.velocity.x directly
vel.x = Mathf.Lerp(vel.x, 0, slowRate * Time.deltaTime);
rigidbody.velocity = vel;
Also give some thought to doing your movement/physics related code within FixedUpdate() instead of Update() and using Time.fixedDeltaTime instead of Time.deltaTime. This will allow for more consistent results independent of framerate.