public static RigidbodyHandle GetNewRigidbody() { Span <RigidbodyState> span = editState.Span; for (int i = 0; i < span.Length; i++) { if (!span[i].IsAssigned) { span[i] = new RigidbodyState(); span[i].IsAssigned = true; span[i].transform = new Transform(Vector3.Zero); span[i].mass = 1; span[i].inertia = Vector3.One; RigidbodyHandle handle = new RigidbodyHandle((uint)i); handles.Add(handle); return(handle); } } editState.Grow(); oldState.Grow(); interpolatedState.Grow(); newState.Grow(); return(GetNewRigidbody()); }
// Undo objects to previous state private void Undo() { if (undoCount <= 0) { return; } undoCount--; stepIndex--; if (stepIndex < 0) { stepIndex = STORAGE_SIZE - 1; } for (int i = 0; i < rigidBodies.Length; i++) { NewRigidBody rigidBody = rigidBodies [i]; RigidbodyState state = storage [stepIndex].states [i]; rigidBody.acceleration = state.acceleration; rigidBody.velocity = state.velocity; rigidBody.position = state.position; rigidBody.angularVelocity = state.angularVelocity; rigidBody.orientation = state.orientation; rigidBody.transform.rotation = Quaternion.Euler(state.orientation); rigidBody.transform.position = rigidBody.position; } }
public void TestRbsTransformPerformance(int warmUpCount, int testCount) { var stopwatch = Stopwatch.StartNew(); for (int i = 0; i < warmUpCount; i++) { rbs = Transform(TransformDirection.LocalToServer, ref rbs, true); } double warmUpTime = stopwatch.Elapsed.TotalSeconds; stopwatch.Reset(); UnityEngine.Debug.LogFormat("[Warm-Up] Performed: {0} transformations in {1}s. ({2}/s)", warmUpCount, warmUpTime, (warmUpCount / warmUpTime)); for (int i = 0; i < testCount; i++) { rbs = Transform(TransformDirection.LocalToServer, ref rbs, true); } stopwatch.Stop(); double testTime = stopwatch.Elapsed.TotalSeconds; UnityEngine.Debug.LogFormat("[Test] Performed: {0} transformations in {1}s. ({2}/s)", testCount, testTime, (testCount / testTime)); }
public static void ApplyTo(this RigidbodyState state, Rigidbody body) { body.position = state.Position; body.velocity = state.Velocity; body.rotation = state.Rotation; body.angularVelocity = state.AngularVelocity; }
public EulerBody(RigidbodyConfig config, RigidbodyState state) { _config = config; _state = state; Reset(); }
// Store current state of objects private void StoreState() { RigidbodyState[] objectStates = new RigidbodyState[rigidBodies.Length]; for (int i = 0; i < rigidBodies.Length; i++) { NewRigidBody rigidBody = rigidBodies[i]; RigidbodyState state = new RigidbodyState(); state.acceleration = rigidBody.acceleration; state.velocity = rigidBody.velocity; state.position = rigidBody.position; state.angularVelocity = rigidBody.angularVelocity; state.orientation = rigidBody.transform.rotation.eulerAngles; objectStates[i] = state; } storage[stepIndex].states = objectStates; undoCount++; if (undoCount >= STORAGE_SIZE) { undoCount = STORAGE_SIZE - 1; } stepIndex++; if (stepIndex >= STORAGE_SIZE) { stepIndex = 0; } }
public void ReplaceRigidbodyState(RigidbodyState newState) { var index = GameComponentsLookup.RigidbodyState; var component = CreateComponent <RigidbodyStateComponent>(index); component.state = newState; ReplaceComponent(index, component); }
private void OnReceiveState(PlayerMessage.StateUpdate message, MessageMetadata metadata) { _lastServerState = message.State; _lastReceivedStateTimestamp = _fixedClock.CurrentTime; _lastReceivedStateRTT = RamjetClient.RoundtripTime; _serverHistory.Enqueue(message.State); }
private void UpdateStatistics() { /* Note: Calculating position derivatives in Update caused framerate dependent effects to happen * (which is what caused the OrbitCamera to lag behind at low fps) */ /* Update altitudes. */ _altitudeSeaLevel = _body.transform.position.y; RaycastHit hit; if (Physics.Raycast(_body.transform.position, Vector3.down, out hit, Mathf.Infinity, _layerMask)) { _altitudeGround = hit.distance; //Debug.Log("I hit this thang: " + hit.collider.name); } /* Find position derivatives. */ Vector3 velocity = _body.velocity; Vector3 oldVelocity = RigidbodyState.Lerp(_historyBuffer, Time.fixedTime - 0.25f).Velocity; _acceleration = (velocity - oldVelocity) / 0.25f; Vector3 localAngularVelocity = _body.transform.InverseTransformDirection(_body.angularVelocity); _localAngularAcceleration = localAngularVelocity - _localAngularVelocity; _localAngularVelocity = localAngularVelocity; /* Determine relative wind vector. */ Vector3 windVelocity = _wind.GetWindVelocity(_body.transform.position); _relativeVelocity = _body.velocity - windVelocity; _trueAirspeed = _relativeVelocity.magnitude; /* Determine angle of attack. */ Vector3 v1 = _body.transform.TransformDirection(_rollAxis); Vector3 v2 = _relativeVelocity.normalized; Vector3 n = _body.transform.TransformDirection(_pitchAxis); _angleOfAttack = MathUtils.AngleAroundAxis(v1, v2, n); /* Determine glide ratio. */ float horizontalDistance = Mathf.Sqrt(Mathf.Pow(_body.velocity.x, 2f) + Mathf.Pow(_body.velocity.z, 2f)); float verticalDistance = -_body.velocity.y; _glideRatio = horizontalDistance / verticalDistance; /* Determine Angle to ground for local axes. */ Vector3 rollAxisCenter = _body.transform.forward; _angleToGroundRoll = MathUtils.AngleAroundAxis(Vector3.down, rollAxisCenter, _body.transform.TransformDirection(_rollAxis)); Vector3 forward = _body.transform.TransformDirection(_rollAxis); Vector3 projectedForward = new Vector3(forward.x, 0f, forward.z); _angleToGroundPitch = MathUtils.AngleAroundAxis(projectedForward, forward, _body.transform.TransformDirection(_pitchAxis)); _historyBuffer.Enqueue(RigidbodyState.ToImmutable(_body, Time.fixedTime)); }
public static void Serialize(this RigidbodyState body, NetBuffer writer) { writer.Write(body.Position); writer.Write(body.Velocity); writer.Write(body.Acceleration); writer.WriteRotation(body.Rotation); writer.Write(body.AngularVelocity); writer.Write(body.AngularAcceleration); }
private IEnumerator OnDeserialize() { while (true) { _oldState = _newState; //_newState = RigidbodyExtensions.ToImmutable(_target.Rigidbody, _target.Acceleration, Vector3.zero, Time.fixedDeltaTime); yield return(new WaitForSeconds(2f)); } }
private void ClearBuffers() { for (int i = 0; i < _predictionBuffer.Length; i++) { _predictionBuffer[i] = new RigidbodyState(); } _historyBuffer.Clear(); _historyBuffer.Enqueue(RigidbodyState.ToImmutable(_body, Time.fixedTime)); }
private void Correct(IClock fixedClock) { if (_serverHistory.Count < 1) { Debug.Log("no server history available"); return; } /* Extrapolate last received server state to catch up to client time */ /* Todo: Save massive amounts of calculation by only simulating 1 correction tick per actual physics frame, you dummy * New server state? Do offline sim for however many steps it requires to catch up to local client time instantly. * THEN, then you only have to simulate one tick for each real-time physics tick in order to keep up. Until the new server state arrives. * * So in this method we only tick once * In the receive state handler we tick multiple times to catch up to local client time */ var latency = _lastReceivedStateRTT / 2d; var timeSinceLastReceivedState = fixedClock.CurrentTime - _lastReceivedStateTimestamp; var timeSinceServerState = latency + timeSinceLastReceivedState; var startTime = _lastReceivedStateTimestamp - latency; Debug.Assert(timeSinceServerState > 0.0, "timeSinceServerState > 0: " + timeSinceServerState); _eulerBody.State = _lastServerState; PlayerSimulation.SimulateOffline(_simulation.Config, _eulerBody, t => _inputHistory.Lerp(t), startTime, timeSinceServerState, fixedClock.DeltaTime); _correctedState = _eulerBody.State; /* Calculate error between corrected server state and current client state */ var currentClientState = _simulation.UnityBody.State; const float maxPosError = 2f; const float maxRotError = 45f; _posError = Vector3.Distance(currentClientState.Position, _correctedState.Position) / maxPosError; _rotError = Quaternion.Angle(currentClientState.Rotation, _correctedState.Rotation) / maxRotError; /* Apply corrected state over time, with use of error metrics */ _posErrorSmooth = Mathf.Lerp(_posErrorSmooth, 0.5f + _posError, 1f / _errorSmoothing * fixedClock.DeltaTime); _rotErrorSmooth = Mathf.Lerp(_rotErrorSmooth, 0.5f + _rotError, 1f / _errorSmoothing * fixedClock.DeltaTime); var interpolatedState = RigidbodyExtensions.Lerp( currentClientState, _correctedState, _posErrorSmooth * fixedClock.DeltaTime * _errorCorrectionSpeed, _rotErrorSmooth * fixedClock.DeltaTime * _errorCorrectionSpeed); if (_applyCorrection) { interpolatedState.ApplyTo(_simulation.UnityBody.Rigidbody); } }
public void SetUp() { World = new GameObject().transform; rbs = new RigidbodyState { position = new Vector3(10, -15, 25), rotation = new Quaternion(0.7f, 1, 0.3f, 0.2f), velocity = new Vector3(4, 9, -10), angularVelocity = new Vector3(9, 2, 4) }; }
private void SetRigidbodyStates(ServerStateMessage stateMessage) { // Override the client rigidbodies with the server rigidbody parameters for (int i = 0; i < stateMessage.rigidbody_states.Length; i++) { RigidbodyState serverRigidbodyState = stateMessage.rigidbody_states[i]; Transform clientRigidbody = m_syncObjects[i]; clientRigidbody.position = serverRigidbodyState.position; clientRigidbody.rotation = serverRigidbodyState.rotation; } }
public static RigidbodyState Lerp(RigidbodyState a, RigidbodyState b, float positionLerp, float rotationLerp) { return(new RigidbodyState { Position = Vector3.Lerp(a.Position, b.Position, positionLerp), Velocity = Vector3.Lerp(a.Velocity, b.Velocity, positionLerp), Acceleration = Vector3.Lerp(a.Acceleration, b.Acceleration, positionLerp), Rotation = Quaternion.Slerp(a.Rotation, b.Rotation, rotationLerp), AngularVelocity = Vector3.Lerp(a.AngularVelocity, b.AngularVelocity, rotationLerp), AngularAcceleration = Vector3.Lerp(a.AngularAcceleration, b.AngularAcceleration, rotationLerp) }); }
private void SetRigidbodyStates(ServerStateMessage stateMessage) { // Override the client rigidbodies with the server rigidbody parameters for (int i = 0; i < stateMessage.rigidbody_states.Length; i++) { RigidbodyState serverRigidbodyState = stateMessage.rigidbody_states[i]; Rigidbody clientRigidbody = m_syncedRigidbodies[i]; clientRigidbody.position = serverRigidbodyState.position; clientRigidbody.rotation = serverRigidbodyState.rotation; clientRigidbody.velocity = serverRigidbodyState.velocity; clientRigidbody.angularVelocity = serverRigidbodyState.angular_velocity; } }
void ShootBulletFrom(GameEntity weapon) { var transformState = weapon.transform.state; var forward = new Vector3D(transformState.rotation * Vector3.forward); transformState.position += forward; var velocity = forward * weapon.projectileSpeed.value; var rigidbodyState = new RigidbodyState(velocity); var bulletDamage = weapon.damage.value; game.CreateBullet(transformState, rigidbodyState, bulletDamage); }
private RigidbodyState Transform(TransformDirection direction, ref RigidbodyState fromRbs, bool transformVelocity) { var toRbs = new RigidbodyState { position = Transform(direction, fromRbs.position), rotation = Transform(direction, fromRbs.rotation) }; if (transformVelocity) { toRbs.velocity = TransformVector(direction, fromRbs.velocity); toRbs.angularVelocity = TransformVector(direction, fromRbs.angularVelocity); } return(toRbs); }
public void saveState() { Rigidbody[] bodies = GameObject.FindObjectsOfType <Rigidbody>(); bodyStates.Clear(); foreach (Rigidbody b in bodies) { RigidbodyState state = new RigidbodyState(); state.b = b; state.pos = b.position; state.vel = b.velocity; state.aVel = b.angularVelocity; state.q = b.rotation; state.active = b.gameObject.activeSelf; bodyStates.Add(state); } }
public List <RigidbodyState> SaveState() { Rigidbody[] bodies = GetComponentsInChildren <Rigidbody>(true); bodyStates = new List <RigidbodyState>(); foreach (Rigidbody b in bodies) { RigidbodyState state = new RigidbodyState(); state.b = b; state.pos = b.position; state.vel = b.velocity; state.aVel = b.angularVelocity; state.q = b.rotation; state.active = b.gameObject.activeSelf; state.isSleeping = b.IsSleeping(); bodyStates.Add(state); } return(bodyStates); }
public static GameEntity CreatePlayer(this GameContext game, int playerId, TransformState transformState, RigidbodyState rigidbodyState ) { var e = game.CreateEntity(); e.AddTransform(transformState); e.AddRigidbodyState(rigidbodyState); e.isGameObjectDriven = true; e.AddPlayer(playerId); e.ReplaceNetworkUpdatePriority(10000, 0); e.AddPrefab("Player"); return(e); }
public static GameEntity CreateBullet(this GameContext game, TransformState transformState, RigidbodyState rigidbodyState, float damage ) { var e = game.CreateEntity(); e.AddTransform(transformState); e.AddRigidbodyState(rigidbodyState); e.isGameObjectDriven = true; e.isBullet = true; e.AddDamage(damage); e.AddPrefab("Bullet"); e.ReplaceNetworkUpdatePriority(100, 10000); return(e); }
private bool DoesAnyObjectNeedCorrection(ServerStateMessage serverStateMessage) { /// Return true if any rigidbody is deviating from a server rigidbody position uint bufferIndex = serverStateMessage.tick % BUFFER_SIZE; for (int i = 0; i < serverStateMessage.rigidbody_states.Length; i++) { RigidbodyState serverState = serverStateMessage.rigidbody_states[i]; RigidbodyStateNoVel clientState = m_stateBuffer[bufferIndex].rigidbody_states[i]; Vector3 position_error = serverState.position - clientState.position; float rotation_error = 1.0f - Quaternion.Dot(serverState.rotation, clientState.rotation); if (position_error.sqrMagnitude > PositionErrorThreshold * PositionErrorThreshold || rotation_error > RotationErrorThreshold * RotationErrorThreshold) { return(true); } } return(false); }
// Reset objects to the initial state public void Reset() { for (int i = 0; i < rigidBodies.Length; i++) { NewRigidBody rigidBody = rigidBodies [i]; RigidbodyState state = _initialStates[i]; rigidBody.acceleration = state.acceleration; rigidBody.velocity = state.velocity; rigidBody.position = state.position; rigidBody.angularVelocity = state.angularVelocity; rigidBody.orientation = state.orientation; rigidBody.transform.rotation = Quaternion.Euler(state.orientation); rigidBody.transform.position = rigidBody.position; rigidBody.transform.GetComponent <MeshRenderer> ().material = rigidBody._originalMaterial; } firstPlay = false; _initialConditions.SetActive(true); pause = true; }
void Start() { rigidBodies = GameObject.FindObjectsOfType <NewRigidBody> (); // Initialise undoCount = 0; stepIndex = 0; _initialStates = new RigidbodyState[rigidBodies.Length]; RigidbodyState[] objectStates = new RigidbodyState[rigidBodies.Length]; // Initial state of all objects int i = 0; foreach (NewRigidBody rigidBody in rigidBodies) { RigidbodyState state = new RigidbodyState(); state.acceleration = rigidBody.acceleration; state.velocity = rigidBody.velocity; state.position = rigidBody.transform.position; state.orientation = rigidBody.transform.rotation.eulerAngles; state.angularVelocity = rigidBody.angularVelocity; objectStates[i] = state; _initialStates [i] = state; i++; } // Storage initialisation storage = new Storage[STORAGE_SIZE]; storage[stepIndex].states = objectStates; undoCount++; stepIndex++; // Start StartCoroutine(Intergrate()); }
public void Deserialize(NetBuffer reader) { State = RigidbodyExtensions.Deserialize(reader); }
public void SaveState() { state = new RigidbodyState(Rigidbody); }
private void UpdatePrediction() { // The used acceleration stays constant over the whole simulation. We massage it quite a bit to get a stable trajectory Vector3 velocity = Vector3.Lerp(_prevVelocity, WorldVelocity, 1f * Time.deltaTime); Vector3 acceleration = Vector3.Lerp(_prevAcceleration, Acceleration * 1.33f, 0.5f * Time.deltaTime); _prevVelocity = velocity; _prevAcceleration = acceleration; acceleration = acceleration + Vector3.down; // Add a bit of gravity // Setup state for the raycast simulation float stepTime = _trajectorySimTime / _trajectoryRaycastSteps; Vector3 position = transform.position; _collisionPredicted = false; _normalizedCollisionIndex = -1f; // If collision, contains distance along line where 0.0 is start, and 1.0 is end of line. // Todo: decrease path resolution as distance from player increases to save performance // Check for collision along trajectory for (int i = 0; i < _trajectoryRaycastSteps && !_collisionPredicted; i++) { // Integrate velocity velocity += acceleration * stepTime; Vector3 deltaPos = velocity * stepTime; float deltaDistance = deltaPos.magnitude; // Check for collision along this segment RaycastHit hitInfo; if (Physics.SphereCast(position, 1f, deltaPos, out hitInfo, deltaDistance, _layerMask)) { _collisionPoint = hitInfo.point; _collisionNormal = hitInfo.normal; _normalizedCollisionIndex = (i + ((hitInfo.point - position).magnitude / deltaDistance)) / (float)_trajectoryRaycastSteps; _collisionPredicted = true; } // Integrate position position += deltaPos; } // Setup state for the visual simulation stepTime = _trajectorySimTime / _trajectorySegments; position = transform.position; velocity = _prevVelocity; for (int i = 0; i < _trajectorySegments; i++) { var state = new RigidbodyState(); state.Position = position; state.Velocity = velocity; _predictionBuffer[i] = state; // Integrate velocity velocity += acceleration * stepTime; Vector3 deltaPos = velocity * stepTime; // Integrate position position += deltaPos; } }
private MWB_DummyObjectList ForkDummyObjects(MWB_DummyObjectList dummyObjectList, bool isInitializedAsAble, int worldIndex = 0) { //Debug.Log("Forking"); GameObject parent = new GameObject("collide-forked dummy parent"); // this will also instantiate // !!! IMPORTANT : set the transform data of dummys' parent to the same as original objects' parent.transform.parent = dummyMasterParent.transform; // parent, which is the MWB_SYSTEM parent.transform.localPosition = transform.localPosition; parent.transform.localRotation = transform.localRotation; parent.transform.localScale = transform.localScale; // add parent to dummyParent list for clean up ! dummyParentList.Add(parent); MWB_DummyObjectList forkedDummyObjectList = new MWB_DummyObjectList(); foreach (MWB_DummyObject mwbDummyObject in dummyObjectList.MWB_DummyObjects) { GameObject forkedObject = Instantiate(mwbDummyObject.gameObject, parent.transform); // Set layer forkedObject.layer = MWBWaitingLayer; forkedObject.SetActive(isInitializedAsAble); // initilize as kinematic forkedObject.GetComponent <Rigidbody>().isKinematic = true; forkedObject.gameObject.GetComponent <Renderer>().enabled = false; // Destroy(forkedObject.GetComponent <MWB_Object>()); MWB_DummyObject forkedDummy = forkedObject.GetComponent <MWB_DummyObject>(); forkedDummy.Manager = this; // record object source forkedDummy.objectSource = mwbDummyObject.objectSource; // record fork source ( initial object has null ) forkedDummy.forkedSource = mwbDummyObject; // record corresponding dummy list forkedDummy.correspondingDummyList = forkedDummyObjectList; // record previous transform data segment (initial dummy object has null) TransformDataSegment parentSegment = mwbDummyObject.transformDataSegment; forkedDummy.transformDataSegment.previousSegment = parentSegment; mwbDummyObject.transformDataSegment = new TransformDataSegment(parentSegment); // use main path to generate two sub MWB_Path parentPath = mwbDummyObject.dummyMainPath; //mwbDummyObject.RecordPosition(); // !!! Record position to avoid broken line segment mwbDummyObject.SetSubPath(parentPath); //mwbDummyObject.RecordPosition(); // !!! Record position to avoid broken line segment forkedDummy.SetSubPath(parentPath); // assign reference of dummy to path mwbDummyObject.dummyMainPath.SourceDummyObject = mwbDummyObject; forkedDummy.dummyMainPath.SourceDummyObject = forkedDummy; // // set pathIndex //forkedDummy.pathIndex = mwbDummyObject.pathIndex; // Vector3 additionalImpulse; if (m_collidingDummyObjects.ContainsKey(mwbDummyObject)) { // TODO : add a logical additional pulse, rather than just random a force Collision collision = m_collidingDummyObjects[mwbDummyObject]; //additionalImpulse = Vector3.Cross(collision.impulse, Vector3.up) * collision.impulse.magnitude * 5f; //additionalImpulse = new Vector3(UnityEngine.Random.Range(-100, 100), 0, UnityEngine.Random.Range(-100, 100)); Vector3 origin = Vector3.zero; int counter = 0; foreach (var contactPoint in collision.contacts) { origin += contactPoint.point; counter++; } origin /= counter; List <Vector3> perturbation = SinDistributionUtility.CalculatePerturbation(origin, collision.impulse); if (perturbation.Count > worldIndex) { additionalImpulse = perturbation[worldIndex]; } else { additionalImpulse = perturbation[perturbation.Count - 1]; } } else { additionalImpulse = Vector3.zero; } // // maintain rigidbody info , otherwise it'll only copy variables info but not state info RigidbodyState rigidbodyState = new RigidbodyState(mwbDummyObject.GetComponent <Rigidbody>(), additionalImpulse); forkedDummy.rigidbodyState = rigidbodyState; forkedDummyObjectList.AddToDummyObjectList(forkedDummy); // } return(forkedDummyObjectList); }