Goal: Syncronize player position in a multiplayer game in Unity that uses the Mirror Networking API
Problem:
Using the NetworkTransform component the position seems to not be precisely syncronized, both the client and the server sees the player in the wrong position, players tend to fly with no reason
I tried making a separated script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Mirror;
public class PlayerSyncronization : NetworkBehaviour
{
[SyncVar]
public Vector3 syncPosition;
[SyncVar]
public Quaternion syncRotation;
public float lerpRate = 15;
private void FixedUpdate()
{
TransmitPosition();
Lerp();
}
void Lerp()
{
if (!hasAuthority) return;
transform.position = Vector3.Lerp(transform.position, syncPosition, Time.deltaTime * lerpRate);
transform.rotation = Quaternion.Lerp(transform.rotation, syncRotation, Time.deltaTime * lerpRate);
}
[ClientCallback]
void TransmitPosition()
{
CmdProvidePositionToServer(transform.position, transform.rotation);
}
[Command]
void CmdProvidePositionToServer(Vector3 pos, Quaternion rot)
{
syncPosition = pos;
syncRotation = rot;
}
}
but the result is the same of the network transform component, and even if a player stops walking, on the other side he keeps walking till he falls off the map
Those are the errors/warning i got using the script
Info:
Player movement is client side as I'm using root motion.
I can't use IsLocalPlayer as it works only if the player is directly spawned by the NetworkManger and my players are being spawned by a separated script.
Right now, even if I'm not using it, i have a CharacterController in my PlayerPrefab
I'm using Steamworks to make the players connect through internet
If more info are needed just tell me.
I understood that the problem was the Character controller I was using, so in the player script I checked if the player had authority, if not I destroyed the character controller, and if i was destroying it on the server I replaced it with a normal collider without physics, so i could still have collisions
Related
I was attempting to make a top down 2D shooter using Unity. My code contains no errors that I could see, RigidBody2D and PlayerMovement (code for the player to move) have been added to the sprite, and RigidBody2D has been added to the PlayerMovement. My move speed is set to 5. Please let me know what I can do to fix this issue!
Code:
using System.Collections.Generic;
using UnityEngine;
public class PlayerMovement : MonoBehaviour
{
public float moveSpeed;
public Rigidbody2D rb;
Vector2 movement;
void Update()
{
MovementInput();
}
private void FixedUpdate()
{
rb.velocity = movement * moveSpeed;
}
void MovementInput()
{
float mx = Input.GetAxisRaw("Horizontal");
float my = Input.GetAxisRaw("Vertical");
movement = new Vector2(mx, my).normalized;
}
}
Use your character sprite as the mouse cursor instead to write a code to make the player follow the mouse pos
If you really want to move your player via script this video will help you https://www.youtube.com/watch?v=0Qy3l3VuF_o
Have a good day :)
Check if your rigidbody2D's Body type is set to static, If it is then set it to kinematic or dynamic.
Also where did you import the script to?
Your code is not the problem, I tested it myself! Although you could move MovementInput(); to the FixedUpdate. Its not required though.
Edit: Image of the inspector as i have it if it helps
I am currently working on the Flooded Grounds Unity Asset, I'm implementing an Alien NPC, with a script that tells it to follow the player.
The problem that I'm encountering is that the Alien turns his back to the player and I can't figure out why. I also tried rotating it by 180° on the Y axis (both in the transform and inside of the script using transform.rotate.y - when using the transform doesn't make any difference while using it in the update function just makes it constantly snap back and forth).
Here's a video of the issue:
https://drive.google.com/file/d/1tC9zJWKXXDuNZNZJbl2htBUgTPSTB4IG/view?usp=sharing
And here's the script that I'm using:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;
public class EnemyFollow : MonoBehaviour
{
public NavMeshAgent enemy;
public Transform Player;
private Rigidbody alienRb;
private Animator alienAnim;
// Start is called before the first frame update
void Start()
{
alienRb = GetComponent<Rigidbody>();
alienAnim = GetComponent<Animator>();
}
// Update is called once per frame
void Update()
{
enemy.SetDestination(Player.position);
if(enemy.velocity.magnitude > 0)
{
alienAnim.SetTrigger("Walk");
}
}
}
Any help would be very appreciated!
Hello Mazza ^^ First of all, I have to say that your alien monster is really cute :D Anyway, did you try transform.LookAt(Player.transform.position)? Also, transform.rotation is might not be affective, maybe you can try alien.transform.Rotate(0.0f, 90.0f, 0.0f, Space.Self); or transform.rotation = Quaternion.Euler(transform.rotation.x, transform.rotation.y - 180f, transform.rotation.z)
I'm creating a game with Unity and I'm learning C#. I needed some help with a bullet firing mechanism for my game so I found the below script on Unity Answers. It works great, but fires the bullet backwards (which would land anyone in the game in a bad situation). Could anyone help? Thank you!
using UnityEngine;
using System.Collections;
public class ShootDemo : MonoBehaviour
{
public Rigidbody projectile;
public float speed = 20;
// Update is called once per frame
void Update()
{
if (Input.GetButtonDown("Fire1"))
{
Rigidbody instantiatedProjectile = Instantiate(projectile, transform.position,
transform.rotation) as Rigidbody;
instantiatedProjectile.velocity = transform.TransformDirection(new Vector3(0, 0, speed));
}
}
}
What you have would work if you had the forward (blue axis) of the gameobject of ShootDemo pointing in the direction you'd want to shoot.
The fact that does that shoots it in the opposite direction means the forward is pointing is actually pointing in the opposite direction.
Taking that into account by negating speed will reverse the velocity to create the desired effect:
instantiatedProjectile.velocity = transform.forward * -speed;
Or in the format you've already used
instantiatedProjectile.velocity = transform.TransformDirection(new Vector3(0, 0, -speed));
I have a rectangle player sprite with a Box Collider 2D and a Rigidbody2D attached. I also have a script for point-and-click movement attached to the player object (i.e. player moves to mouse click position). However as soon as the player character hits a collider, it starts to jitter rather than just fully stop. I don't know a lot about Unity physics other than what I've picked up in a few tutorials, so I'll include as much relevant information as I can.
The Rigidbody 2D component has all forces set to 0, except for mass being 0.0001. The body type is dynamic, and collision detection is set to continuous. My movement script looks like this, got it straight from a tutorial:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerControls : MonoBehaviour
{
public float speed = 1;
private Vector3 target;
void Start()
{
target = transform.position;
}
void Update()
{
if (Input.GetMouseButtonDown(0)) {
target = Camera.main.ScreenToWorldPoint(Input.mousePosition);
target.z = transform.position.z;
}
transform.position = Vector3.MoveTowards(transform.position, target, speed * Time.deltaTime);
}
}
Is there an easier way to implement smooth point-and-click movement?
I have made a Raycast that goes from my camera to the point of the object clicked. However, I am trying to make an object (in this case a bullet) to fly along the path of the ray. At the moment it flies straight forwards from the camera no matter where on the object you click because of the vector 3. How would I get it to follow the Ray?
C#
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class RaycastShot : MonoBehaviour {
public Camera camera;
private Ray ray;
private RaycastHit hit;
public GameObject bullet;
private GameObject createBullet;
private Collider collider;
void Update () {
if (Input.GetMouseButtonDown (0)) {
ray = camera.ScreenPointToRay (Input.mousePosition);
createBullet = Instantiate (bullet, camera.transform.position, bullet.transform.rotation);
createBullet.AddComponent<Rigidbody>();
createBullet.GetComponent<Rigidbody>().AddRelativeForce (new Vector3(0, 1500, 0));
createBullet.GetComponent<Rigidbody>().useGravity = false;
collider = createBullet.GetComponent<Collider> ();
Destroy (collider);
if (Physics.Raycast (ray, out hit)) {
}
}
Debug.DrawLine (ray.origin, hit.point, Color.red);
}
}
You would want to use ray.direction property instead of (0,1500,0) as the direction of the force.
The add force should occur in FixedUpdate, and should only occur if the Ray hits something. Where you have it now is probably not the best spot.
Of course, make sure the bullet gets instantiated at the camera's location first.
Ray.direction gives you the vector3 direction of the ray object. If you need the distance at which it hit, you could also use ray.distance.
Edit: I'm near my computer now, so here's a more detailed answer relating to your comments.
First off: Here's the way I set up the test Project:
I Created a prefab bullet. This is just a sphere with a rigidbody, with my "BulletController" script attached to it. The point of prefabs is to avoid all of those lines where you have to add components. For testing purposes I set the rigibody to ignore gravity and its mass to 0.1.
Next, I created the BulletController script, which will be attached to the bullet prefab.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class BulletController : MonoBehaviour {
Rigidbody rb;
public float bulletForce;
bool firstTime = false;
Vector3 direction;
// Use this for initialization
void Start () {
rb = GetComponent<Rigidbody> ();
}
public void SetDirection (Vector3 dir) {
direction = dir;
firstTime = true;
}
void OnCollisionEnter () {
//code for when bullet hits something
}
void FixedUpdate () {
if (firstTime) {
rb.AddForce (direction * bulletForce);
firstTime = false;
}
}
}
This script is is charge of controlling bullets. The (later on) script that will create the bullets doesn't really care what happens to them afterwards, since its job is just to create bullets. This BulletController script is in charge of dealing with bullets once they're created.
The main parts are the SetDirection method which tells the bullet which direction to travel in. Also it adds a one-time force in its FixedUpdate method that pushes it in the direction you just set. FixedUpdate is used for physics changes like adding forces. Don't use Update to do this kind of thing. It multiplies the force by a force that you set called "bulletForce".
Finally the BulletListener Script, which is simply attached to an empty game object in the scene. This script is in charge of listening for mouse clicks and creating bullets towards them.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class BulletListener : MonoBehaviour {
public Camera mainCamera;
public BulletController bulletPrefab;
void Update () {
if (Input.GetMouseButtonDown (0)) {
//create ray from camera to mousePosition
Ray ray = mainCamera.ScreenPointToRay (Input.mousePosition);
//Create bullet from the prefab
BulletController newBullet = Instantiate (bulletPrefab.gameObject).GetComponent<BulletController> ();
//Make the new bullet start at camera
newBullet.transform.position = mainCamera.transform.position;
//set bullet direction
newBullet.SetDirection (ray.direction);
}
}
}
In the inspector for this empty game object, I added this script, and then dragged the camera, and the bulletPrefab into the appropriate fields. Be sure to drag the prefab from the FOLDER, not from the SCENE. Since this will use the prefab, not an object in the scene.
Now click around and you'll see the bullets flying! Note that using a low force is good to test, and then increase it later.
The main things to take away from this is to split up your logic. A script should only be in charge of one thing. For example, your enemies might also fire bullets. You can now reuse your bulletController script for those bullets as well. Also, say you have different sized or shaped bullets, you can just drag the bulletcontroller script onto the different prefabs you've made for your bullets. This will not affect your listener script which will still create bullets where you click.
If you have the end point then you can move along the vector with MoveTowards:
Vector3 target = hit.point;
StartCoroutine(MoveAlong(target));
private IEnumerator MoveAlong(Vector3 target){
while(this.transform.position != target){
this.transform.position = MoveTowards(this.transform.position, target, step);
yield return null;
}
}