I am currently making my first experience with the Netcode for Gameobject package from unity.
I would like to implement a server authorized movement of players. Here I encounter various problems and hope you can help me at this point or give me some food for thought.
So I have a playerprefab which has the network transform component in it. In this I have selected that only the X and Y coordinates should be synchronized.
The first try looked like this
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Unity.Netcode;
public class PlayerNetwork : NetworkBehaviour
{
Vector3 moveDir = new Vector3(0, 0, 0);
float speed = 10;
void Start()
{
}
void Update()
{
if (!IsOwner) return;
moveDir = new Vector3(0, 0, 0);
if (Input.GetKey(KeyCode.W)) moveDir.y = -1f;
if (Input.GetKey(KeyCode.S)) moveDir.y = +1f;
if (Input.GetKey(KeyCode.A)) moveDir.x = -1f;
if (Input.GetKey(KeyCode.D)) moveDir.x = +1f;
transform.position = moveDir* speed * Time.deltaTime;
}
}
in this attempt, the host can move itself, but the client cannot.
I understood that the client initiates the movement locally, but the Network Transform component synchronizes the server's movement data over it again.
So I assumed I had to tell the server the new position so it would sync the new position to the client.
Thus my next attempt:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Unity.Netcode;
public class PlayerNetwork : NetworkBehaviour
{
Vector3 moveDir = new Vector3(0, 0, 0);
float speed = 10;
void Start()
{
}
void Update()
{
if (!IsOwner) return;
moveDir = new Vector3(0, 0, 0);
if (Input.GetKey(KeyCode.W)) moveDir.y = -1f;
if (Input.GetKey(KeyCode.S)) moveDir.y = +1f;
if (Input.GetKey(KeyCode.A)) moveDir.x = -1f;
if (Input.GetKey(KeyCode.D)) moveDir.x = +1f;
Vector3 pos = moveDir* speed * Time.deltaTime;
moveServerRPC(pos);
}
[ServerRpc]
void moveServerRPC(Vector3 pos)
{
transform.position = pos;
}
}
Now the client can move, but it feels very "hakelig".
It got better after I disabled interpolating on the Network Transform.
Additionally I rewrote the ServerRPC function as follows:
[ServerRpc]
void moveServerRPC(Vector3 pos)
{
transform.Translate(pos);
}
now the movements look smoother but the movement on the client still feels staggered and a bit spongy. Of course, this would be unthinkable for an FPS shooter or similar. But even if it doesn't matter in terms of gameplay, it just doesn't feel good to use.
In the respective readings, it is always recommended to control the movement via a Client Network Transform component, but at the same time it is not recommended to do so in competitive games. Unfortunately, I can't find any examples of this.
How would one proceed here? How far off is my idea and what would have to be changed to get a fluid but server controlled movement?
Related
I have made this script to move my player with no physics involved:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class movement : MonoBehaviour
{
[SerializeField] private float speed;
private float horinzontal;
private float vertical;
private void Update()
{
vertical = Input.GetAxis("Vertical");
horinzontal = Input.GetAxis("Horizontal");
if (horinzontal > 0.01f)
transform.localScale = Vector3.one;
else if (horinzontal < -0.01f)
transform.localScale = new Vector3(-1, 1, 1);
}
}
But my player is not moving, he is just turning left and right?
Why does it happen and how can I fix this issue?
Right now, your code is just changing what direction the player faces since you're editing transform.localScale (how big the object is / what direction your object faces). You want to edit transform.position of the GameObject (the location of your object).
Assuming that this is a 2D project, for basic horizontal movement you can do the following:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Movement : MonoBehaviour
{
public float speed = 5f;
private void Update()
{
if (Input.GetAxis("Horizontal") > 0.01f)
{
transform.localScale = Vector3.one;
transform.position = new Vector2(transform.position.x + (speed * Time.deltaTime), transform.position.y);
}
else if (Input.GetAxis("Horizontal") < -0.01f)
{
transform.localScale = new Vector3(-1, 1, 1);
transform.position = new Vector2(transform.position.x - (speed * Time.deltaTime), transform.position.y);
}
}
}
This will be enough to get you started. If you want to be sure you understand how this works, try adding vertical movement in yourself, the code is very similar to what I've written here (even if you don't need vertical movement its good for practice).
This approach is by no means perfect, or even good. You will need to fine tune how the character moves to what you want in your game. I highly recommend you try some of the Unity tutorials to help familiarize yourself with C# and Unity.
I especially recommend the Unity microgame tutorials if longer projects seem too daunting. It will give you a crash course in the basics and you'll finish the courses with a collection of games you can modify yourself. Also note, that you can access official courses and lessons directly from Unity Hub.
You do not seem to have made any movement changes, only the size has changed. To understand the current problem, add the input vector to transform.position. I tried to apply this change in the summary of the code below, but there is a more principled way to use Rigidbody2D, and in this case, read the link below.
[SerializeField] private float speed = 1;
private float horinzontal;
private float vertical;
private void Update()
{
vertical = Input.GetAxis("Vertical");
horinzontal = Input.GetAxis("Horizontal");
var _sign = Mathf.Sign(horinzontal);
if (_sign == 0) return;
transform.localScale = new Vector3(_sign, 1);
transform.position += new Vector3(_sign*speed*Time.deltaTime, 0);
}
more information about Rigidbody2D:
https://docs.unity3d.com/Manual/class-Rigidbody2D.html
I am a freshman design student and they've asked us to create a game on unity3D without much training on it so needless to say I don't know much except for the super basic stuff. I don't know anything about c# and I've been having an issue making a gameobject teleport. I've spent 6 hours searching for a solution online and the only conclusion I got to was that my object is probably having issues teleporting because of the way I am controlling it - something to do with the controller remembering the last position before the teleport and returning to it. I have no idea how to fix it though.
So this is what my scene looks like: I have a sphere as my character, I move it to this other object that has a collider as trigger which then teleports my sphere to a different point (black object) on the terrain. As soon as my object reaches there, it starts sliding back to the point where the teleport happened. I even tried edit > project settings > physics > auto sync transforms as many suggested that and it worked for them.
This is the code by which I control my player:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MyPlayer : MonoBehaviour
{
public float speed = 1;
public float spacing = 1;
private Vector3 pos;
// Use this for initialization
void Awake()
{
pos = transform.position;
}
// Update is called once per frame
void Update()
{
if (Input.GetKeyDown(KeyCode.W))
pos.x += spacing;
if (Input.GetKeyDown(KeyCode.S))
pos.x -= spacing;
if (Input.GetKeyDown(KeyCode.D))
pos.z -= spacing;
if (Input.GetKeyDown(KeyCode.A))
pos.z += spacing;
transform.position = Vector3.MoveTowards(transform.position, pos, speed * Time.deltaTime);
}
}
and I also have a camera that follows the sphere using this code
using UnityEngine;
using System.Collections;
public class CompleteCameraController : MonoBehaviour {
public GameObject player; //Public variable to store a reference to the player game object
private Vector3 offset; //Private variable to store the offset distance between the player and camera
// Use this for initialization
void Start ()
{
//Calculate and store the offset value by getting the distance between the player's position and camera's position.
offset = transform.position - player.transform.position;
}
// LateUpdate is called after Update each frame
void LateUpdate ()
{
// Set the position of the camera's transform to be the same as the player's, but offset by the calculated offset distance.
transform.position = player.transform.position + offset;
}
}
and I have another code on the camera that makes me be able to look around using my mouse
using UnityEngine;
using System.Collections;
public class FlyCamera : MonoBehaviour
{
/*
Writen by Windexglow 11-13-10. Use it, edit it, steal it I don't care.
Converted to C# 27-02-13 - no credit wanted.
Simple flycam I made, since I couldn't find any others made public.
Made simple to use (drag and drop, done) for regular keyboard layout
wasd : basic movement
shift : Makes camera accelerate
space : Moves camera on X and Z axis only. So camera doesn't gain any height*/
float mainSpeed = 700.0f; //regular speed
float shiftAdd = 950.0f; //multiplied by how long shift is held. Basically running
float maxShift = 2000.0f; //Maximum speed when holdin gshift
float camSens = 0.25f; //How sensitive it with mouse
private Vector3 lastMouse = new Vector3(255, 255, 255); //kind of in the middle of the screen, rather than at the top (play)
private float totalRun = 1.0f;
void Update()
{
lastMouse = Input.mousePosition - lastMouse;
lastMouse = new Vector3(-lastMouse.y * camSens, lastMouse.x * camSens, 0);
lastMouse = new Vector3(transform.eulerAngles.x + lastMouse.x, transform.eulerAngles.y + lastMouse.y, 0);
transform.eulerAngles = lastMouse;
lastMouse = Input.mousePosition;
//Mouse camera angle done.
//Keyboard commands
float f = 0.0f;
Vector3 p = GetBaseInput();
if (Input.GetKey(KeyCode.LeftShift))
{
totalRun += Time.deltaTime;
p = p * totalRun * shiftAdd;
p.x = Mathf.Clamp(p.x, -maxShift, maxShift);
p.y = Mathf.Clamp(p.y, -maxShift, maxShift);
p.z = Mathf.Clamp(p.z, -maxShift, maxShift);
}
else
{
totalRun = Mathf.Clamp(totalRun * 0.5f, 1f, 1000f);
p = p * mainSpeed;
}
p = p * Time.deltaTime;
Vector3 newPosition = transform.position;
if (Input.GetKey(KeyCode.Space))
{ //If player wants to move on X and Z axis only
transform.Translate(p);
newPosition.x = transform.position.x;
newPosition.z = transform.position.z;
transform.position = newPosition;
}
else
{
transform.Translate(p);
}
}
private Vector3 GetBaseInput()
{ //returns the basic values, if it's 0 than it's not active.
Vector3 p_Velocity = new Vector3();
if (Input.GetKey(KeyCode.W))
{
p_Velocity += new Vector3(0, 0, 1);
}
if (Input.GetKey(KeyCode.S))
{
p_Velocity += new Vector3(0, 0, -1);
}
if (Input.GetKey(KeyCode.A))
{
p_Velocity += new Vector3(-1, 0, 0);
}
if (Input.GetKey(KeyCode.D))
{
p_Velocity += new Vector3(1, 0, 0);
}
return p_Velocity;
}
}
Please let me know if there's a specific part of my code that I need to edit to resolve this or alternatively if you have a different code that won't give me this issue, that would make my life so much easier. If I need to edit something or you're sharing a code, please respond with the complete (corrected) code because otherwise I will just be even more confused.
I know this is a super long post and I am sorry but I am really desperate. It's been really hard studying online and basically having to teach myself all of this. This is for a final project so I will really appreciate any help you can throw my way. Thank you for reading and thanks for any help in advance.
EDIT: The teleport code is executing fine because I do teleport to the chosen location, I just end up sliding back to the point which I teleported from.
This is the teleporting code I am using.
using UnityEngine;
using System.Collections;
public class Teleport : MonoBehaviour
{
public GameObject ui;
public GameObject objToTP;
public Transform tpLoc;
void Start()
{
ui.SetActive(false);
}
void OnTriggerStay(Collider other)
{
ui.SetActive(true);
if ((other.gameObject.tag == "Player") && Input.GetKeyDown(KeyCode.E))
{
objToTP.transform.position = tpLoc.transform.position;
}
}
void OnTriggerExit()
{
ui.SetActive(false);
}
}
Ok, so the main reason why your character is drifting back to original position is that the pos variable in the MyPlayer script stays the same after teleporting.
Remedy for that will be changing pos variable from Teleport script after objToTP.transform.position = tpLoc.transform.position;. Something like objToTP.gameobject.GetComponent<MyPlayer>().pos = tpLoc.transform.position;
But make sure that objToTP has component MyPlayer and pos in MyPlayer is public.
Once again: it's a simple way to resolve your problem. In a real project you should create more flexible architecture, but that's a different story.
I believe that you sliding back because you moving player with transform.position = Vector3.MoveTowards in Update().
And you moving it to coordinates that was got from your input
Im making a 3d platformer In unity as my first game, and I'm trying to add some mouse rotation, but don't know what to do. the problem is it literally will not rotate.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PCM : MonoBehaviour
{
public float speed = 10.0f;
// Start is called before the first frame update
void Start()
{
Cursor.lockState = CursorLockMode.Locked;
}
// Update is called once per frame
void Update()
{
float translation = Input.GetAxis("MouseX") * speed;
float straffe = Input.GetAxis("MouseY") * speed;
translation *= Time.deltaTime;
straffe *= Time.deltaTime;
transform.Translate(straffe, 0, translation);
}
}
all player propeties
I assume, since you said "platform" that you're doing 2D. You had
transform.Translate(straffe, 0, translation);
Usually, 2D works on X- (left/right) and Y- (up/down) axes (and Z is "in/out"). Try
transform.Translate(straffe, translation, 0);
I am trying to make a game where a ball will be ricocheting off several different colliders on screen. Based on what I researched I got some code that seemed to make sense at first but does not seem to work at all. I am testing it out just by having the ball fall down onto a 2D floor with a box collider attached to it. However once it collides with the floor it just stops there and doesn't bounce back up. I tried disabling "Queries Start in Colliders" in the project settings and offsetting the origin position of the RaycastHit2D so that it would not detect the collider its attached to but that still didn't work. I don't think the RaycastHit2D is working at all because it doesn't even display anything in the console. Here is my code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class EnemyBehavior : MonoBehaviour {
Rigidbody2D rigidbody;
public Vector2 startPos;
public float speed;
public float hitOffset;
Vector3 vector = new Vector3(0, 5,0); //used to offset origin point of RaycastHit2D hit
private void OnEnable()
{
rigidbody = GetComponent<Rigidbody2D>();
this.transform.position = startPos;
}
private void Update()
{
transform.Translate(Vector2.down * speed * Time.deltaTime);
RaycastHit2D hit = Physics2D.Raycast(transform.position + vector, - transform.up, speed * Time.deltaTime + hitOffset);
Debug.DrawRay(transform.position, -transform.up, Color.red);
Ray2D ray = new Ray2D(transform.position, -transform.up);
if (hit)
{
Debug.Log(speed * Time.deltaTime + hitOffset);
Debug.Log(hit.collider.name);
Vector2 reflectDir = Vector2.Reflect(ray.direction,hit.normal);
float rotation = Mathf.Atan2(reflectDir.y, reflectDir.x) * Mathf.Rad2Deg;
transform.eulerAngles = new Vector3(0, 0, rotation);
}
}
}
Is my math bad? Any help is very appreciated, thanks.
I'm having a play with Google Cardboard. I am sitting in a cockpit and I can look around it with no problem.
Now I want to tilt my cockpit from side to side to give a more realistic feel rather than just being stationary.
So far I have this:
using UnityEngine;
using System.Collections;
public class Tilt : MonoBehaviour
{
float speed = 0.25f;
void Update()
{
Tilter ();
}
void Tilter()
{
if (transform.rotation.z < 5f) {
transform.Rotate (new Vector3 (0f, 0f, speed));
}
if (transform.rotation.z > 5f)
transform.Rotate (new Vector3 (0f, 0f, -speed));
}
}
This starts tilting the cockpit to the left as expected, but once the rotation gets bigger than the value of 5, the cockpit does not rotate the other way, it keeps rotating the same way, instead of the opposite direction.
I have not tried this code, but if I understand what you are trying to do, I would suggest to use Mathf.Sin and Time.time to continuously get values in the range of -1 to 1 and then multiply for the rotating range of your cockpit. For example:
using UnityEngine;
using System.Collections;
public class Tilt : MonoBehaviour
{
float speed = 1.0f;
float rotationAngle = 45;
void Update()
{
Tilter ();
}
void Tilter()
{
float rotationZ = rotationAngle * Mathf.Sin(Time.time * speed);
transform.Rotate (new Vector3 (0f, 0f, rotationZ ));
}
}
This example should slowly rotate your cockpit from 0 to 45, then back to 0, then to -45, then back to 0, an so on (again I have not tried it).
You can increase or decrease the value of speed to make the rotation faster or slower.