Example #1
0
        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;
        }
    }
Example #3
0
        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;
 }
Example #5
0
    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);
    }
Example #8
0
    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);
 }
Example #11
0
    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));
    }
Example #13
0
    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);
        }
    }
Example #14
0
        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);
    }
Example #19
0
        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);
        }
Example #20
0
 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);
     }
 }
Example #21
0
 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);
 }
Example #22
0
    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);
    }
Example #23
0
    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());
    }
Example #27
0
 public void Deserialize(NetBuffer reader)
 {
     State = RigidbodyExtensions.Deserialize(reader);
 }
Example #28
0
 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);
    }