- Home /
Floating Origin and Multiplayer
Hello, I tested this script for a Floating Origin http://wiki.unity3d.com/index.php?title=Floating_Origin to prevent problem with huge Distances.
But If a player reaches the threshold I got strange behavior of the Player SpaceShips.
The enviroment moves correctly but the ship of the other player is not moved with the enviroment, it is still at the relative position to the map origin.
The same for the other player: The ship of the other player reaches the threshold, and get set back to the map origin.
(sorry for the odd english)
I have the same problem, I don't understand what your doing? your using UFPS right?
Answer by DaDonik · Jan 24, 2015 at 10:11 PM
Without knowing anything about your multiplayer code, there is not much we can tell you.
I guess the wiki solution you've posted is not really applicable in a multiplayer game, because it only considers the player and it's vicinity. In the case where the other player is not within the threshold, there will be problems.
I'm afraid there is no easy solution to this, but i'm also very interested in space games and therefore i would like to discuss it with you. If you like, you can pm me via the forum and we can talk in our native language.
Hello, I think i solved the problem (maybe), I use 2 coordinate systems: One for the "local Space" and another one for the Globalspace, wich is 1:10000 scale.
I Calculate the local position of a Player by using an localoffset variable.
Now there a two problems to solve:
If a player $$anonymous$$oves his/hers local object, the object travels only half the distance it should travel.! [bug?][1] [1]: /storage/temp/39519-bug.jpg
the other Problem is, if I accerlerate to Z+ it works only if the Z+ Velocity is bigger as 0.3 m/s (0.3m/s are calculated by the GlobalRef script)
The player controlls the local Object via Forces in FixedUpdate(). The change velocity is added to the "GlobalSpace" reference Gameobject.
The whole script is a bit to long to post here. Therefore the function that calculates the local Offset (i think there is something wrong, because of the tiny velocity problem and the strange behavior in $$anonymous$$ultiplayer).
void LocalRef()
{
if(localRef != null)
{
localDeltaVelocity = localRef.rigidbody.velocity - localVelocity;
localVelocity = localRef.rigidbody.velocity;
transform.rigidbody.velocity += localDeltaVelocity/Constants.spaceScale;
if(isActive)
{
foreach(SpaceObjectRef otherRef in localSpaceData.localRefs)
{
if(!otherRef.isActive && otherRef.localRef != null)
{
otherRef.localOffset = Convert.Vector3dToVector3((otherRef.realPosition - realPosition)*Constants.spaceScale);
otherRef.localRef.rigidbody.position = otherRef.localOffset + originOffset;
}
}
}
}
transform.rigidbody.AddForce(Vector3.zero);
}
I will have a more detailed look at your code tomorrow. From a first glimpse i assume that the value calculated by
localDeltaVelocity/Constants.spaceScale
might be too small, due to floating point imprecision. This might cause the problem that your velocity has to be bigger than 0.3 m/s.
On a sidenote...don't use foreach if you can work with a simple for loop. Foreach produces garbage, for doesn't.
Answer by sebeisdrache · Jan 25, 2015 at 09:46 PM
here is my complete Script. I have a Utility and a Constans Class, i think the names should be inform about the ussage (Like gravity constant and set main camera). Vector3d is https://github.com/kohlditz/vector3d
using UnityEngine;
using System.Collections;
public class SpaceObjectRef : MonoBehaviour {
public Vector3d realPosition;
public Vector3d realVelocity;
GameObject localRef;
public GameObject localRefPrefab;
public bool isActive;
Vector3 localDeltaVelocity;
Vector3 localVelocity;
public Vector3 localOffset;
Vector3 deltaPosition;
GameObject space;
GameObject localSpace;
LocalSpace localSpaceData;
GameObject skyBoxCam;
GameObject playerCam;
public double realPositionX;
public double realPositionY;
public double realPositionZ;
public double realVelocityX;
public double realVelocityY;
public double realVelocityZ;
public double distanceFormPlanet;
public double distanceFormSurface;
public double gravityForce;
public Vector3 directionToPlanet;
public double speed;
public Planet planet;
Vector3 position;
public Quaternion rotation;
public Vector3 angularVelocity;
Vector3 velocity;
Vector3 originPos;
Vector3 originOffset;
private float lastSynchronizationTime = 0f;
private float syncDelay = 0f;
private float syncTime = 0f;
private Vector3 syncStartPosition = Vector3.zero;
private Vector3 syncEndPosition = Vector3.zero;
private Quaternion syncStartRotation = Quaternion.identity;
private Quaternion syncEndRotation = Quaternion.identity;
private bool gotSync = false;
void Awake ()
{
GetValues();
ApplyValues();
localSpace = GameObject.Find("LocalSpace");
skyBoxCam = GameObject.FindGameObjectWithTag("SkyBoxCam");
space = GameObject.Find("Space");
localSpaceData = localSpace.GetComponent<LocalSpace>();
if(networkView.isMine)
{
isActive = true;
}
if(transform.parent == null)
{
transform.parent = space.transform;
}
}
void Start () {
if(isActive && localRefPrefab != null)
{
localRef = Instantiate(localRefPrefab, Vector3.zero, rotation) as GameObject;
localRef.transform.parent = localSpace.transform;
PlayerRef playerRef = localRef.GetComponent<PlayerRef> ();
if(playerRef != null)
{
playerRef.owner = true;
Utility.SetMainCam(playerRef.cam);
}
localSpaceData.localRefs.Add(this);
}
}
void FixedUpdate()
{
if(networkView != null && !networkView.isMine)
{
SyncedMovement();
}
Gravitiy();
LocalRef();
UpdateValues();
}
void Update()
{
}
void LateUpdate () {
skyBoxCam.transform.position = transform.position;
FloatingOrigin();
}
void FloatingOrigin()
{
if(isActive && localRef != null)
{
originPos = localRef.transform.position;
if(originPos.magnitude > Constants.floatingOriginThreshold)
{
originOffset -= originPos;
foreach(Transform child in localSpace.transform)
{
child.position -= originPos;
}
}
}
}
void OnDestroy()
{
if(localRef != null)
{
Destroy(localRef);
}
}
void OnTriggerEnter(Collider other)
{
if(isActive)
{
SpaceObjectRef spaceObjectRef = other.GetComponent<SpaceObjectRef>();
localOffset = Convert.Vector3dToVector3((spaceObjectRef.realPosition - realPosition)*Constants.spaceScale);
if(spaceObjectRef.localRefPrefab != null && spaceObjectRef.localRef == null)
{
spaceObjectRef.localRef = Instantiate(spaceObjectRef.localRefPrefab, localOffset, spaceObjectRef.rotation) as GameObject;
spaceObjectRef.localRef.rigidbody.angularVelocity = spaceObjectRef.angularVelocity;
spaceObjectRef.localRef.transform.parent = localSpace.transform;
localSpaceData.localRefs.Add(spaceObjectRef);
}
}
}
void OnTriggerExit(Collider other) {
if(isActive)
{
SpaceObjectRef spaceObjectRef = other.GetComponent<SpaceObjectRef>();
if(spaceObjectRef.localRef != null)
{
Destroy(spaceObjectRef.localRef);
localSpaceData.localRefs.Remove(spaceObjectRef);
}
}
}
void LocalRef()
{
if(localRef != null)
{
localDeltaVelocity = localRef.rigidbody.velocity - localVelocity;
localVelocity = localRef.rigidbody.velocity;
transform.rigidbody.velocity += localDeltaVelocity/Constants.spaceScale;
if(isActive)
{
foreach(SpaceObjectRef otherRef in localSpaceData.localRefs)
{
if(!otherRef.isActive && otherRef.localRef != null)
{
otherRef.localOffset = Convert.Vector3dToVector3((otherRef.realPosition - realPosition)*Constants.spaceScale);
otherRef.localRef.rigidbody.position = otherRef.localOffset + originOffset;
}
}
}
}
transform.rigidbody.AddForce(Vector3.zero);
}
void GetValues()
{
if(realPositionX != 0 || realPositionY != 0 || realPositionZ != 0)
{
realPosition.x = realPositionX;
realPosition.y = realPositionY;
realPosition.z = realPositionZ;
}
else
{
realPosition = Convert.Vector3ToVector3d(transform.rigidbody.position);
}
//rotation = transform.rigidbody.rotation;
realVelocity.x = realVelocityX;
realVelocity.y = realVelocityY;
realVelocity.z = realVelocityZ;
}
void ApplyValues()
{
position = Convert.Vector3dToVector3(realPosition);
velocity = Convert.Vector3dToVector3(realVelocity);
transform.rigidbody.position = position;
//transform.rigidbody.rotation = rotation;
transform.rigidbody.velocity = velocity;
}
void UpdateValues()
{
realPosition = Convert.Vector3ToVector3d(transform.rigidbody.position);
realVelocity = Convert.Vector3ToVector3d(transform.rigidbody.velocity);
if(localRef != null)
{
rotation = localRef.rigidbody.rotation;
angularVelocity = localRef.rigidbody.angularVelocity;
}
position = transform.rigidbody.position;
velocity = transform.rigidbody.velocity;
realPositionX = realPosition.x;
realPositionY = realPosition.y;
realPositionZ = realPosition.z;
realVelocityX = realVelocity.x;
realVelocityY = realVelocity.y;
realVelocityZ = realVelocity.z;
speed = rigidbody.velocity.magnitude * Constants.spaceScale;
}
void Gravitiy()
{
if(planet != null)
{
distanceFormPlanet = Vector3d.Distance(realPosition, planet.realPosition) * Constants.spaceScale;
distanceFormSurface = distanceFormPlanet - planet.radius;
gravityForce = Constants.gravityConstantD * ( planet.mass / ( distanceFormPlanet * distanceFormPlanet ) );
Vector3d dir = planet.realPosition - realPosition;
dir.Normalize();
directionToPlanet = Convert.Vector3dToVector3(dir);
rigidbody.AddForce( directionToPlanet * (float)(gravityForce/Constants.spaceScale), ForceMode.Acceleration);
}
}
private void SyncedMovement()
{
if(gotSync == true && localRef != null)
{
syncTime += Time.deltaTime;
rigidbody.position = Vector3.Lerp(syncStartPosition, syncEndPosition, syncTime / syncDelay);
localRef.rigidbody.rotation = Quaternion.Slerp(syncStartRotation, syncEndRotation, syncTime / syncDelay);
}
}
void OnSerializeNetworkView(BitStream stream, NetworkMessageInfo info)
{
Vector3 syncPosition = Vector3.zero;
Quaternion syncRotation = Quaternion.identity;
Vector3 syncVelocity = Vector3.zero;
if (stream.isWriting)
{
syncPosition = rigidbody.position;
stream.Serialize(ref syncPosition);
if(localRef != null)
{
syncRotation = localRef.rigidbody.rotation;
stream.Serialize(ref syncRotation);
}
syncVelocity = rigidbody.velocity;
stream.Serialize(ref syncVelocity);
}
else
{
stream.Serialize(ref syncPosition);
stream.Serialize(ref syncRotation);
stream.Serialize(ref syncVelocity);
rigidbody.velocity = syncVelocity;
syncTime = 0f;
syncDelay = Time.time - lastSynchronizationTime;
lastSynchronizationTime = Time.time;
syncEndPosition = syncPosition + syncVelocity * syncDelay;
syncStartPosition = rigidbody.position;
if(localRef != null)
{
syncEndRotation = syncRotation;
syncStartRotation = localRef.rigidbody.rotation;
}
gotSync = true;
}
}
}
I have fixed the Problem with the worng Player Position:
In the update() function I placed: if(isActive) { localRef.transform.positon = Vector3.zero; }
It works in $$anonymous$$ulti and single player and objects can collide with each other. Later I will fixing the Position resolution by using real Orbital mechanics, but i need a bit of knowledge ot it to do it.
Did you ever fix this? I was testing your code and I get LocalSpace error thing.
Your answer
Follow this Question
Related Questions
Unity networking tutorial? 6 Answers
Shooting in multiplayer? 0 Answers
Unity3d floating limits? 3 Answers
Floating origin and scaled, layered cameras - where to put player object? 0 Answers
Glitches issues (huge world) 20k x 20k 3 Answers