Twitching objects in Unity during camera movement in 2D - unity3d

I'm using Windows 7 Ultimate (SP1),
Unity 5.3.2 (also tested with 5.3.0, 5.3.1, 5.2.4).
I've caused a bug which is visible in editor, standalone builds, Android builds.
Simple sceene contains:
Sphere - GameObject without sphere colider and with Rigidbody2D which is used by movement script:
private Rigidbody2D m_rigidbody;
void Start() {
m_rigidbody = GetComponent<Rigidbody2D>();
}
void Update() {
if (Input.GetAxis("Horizontal") > 0) //RIGHT
{
m_rigidbody.velocity = new Vector2(1, 0);
} else if (Input.GetAxis("Horizontal") < 0) //LEFT
{
m_rigidbody.velocity = new Vector2(-1, 0);
}
else
{
m_rigidbody.velocity = new Vector2(0, 0);
}
}
3 Cubes - static GameObjects (for abillity to see that sphere is moving)
MainCamera - classic camera, that follows shere using CS script:
public Transform m_Target;
void Update () {
transform.position = Vector3.Lerp(transform.position, new Vector3(m_Target.position.x, transform.position.y, transform.position.z), 1f);
}
Problem: while camera moves, we can see, that (static) GameObjects are "twitching" on the screen...
I've used FixedUpdate in scripts(didn't solve the problem).
Used different Interpolate settings: even used on both (sphere and camera) kinematic Rigidbody2D Extrapolate setting (didn't solve the problem).
Tried to use Rigidbody (instead os Rigidbody2D).
I've found similar question Link to unity3d.ru forum
(didn't solve the problem)
Update: I've set a movement script to Camera and turned off "camera follow". Just simple standart camera moving right (or left) with constant speed and result - static objects are twitching...

In your code,
transform.position = Vector3.Lerp(transform.position, new Vector3(m_Target.position.x, transform.position.y, transform.position.z), 1f);
...your interpolant factor is 1f. That would just make it jump directly to the target value rather than lerping it. I suggest changing that to something else, like 0.75f. That is,
transform.position = Vector3.Lerp(transform.position, new Vector3(m_Target.position.x, transform.position.y, transform.position.z), 0.75f);
I hope that helps!

Related

Top Down Shooter Animations Unity, how do you get the right directional animations to play when moving?

i'm not really sure how to phrase the question sorry about that. I have encountered this hurdle while setting up animations on a character for learning a top down character controller (No rigid body) I've seen this question asked on Reddit and unity forums like a decade ago, but I don't really understand their answers.
My problem right now is that I can't find out a way to tell mecanim if the player is moving towards the direction they're facing. For example, if the player is moving left and aiming to the left, the moveForward animation should be played. If the player is moving left but aiming to the right, the moveBackwards animation should be played.
This is the first time i'm posting a question. I am sorry if my formatting is wrong.
Here is the code I have, I would greatly appreciate any help.
public class CharacterMovement : MonoBehaviour
{
private Vector3 velocity;
private Vector3 PlayerMoveInput;
Animator animationS;
[SerializeField] CharacterController characterrController;
[SerializeField] private float MoveSpeed;
[SerializeField] private float JumpHeight;
[SerializeField] private float Gravity = -9.81f;
// Start is called before the first frame update
void Start()
{
animationS = GetComponent<Animator>();
}
// Update is called once per frame
void Update()
{
PlayerMoveInput = new Vector3(Input.GetAxis("Horizontal"), 0f, Input.GetAxis("Vertical")); //collects the input for the player
MovePlayer();
PlayerRotation();
}
private void MovePlayer()
{
if (characterrController.isGrounded)
{
velocity.y = -1f;
}
if (Input.GetKeyDown(KeyCode.Space) && characterrController.isGrounded)
{
velocity.y = JumpHeight;
}
///
else
{
velocity.y -= Gravity * -2f * Time.deltaTime;
}
Vector3 MoveVector = transform.TransformDirection(PlayerMoveInput);
characterrController.Move(MoveSpeed * Time.deltaTime * MoveVector);
characterrController.Move(velocity * Time.deltaTime);
float velocityX = Vector3.Dot(PlayerMoveInput, transform.forward);
float velocityZ = Vector3.Dot(PlayerMoveInput, transform.right);
animationS.SetFloat("velocityX", velocityZ, 0.1f, Time.deltaTime);
animationS.SetFloat("velocityZ", velocityX, 0.1f, Time.deltaTime);
}
void PlayerRotation()
{
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
RaycastHit hit;
Debug.DrawRay(ray.origin, ray.direction, Color.yellow);
if (Physics.Raycast(ray, out hit))
{
Vector3 targetPosition = new Vector3(hit.point.x, transform.position.y, hit.point.z);
Quaternion rotation = Quaternion.LookRotation(targetPosition - transform.position);
transform.rotation = Quaternion.Lerp(transform.rotation, rotation, Time.deltaTime * 10.0f);
}
}
}
This isn't the exact implementation that would be used with your code but should give you a good start.
// get the angle between where the player is pointing, and where he is moving
float angle = Vector3.Angle(MoveVector, targetPosition - transform.position);
if (angle < 90f){
//move forward animation
} else {
//move back animation
}
I haven't tested this code but the idea is that if the angle between the direction the player is facing and the direction the player is moving is less than 90 degrees, then he is moving forward. Also the variables used here: MoveVector and targetPosition are private so you will need to fix that issue before this method can be implemented.
With mechanim, its very common to have 4 separate float value params in your animator. Two are used for movement info, two are for look direction info. This lets you use blend trees based on those functions that handle alot of the pain, all you need to do is update the values in the animator with the correct ones on each update/lateupdate depending on what you are doing.
This is how my animator params are layed out as well as the locomotion blend tree, I have another on a separate layer just for the head that uses Head left right, and head updown params to, you know, control the head.
And here is the code (or at least some of it) that sets the values on the animator component
EDIT:
Sorry, forgot to mention that the function i call "LerpFloat" on the anim variable is an extention method i defined myself for the animator component, all it does is gets the float value, lerps it, then sets the float value back. It just uses Mathf.Lerp.
Thank you both for your answers, the problem was the settings of the animation clips.....
Where you tick
Root transform Rotation
Root transform position (Y)
Root transform position (XZ)
I had ticked all of them, where just the root transform rotation was needed.
I will need to be more careful with the animator and animation clips in the future to avoid headaches.

applying velocity to rigidbody makes it float instead of dashing

Im trying to code so that my Character dashes to the right when pressing the Left mouse button, but instead of dashing it just starts slowly glieding or lets say floating.
This is the code i´ve used;
if (Input.GetMouseButton(0))
{
rb.velocity = Vector2.right * DashSpeed;
}
Im not sure but a other part of my code might be the reason for this problem but if so i would like to know how i could solve it. Thats the part im talking about
rb.velocity = new Vector2(moveInput * speed, rb.velocity.y);
thats the code im using for movement.
void Start()
{
cam = Camera.main;
rb = GetComponent<Rigidbody2D>();
}
private void Update()
{
horizontal = Input.GetAxisRaw("Horizontal");
animator.SetFloat("Horizontal", Input.GetAxis("Horizontal"));
if (Input.GetKeyDown(KeyCode.Space) && isGrounded == true)
{
float jumpVelocity = 7f;
rb.velocity = Vector2.up * jumpVelocity;
jumpsound.Play();
}
Vector3 worldPos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
if (Input.GetKey(KeyCode.RightAlt))
{
Dashing();
}
}
void FixedUpdate()
{
isGrounded = Physics2D.OverlapCircle(groundCheck.position, CheckRadius, whatisGround);
moveInput = Input.GetAxisRaw("Horizontal");
rb.velocity = new Vector2(moveInput * speed, rb.velocity.y);
if (Input.GetKeyDown(KeyCode.Escape))
{
SceneManager.LoadScene("Main menu");
}
}
void Dashing()
{
rb.AddForce(Vector2.right * DashSpeed, ForceMode2D.Impulse);
}
The issue with your current code is you are directly changing velocity in a few places. Some basic physics, the integral of position vs. time graph is velocity, and the integral of velocity is acceleration vs. time. To get a more realistic movement, it is better to apply a Force to objects. When doing this, the physics engine Unity uses can add a new force at a given time, then using acceleration can accelerate the object in that direction over time, then can change the velocity over time which will result in the position changing over time.
The example code you posted, you are directly setting velocity in a few places.
rb.velocity = Vector2.up * jumpVelocity; (Jump)
rb.velocity = new Vector2(moveInput * speed, rb.velocity.y); (Movement)
rb.velocity = Vector2.right * DashSpeed; (Dash)
When directly setting these values, the new values overwrite the old ones. As your movement code is not in any sort of if conditional it will continually write to the velocity causing the dash to never change anything regardless if you use add-force or change velocity directly.
I would consider making both your jump and dash use AddForce, and if you like the feel of your movement by applying velocity directly, then add the velocity do not set it.
Your previous line rb.velocity = new Vector2(moveInput * speed, rb.velocity.y); would then become rb.AddForce(new Vector2(moveInput * speed, 0), ForceMode2D.Impulse);. Similarly you can update your jump and dash to match this. Let me know if you get this working or have more questions.
It could be a problem with your animation. Link to a thread on unity answers:
https://answers.unity.com/questions/674516/rigidbody-character-problems-constant-floating-jum.html
You should go over to the animation place and hit bake into pose.
You should use the Rigidbody2D.AddForce(Vector2, ForceMode2D). What this does is moving the GameObject in the direction of the Vector2, with the force mode of ForceMode2D. What is different about this from just translating it, is that it interacts with physics and improves the quality of your game. Here is a link, and the script:
https://docs.unity3d.com/ScriptReference/Rigidbody2D.AddForce.html
Rigidbody2D rb;
float dashSpeed;
void Update()
{
if (Input.GetMouseButton(0))
{
rb.AddForce(Vector2.right * dashSpeed);
}
}
And if the other part of the code you were talking about, if that is glitching, then do the same trick.

Unity Physics: How To Limit Rotation of Object Moved by Gravity

I have a Child object, an Iron Bar (with Rigidbody and Gravity), connected to a Long Arm (w/ Rigidbody and isKinematic). I need to restrict the rotation of the Iron Bar from 1 to 40 degree angles only so it won't go overboard and hit the Long Arm. Please refer to attached image for more info. I tried several approaches from using a Hinge Joint and its Limit options and also through code. But I cannot seem to solve this problem. Right now I have this script attached to the Iron Bar but it does not seem to have any effect.
public Transform targetTransform;
private Vector3 _currentAngle;
private Vector3 _targetAngle;
float rotationX;
void FixedUpdate () {
transform.right = targetTransform.transform.right; //-- To make the Iron Bar follow player rotation
rotationX = transform.eulerAngles.x;
if (rotationX > 40) {
_targetAngle = new Vector3 (40, transform.eulerAngles.y, transform.eulerAngles.z);
_currentAngle = new Vector3 (Mathf.LerpAngle (transform.eulerAngles.x, _targetAngle.x, Time.deltaTime), Mathf.LerpAngle (transform.eulerAngles.y, _targetAngle.y, Time.deltaTime), Mathf.LerpAngle (transform.eulerAngles.z, _targetAngle.z, Time.deltaTime));
transform.eulerAngles = _currentAngle;
} else if (rotationX < 1) {
_targetAngle = new Vector3 (1, transform.eulerAngles.y, transform.eulerAngles.z);
_currentAngle = new Vector3 (Mathf.LerpAngle (transform.eulerAngles.x, _targetAngle.x, Time.deltaTime), Mathf.LerpAngle (transform.eulerAngles.y, _targetAngle.y, Time.deltaTime), Mathf.LerpAngle (transform.eulerAngles.z, _targetAngle.z, Time.deltaTime));
transform.eulerAngles = _currentAngle;
}
}
Would appreciate any help you can provide. Thanks for taking a look.
Note: This is a revised question but related to the initial one which I have already partially solved. Revision was made for further clarification.

Unity AddExplosionForce synchronize over the Network Manager

im working on a little 3D-Game for 2 player in Unity. The game concept is a space-race, where you have to fly through rings. As an additionally feature i want to give the player the ability to push the other player. So when they hit a specific button their spaceship should send a "shockwave" that hit the other player and pushes him a little back. I wanted to realize this with the Physics.OverlapSphere and AddExplosionForce functions.
I tested this in a local extra scene without the network function and it worked very well.
As i wanted to import the function into the real game, i have the problem that the effect just hit the local player and not the other one. The other one is just lagging weirdly and didn't change his position (In the other game instance also not. It's like the client didn't get the change).
I have to say, I'm already using the Network Manager and the normal movement with "wasd" is working for both players.
Following the code I'm using (It's just the standard example):
Vector3 explosionPos = transform.position;
Collider[] colliders = Physics.OverlapSphere(explosionPos, radius);
foreach (Collider hit in colliders)
{
Rigidbody rb = hit.GetComponent<Rigidbody>();
if (rb != null)
rb.AddExplosionForce(power, explosionPos, radius, 3.0F);
}
Does somebody know, if there is something I have to add for the network thing?
Try creating a [Command] function that will run [ClientRpc] function with the code you provided. It should look something like this:
[Command]
void CmdOnExplosion(float power, Vector3 explosionPos, float radius, float upwardsMod)
{
RpcExplode(power, explosionPos, radius, upwardsMod);
}
[ClientRpc]
void RpcExplode(float power, Vector3 explosionPos, float radius, float upwardsMod)
{
Collider[] colliders = Physics.OverlapSphere(explosionPos, radius);
foreach (Collider hit in colliders)
{
Rigidbody rb = hit.GetComponent<Rigidbody>();
if (rb != null)
{
rb.AddExplosionForce(power, explosionPos, radius, 3.0F);
}
}
}

How does velocity works?

hey guys i've something here to ask about how does really the velocity on unity works ??? i've been working on a project recently, i want to create the bouncing ball games, so whenever the ball hit the collider, it will be bounced depends on the position that have been hit.
i'm using the getComponent().velocity, but somehow the ball doesn't bounce really well, and whenever the ball hit the middle of collider, it should be bounced back without changing the direction .. please help !!! any help would be grateful ... here's my code :
float getBallPos(Vector2 ballPos, Vector2 boxPos, float boxWide ){
return (ballPos.x - boxPos.x)/boxWide ;
} ---> to get the bounce direction
void OnCollisionEnter2D (Collision2D other){
isHit = true;
if (other.gameObject.tag == "up") {
float x = getBallPos (transform.position, other.transform.position, other.collider.bounds.size.x);
Vector2 dir = new Vector2 (x, 1).normalized;
Debug.Log ("normalized : " + dir);
GetComponent<Rigidbody2D> ().velocity = dir * 5f;
}else if (other.gameObject.tag == "down") {
float x = getBallPos (transform.position, other.transform.position, other.collider.bounds.size.x);
Vector2 dir = new Vector2 (x, -1).normalized;
Debug.Log ("normalized : " + dir);
GetComponent<Rigidbody2D> ().velocity = dir * 5f;
}
}
You should create a Physics Material 2D with a high bounciness and low friction and apply it to your collider2D (you should see the values until you feel comfortable with it.
You create them in Assets->Create->Physics2D Material.
What you are trying yo do is simulate physics and it requires a somewhat complex mathematical model.