I'm trying to get my basic game online and got into some problems.
I followed this tutorial which is really nice and everything worked but one thing, the interpolation.
Without interpolation, I have too much latency issues (the other player is "lagging" a lot). I tried to follow the tutorial, adding
void FixedUpdate()
{
if (networkView.isMine)
else{
syncTime += Time.deltaTime;
rigidbody2D.position = Vector3.Lerp(syncStartPosition, syncEndPosition, syncTime / syncDelay);
}
And using this method:
void OnSerializeNetworkView(BitStream stream, NetworkMessageInfo info)
{
Vector3 syncPosition = Vector3.zero;
if (stream.isWriting)
{
syncPosition = rigidbody2D.position;
stream.Serialize(ref syncPosition);
}
else
{
stream.Serialize(ref syncPosition);
syncTime = 0f;
syncDelay = Time.time - lastSynchronizationTime;
lastSynchronizationTime = Time.time;
syncStartPosition = rigidbody2D.position;
syncEndPosition = syncPosition;
}
}
But now the other player is invisible when not moving, and is visible but flickering a lot when moving (flickering so much I hardly see it). Since my method is called from FixedUpdate, I am wondering if the gameobject is simple refreshing so much that I don't even see it. Is that possible?
In any case, would you have an idea on how to fix this?
Thank you very much for your help in advance!
PS: I tried to lerp only if syncTime/syncDelay < 1.0 to be sure I don't extrapolate, but it did not change a thing.
PPS: When I use the interpolation, it flickers a lot but I can see that the position is right, it is not lagging like before, so the best would be to resolve how to make my interpolation and not removing it.
First of all, do not use Time.deltaTime in FixedUpdate(). FixedUpdate() is for physics only and actually runs around 50fps. On the other hand Time.deltaTime is the time for the last frame. So, technically you will get flickering in your lerp function. Use the function in Update(). And I can see, you are just transforming positions. So, why rigidbody2D.position? you can use transform.position and move the whole codes to Update(). Hope it will help.
Related
I was trying to make my object change direction when it moves by 1 unit, so i set its rigidbody.velocity to be 0.25, and set a coroutine that changes its direction every 4 seconds. But i noticed that it has some small inaccuracies (such as changing direction when moved by 0.998), which builds up to a lot after running for some time.
Now I know the best way is probably to just directly change transform.position in this case, but could someone tell me why does my previous method have these inaccuracies?
Edit:
To add a bit of context, im trying to replicate a traditional snake game but with smooth movement(in stead of jumping between the grids). It was a bit hard to explain how the direction can only be changed when the snake has reached a whole unit so i just said that the direction is changed every 4 seconds in the original post. Here is the code
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SnakeHead : MonoBehaviour
{
private Rigidbody2D rigidBody;
private Vector2 currDir;
[SerializeField] private float speed;
void Start()
{
rigidBody = gameObject.GetComponent<Rigidbody2D>();
currDir = Snake.Instance.GetDir();
StartCoroutine(Move());
}
IEnumerator Move()
{
while (GameManager.gameIsRunning)
{
currDir = Snake.Instance.GetDir();
rigidBody.velocity = currDir * speed;
yield return new WaitForSeconds(1 / speed);
}
}
}
note that i set speed to be 0.25 in the unity editor window.
im aware that changing transform.position directly is bad practice, but ive watched several tutorials and all of them did that on the snake's movement. Does anyone know if there's a better way?
It's pretty hard to make it such that you change direction exactly after 4 seconds. Using WaitForSeconds(4) will not wait exactly 4 second, instead it will wait at least 4 seconds as correctly mentioned in the comments. It largely depends on how frequently your coroutine is checked by the engine.
As you already mentioned, it would probably be a good idea to do some explicit actions. Either moving it "by hand" (not through the physics simulation), or periodically set the position to a known value.
So, I'm trying to make my own movement script for Unity with a Rigidbody component attached to my character, and I'm using this code inside of the update function:
// Up above, in public scope, before Start and Update functions
public float speed = 1f;
public Rigidbody body;
void Update() {
if (Input.GetKey(KeyCode.LeftArrow())) { // Left arrow key
body.AddForce(transform.forward * speed * Time.deltaTime);
}
}
My problem is, since it's inside of the Update() function, it keeps going, it keeps turning, even if I don't have the key pressed.
Does anyone know how to fix this problem? I have tried taking away Time.deltaTime but Brackeys said you use it so that it's frame rate dependent, so if you have a higher frame rate it doesn't turn faster, and same with a low frame rate, you turn slower. Thanks in advance.
It keeps turning even after releasing the key? Yep that's what AddForce will do.
After you apply a force to an object it will continue to move based on that force uless it has drag or an opposing force is applied. Go into the rigidbody to set the drag or create a script that applies an opposing force once you stop pressing the button.
If you put a Debug.Log within the if statement you will see it is not called every frame but only when you have the button held down.
And last, I don't think that your keycode should have () after LeftArrow, does this not produce an error?
An object in motion stays in motion with the same speed and in the
same direction unless acted upon by an unbalanced force.
---- Isaac Newton
So if you want to stop the object, you can do:
Add an oppsite force
if (Input.GetKey(KeyCode.LeftArrow())) {
...
} else if (!body.IsSleeping()) {
body.AddForce(-body.velocity * factor);
}
Give a drag value
body.drag = dragValue;
You have two questions, one on the title and another one on the description.
For the title one:
The only way to stop/break Update() cycle is to disable the script, like this:
enabled = false;
For the description one:
You have to stop the force applied to the object (as the rest of the answers exemplify).
You can apply an opposite force, or just set velocity to 0.
rigidbody.velocity = Vector3.zero;
I just learn Unity3d for a while, then I have a question about The Camera Follow and Background move are not smooth. I create a cube with ragidbody2d , then i use two dufferent ways to make camera follow :
a. I make the camera in the cube
b. I use Script to control the camera (lateupdate use)
And I add some pictures which are converted into sprite (the size is 1024*512). I make them to backgound.
when play it , both methods have the same problem, the background move is not smooth, but not completely smooth at all,it will appear from time to time.
I tried the official 2d example found in fast-moving role the backgound is not smooth too. But there are some game made by Unity like badland, when I play it ,there is no this problem.I dont know how to solve this problem, Is the camera configured ? Scirpt? The Type of texture? compressed way? or Need to use some plug-ins?
please help me .thank you .
use "LateUpdate"
LateUpdate is called after all Update functions have been called. This is useful to order script execution. For example a follow camera should always be implemented in LateUpdate because it tracks objects that might have moved inside Update.
It probably because the updates you're using are not synced.
There's the main update (triggered each frame, time between those are different (Time.deltaTime)), FixedUpdate (triggered every physics update, which is a fixed time (Time.fixedTime)) and LateUpdate (every frame, but at the very last).
If you're trying to follow a rigidbody affected by physics, it's recommended to set the camera update function to Late- or FixedUpdate.
You can use it in the Update function if you set the interpolation of the rigidbody in it's inspector:
A rigidody gets an update for it's position every x fixed time, the Update function can be triggered 5 times when FixedUpdate has only been called once, or vice versa. This will give strange results, so setting the rigidbodies interpolation will smooth things out between those unsynced updates.
Also, you can move the camera smoothly by using Lerp methods. an example:
void Update() {
Camera.main.transform.position = Vector3.Lerp(Camera.main.transform.position, targetPosition, Time.deltaTime * 5);
}
more about lerping here
Hope this helps
I found another problem that I don't move camera at all, just move a GameObject which has some pictures as backgound. The Script of Moving GameObject is
Update()
this.transform.Translate(Vector3.right * Time.deltaTime * 40.0f, Space.World);
or
Vector3 pos = this.transform.position;
pos.x += (100.0f * Time.deltaTime);
transform.position = Vector3.Lerp(transform.position, pos, Time.deltaTime * 50);
the reuslt is the background move is not smooth with a visual lag, but not completely smooth at all,it will appear from time to time.
Is there some configures wrong? Graphics Emulation? or something else ?
I need to move some transforms with attached colliders to a specific position, then check if one of them is hit by raycast.
I've done that the naive way (pseudo code) :
foreach(object in objects){
actual_position = object.transform.position
object.transform.position = object.new_position
}
if(Physics.Raycast(...)) objectHit();
// Then I revert each of them them back to their actual_position
After testing multiple times with the same context (same positions between tests for each objects), the raycast sometimes miss, sometimes not (~50/50).
Done a bit of research and found that in the Raycast doc page :
If you move colliders from scripting or by animation, there needs to
be at least one FixedUpdate executed so that the physics library can
update its data structures, before a Raycast will hit the collider at
it's new position.
So I calmed my anger and started looking for a solution.
This thread has a way using a coroutine to wait the next tick :
Raycast doesn't work properly
I'm affraid it won't work for me, as I need the objects to get back to their real position instantly.
This process can happen multiple times per frame (each time a player fire his weapon)
Is there a way to force the colliders update ?
If not... should I make my own raycasts and colliders ? :(
Thanks
Another workaround is to deactivate and activate Gameobject (attached collider) immediately. In this case collider position will be updated in single frame.
Another solution is
Physics.autoSyncTransforms and Physics.SyncTransform
Maybe you can try this out (adding to your pseudo-code):
foreach(object in objects)
{
actual_position = object.transform.position;
object.transform.position = object.new_position;
StartCoroutine(CheckToRevertOnNextFixedUpdate(object, actual_position));
}
IEnumerator CheckToRevertOnNextFixedUpdate(object, actual_position)
{
yield return new WaitForFixedUpdate();
if(Physics.Raycast(...)) objectHit();
// Then I revert each of them them back to their actual_position
}
Essentially this delays your check to the next FixedUpdate() for each object - and reverts each of them if needed. I hope this is not overcomplicated, since you only add a few lines of code.
I'm also assuming that moving the object's position for 1 FixedUpdate() frame would not have a visual effect of the the object teleporting to the new position and back. However, you can always move the collider only, and then move the rest of the transform there after the FixedUpdate().
Performance-wise, the best method seems to be updating the RigidBody.position:
private Rigidbody Rigidbody;
void Start()
{
Rigidbody = gameObject.GetComponent<Rigidbody>();
}
void Upate()
{
//.... your code
Rigidbody.position = newPosition;
}
Much faster then deactivate/activate or Physics.SyncTransform().
I am trying to move my player by using rigidbody.velocity:
rigidbod.velocity = new Vector2 (Input.GetAxis ("Horizontal") * maxSpeed, rigidbod.velocity.y);
the problem is, this messes up of my explosion code. The character is supposed to be knocked back when near an explosion. I know why it happens; if the player is still, the rigidbody's X velocity would be returned as 0, meaning any outside forces pushing the player along the X axis would counteract this. So when I add the explosion, the player cuts to his new position a few units away. It looks very unnatural and jerky, as he should be pushed back, but his code is telling him to be still unless a key is pressed. I'm posting this to see if there's any way I can re-write this code to be able to move the player while being pushed correctly from outside forces. I heard that AddForce works, but when I used it, my player's velocity constantly increased. He is wither way too fast or way too slow. Any ideas on how I can get this to work? I tried adding rigidbody.velocity.x after where it says 'maxspeed' hoping that it would allow outside force input, and it works, but it messes up the movement code, making him go way too fast. I can't seem to get both the explosions and the movement code to work correctly at the same time. Any help would be greatly appreciated. Thanks.
which is exactly why in the Unity docs they explicitly state:
In most cases you should not modify the velocity directly, as this can
result in unrealistic behaviour.
instead of modifying the velocity directly, you should be using an AddForce(..)
Vector2 force = new Vector2 (Input.GetAxis ("Horizontal") * maxSpeed, 0f);
rigidbody.AddForce(force);
//or if in update:
rigidbody.AddForce(force * Time.deltaTime);