示例#1
0
        private void AddForce(OMV.Vector3 force, bool pushforce, bool inTaintTime)
        {
            if (force.IsFinite())
            {
                float magnitude = force.Length();
                if (magnitude > BSParam.MaxAddForceMagnitude)
                {
                    // Force has a limit
                    force = force / magnitude * BSParam.MaxAddForceMagnitude;
                }

                OMV.Vector3 addForce = force;
                // DetailLog("{0},BSCharacter.addForce,call,force={1}", LocalID, addForce);

                PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.AddForce", delegate()
                {
                    // Bullet adds this central force to the total force for this tick
                    // DetailLog("{0},BSCharacter.addForce,taint,force={1}", LocalID, addForce);
                    if (PhysBody.HasPhysicalBody)
                    {
                        PhysicsScene.PE.ApplyCentralForce(PhysBody, addForce);
                    }
                });
            }
            else
            {
                m_log.WarnFormat("{0}: Got a NaN force applied to a character. LocalID={1}", LogHeader, LocalID);
                return;
            }
        }
示例#2
0
        // I am the root of a linkset and a new child is being added
        // Called while LinkActivity is locked.
        private void AddChildToLinkset(BSPhysObject child)
        {
            if (!HasChild(child))
            {
                m_children.Add(child);

                BSPhysObject rootx      = LinksetRoot; // capture the root and body as of now
                BulletBody   rootBodyx  = LinksetRoot.BSBody;
                BSPhysObject childx     = child;
                BulletBody   childBodyx = child.BSBody;

                DetailLog("{0},AddChildToLinkset,call,rID={1},rBody={2},cID={3},cBody={4}",
                          rootx.LocalID,
                          rootx.LocalID, rootBodyx.ptr.ToString("X"),
                          childx.LocalID, childBodyx.ptr.ToString("X"));

                PhysicsScene.TaintedObject("AddChildToLinkset", delegate()
                {
                    DetailLog("{0},AddChildToLinkset,taint,child={1}", LinksetRoot.LocalID, child.LocalID);
                    // build the physical binding between me and the child
                    m_taintChildren.Add(childx);
                    PhysicallyLinkAChildToRoot(rootx, rootBodyx, childx, childBodyx);
                });
            }
            return;
        }
示例#3
0
        // The simulator wants to set a new heightmap for the terrain.
        public void SetTerrain(float[] heightMap)
        {
            float[] localHeightMap = heightMap;
            PhysicsScene.TaintedObject("TerrainManager.SetTerrain", delegate()
            {
                if (m_worldOffset != Vector3.Zero && MegaRegionParentPhysicsScene != null)
                {
                    // If a child of a mega-region, we shouldn't have any terrain allocated for us
                    ReleaseGroundPlaneAndTerrain();
                    // If doing the mega-prim stuff and we are the child of the zero region,
                    //    the terrain is added to our parent
                    if (MegaRegionParentPhysicsScene is BSScene)
                    {
                        DetailLog("{0},SetTerrain.ToParent,offset={1},worldMax={2}",
                                  BSScene.DetailLogZero, m_worldOffset, m_worldMax);
                        ((BSScene)MegaRegionParentPhysicsScene).TerrainManager.UpdateOrCreateTerrain(BSScene.CHILDTERRAIN_ID,
                                                                                                     localHeightMap, m_worldOffset, m_worldOffset + DefaultRegionSize, true);
                    }
                }
                else
                {
                    // If not doing the mega-prim thing, just change the terrain
                    DetailLog("{0},SetTerrain.Existing", BSScene.DetailLogZero);

                    UpdateOrCreateTerrain(BSScene.TERRAIN_ID, localHeightMap,
                                          m_worldOffset, m_worldOffset + DefaultRegionSize, true);
                }
            });
        }
示例#4
0
        // I am the root of a linkset and one of my children is being removed.
        // Safe to call even if the child is not really in my linkset.
        private void RemoveChildFromLinkset(BSPhysObject child)
        {
            if (m_children.Remove(child))
            {
                BSPhysObject rootx      = LinksetRoot; // capture the root and body as of now
                BulletBody   rootBodyx  = LinksetRoot.BSBody;
                BSPhysObject childx     = child;
                BulletBody   childBodyx = child.BSBody;

                DetailLog("{0},RemoveChildFromLinkset,call,rID={1},rBody={2},cID={3},cBody={4}",
                          childx.LocalID,
                          rootx.LocalID, rootBodyx.ptr.ToString("X"),
                          childx.LocalID, childBodyx.ptr.ToString("X"));

                PhysicsScene.TaintedObject("RemoveChildFromLinkset", delegate()
                {
                    if (m_taintChildren.Contains(childx))
                    {
                        m_taintChildren.Remove(childx);
                    }

                    PhysicallyUnlinkAChildFromRoot(rootx, rootBodyx, childx, childBodyx);
                    RecomputeLinksetConstraintVariables();
                });
            }
            else
            {
                // This will happen if we remove the root of the linkset first. Non-fatal occurance.
                // PhysicsScene.Logger.ErrorFormat("{0}: Asked to remove child from linkset that was not in linkset", LogHeader);
            }
            return;
        }
        // Remove the specified child from the linkset.
        // Safe to call even if the child is not really in my linkset.
        protected override void RemoveChildFromLinkset(BSPrimLinkable child)
        {
            if (m_children.Remove(child))
            {
                BSPrimLinkable rootx  = LinksetRoot; // capture the root and body as of now
                BSPrimLinkable childx = child;

                DetailLog("{0},BSLinksetConstraints.RemoveChildFromLinkset,call,rID={1},rBody={2},cID={3},cBody={4}",
                          childx.LocalID,
                          rootx.LocalID, rootx.PhysBody.AddrString,
                          childx.LocalID, childx.PhysBody.AddrString);

                PhysicsScene.TaintedObject("BSLinksetConstraints.RemoveChildFromLinkset", delegate()
                {
                    PhysicallyUnlinkAChildFromRoot(rootx, childx);
                });
                // See that the linkset parameters are recomputed at the end of the taint time.
                Refresh(LinksetRoot);
            }
            else
            {
                // Non-fatal occurance.
                // PhysicsScene.Logger.ErrorFormat("{0}: Asked to remove child from linkset that was not in linkset", LogHeader);
            }
            return;
        }
示例#6
0
 // called when this character is being destroyed and the resources should be released
 public override void Destroy()
 {
     DetailLog("{0},BSCharacter.Destroy", LocalID);
     PhysicsScene.TaintedObject("BSCharacter.destroy", delegate()
     {
         BulletSimAPI.DestroyObject(PhysicsScene.WorldID, LocalID);
     });
 }
示例#7
0
 // Tell the object to clean up.
 public virtual void Destroy()
 {
     PhysicalActors.Enable(false);
     PhysicsScene.TaintedObject("BSPhysObject.Destroy", delegate()
     {
         PhysicalActors.Dispose();
     });
 }
示例#8
0
 public override void UnSubscribeEvents()
 {
     // DetailLog("{0},{1}.UnSubscribeEvents,unsubscribing", LocalID, TypeName);
     SubscribedEventsMs = 0;
     PhysicsScene.TaintedObject(TypeName + ".UnSubscribeEvents", delegate()
     {
         CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(BSBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
     });
 }
示例#9
0
        public BSCharacter(uint localID, String avName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size, bool isFlying)
            : base(parent_scene, localID, avName, "BSCharacter")
        {
            _physicsActorType = (int)ActorTypes.Agent;
            _position         = pos;

            // Old versions of ScenePresence passed only the height. If width and/or depth are zero,
            //     replace with the default values.
            _size = size;
            if (_size.X == 0f)
            {
                _size.X = BSParam.AvatarCapsuleDepth;
            }
            if (_size.Y == 0f)
            {
                _size.Y = BSParam.AvatarCapsuleWidth;
            }

            // A motor to control the acceleration and deceleration of the avatar movement.
            // _velocityMotor = new BSVMotor("BSCharacter.Velocity", 3f, 5f, BSMotor.InfiniteVector, 1f);
            // _velocityMotor = new BSPIDVMotor("BSCharacter.Velocity", 3f, 5f, BSMotor.InfiniteVector, 1f);
            // Infinite decay and timescale values so motor only changes current to target values.
            _velocityMotor = new BSVMotor("BSCharacter.Velocity",
                                          0.2f,                   // time scale
                                          BSMotor.Infinite,       // decay time scale
                                          BSMotor.InfiniteVector, // friction timescale
                                          1f                      // efficiency
                                          );
            _velocityMotor.PhysicsScene = PhysicsScene;           // DEBUG DEBUG so motor will output detail log messages.

            _flying          = isFlying;
            _orientation     = OMV.Quaternion.Identity;
            _velocity        = OMV.Vector3.Zero;
            _appliedVelocity = OMV.Vector3.Zero;
            _buoyancy        = ComputeBuoyancyFromFlying(isFlying);
            _currentFriction = BSParam.AvatarStandingFriction;
            _avatarDensity   = BSParam.AvatarDensity;

            // The dimensions of the avatar capsule are kept in the scale.
            // Physics creates a unit capsule which is scaled by the physics engine.
            ComputeAvatarScale(_size);
            // set _avatarVolume and _mass based on capsule size, _density and Scale
            ComputeAvatarVolumeAndMass();
            DetailLog("{0},BSCharacter.create,call,size={1},scale={2},density={3},volume={4},mass={5}",
                      LocalID, _size, Scale, _avatarDensity, _avatarVolume, RawMass);

            // do actual creation in taint time
            PhysicsScene.TaintedObject("BSCharacter.create", delegate()
            {
                DetailLog("{0},BSCharacter.create,taint", LocalID);
                // New body and shape into PhysBody and PhysShape
                PhysicsScene.Shapes.GetBodyAndShape(true, PhysicsScene.World, this);

                SetPhysicalProperties();
            });
            return;
        }
示例#10
0
        public BSCharacter(uint localID, String avName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size,
                           bool isFlying)
            : base(parent_scene, localID, avName, "BSCharacter")
        {
            _physicsActorType = (int)ActorTypes.Agent;
            _isPhysical       = true;
            _position         = pos;

            _flying      = isFlying;
            _orientation = OMV.Quaternion.Identity;
            RawVelocity  = OMV.Vector3.Zero;
            _buoyancy    = ComputeBuoyancyFromFlying(isFlying);
            Friction     = BSParam.AvatarStandingFriction;
            Density      = BSParam.AvatarDensity / BSParam.DensityScaleFactor;

            // Old versions of ScenePresence passed only the height. If width and/or depth are zero,
            //     replace with the default values.
            _size = size;
            if (_size.X == 0f)
            {
                _size.X = BSParam.AvatarCapsuleDepth;
            }
            if (_size.Y == 0f)
            {
                _size.Y = BSParam.AvatarCapsuleWidth;
            }

            // The dimensions of the physical capsule are kept in the scale.
            // Physics creates a unit capsule which is scaled by the physics engine.
            Scale = ComputeAvatarScale(_size);
            // set _avatarVolume and _mass based on capsule size, _density and Scale
            ComputeAvatarVolumeAndMass();

            // The avatar's movement is controlled by this motor that speeds up and slows down
            //    the avatar seeking to reach the motor's target speed.
            // This motor runs as a prestep action for the avatar so it will keep the avatar
            //    standing as well as moving. Destruction of the avatar will destroy the pre-step action.
            m_moveActor = new BSActorAvatarMove(PhysicsScene, this, AvatarMoveActorName);
            PhysicalActors.Add(AvatarMoveActorName, m_moveActor);

            DetailLog("{0},BSCharacter.create,call,size={1},scale={2},density={3},volume={4},mass={5}",
                      LocalID, _size, Scale, Density, _avatarVolume, RawMass);

            // do actual creation in taint time
            PhysicsScene.TaintedObject(LocalID, "BSCharacter.create", delegate()
            {
                DetailLog("{0},BSCharacter.create,taint", LocalID);
                // New body and shape into PhysBody and PhysShape
                PhysicsScene.Shapes.GetBodyAndShape(true, PhysicsScene.World, this);

                SetPhysicalProperties();

                SubscribeEvents(1000);
            });
            return;
        }
示例#11
0
 public override void UnSubscribeEvents()
 {
     SubscribedEventsMs = 0;
     PhysicsScene.TaintedObject(TypeName + ".UnSubscribeEvents", delegate()
     {
         // Make sure there is a body there because sometimes destruction happens in an un-ideal order.
         if (PhysBody.HasPhysicalBody)
         {
             CurrentCollisionFlags = PhysicsScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
         }
     });
 }
示例#12
0
        // called when this character is being destroyed and the resources should be released
        public override void Destroy()
        {
            base.Destroy();

            DetailLog("{0},BSCharacter.Destroy", LocalID);
            PhysicsScene.TaintedObject("BSCharacter.destroy", delegate()
            {
                PhysicsScene.Shapes.DereferenceBody(PhysBody, null /* bodyCallback */);
                PhysBody.Clear();
                PhysicsScene.Shapes.DereferenceShape(PhysShape, null /* bodyCallback */);
                PhysShape.Clear();
            });
        }
示例#13
0
 public override void UnSubscribeEvents()
 {
     // DetailLog("{0},{1}.UnSubscribeEvents,unsubscribing", LocalID, TypeName);
     SubscribedEventsMs = 0;
     PhysicsScene.TaintedObject(TypeName + ".UnSubscribeEvents", delegate()
     {
         // Make sure there is a body there because sometimes destruction happens in an un-ideal order.
         if (PhysBody.HasPhysicalBody)
         {
             CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
         }
     });
 }
示例#14
0
        public BSCharacter(uint localID, String avName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size, bool isFlying)
        {
            base.BaseInitialize(parent_scene, localID, avName, "BSCharacter");
            _physicsActorType = (int)ActorTypes.Agent;
            _position         = pos;
            _size             = size;
            _flying           = isFlying;
            _orientation      = OMV.Quaternion.Identity;
            _velocity         = OMV.Vector3.Zero;
            _buoyancy         = ComputeBuoyancyFromFlying(isFlying);

            // The dimensions of the avatar capsule are kept in the scale.
            // Physics creates a unit capsule which is scaled by the physics engine.
            ComputeAvatarScale(_size);
            _avatarDensity = PhysicsScene.Params.avatarDensity;
            // set _avatarVolume and _mass based on capsule size, _density and _scale
            ComputeAvatarVolumeAndMass();

            ShapeData shapeData = new ShapeData();

            shapeData.ID          = LocalID;
            shapeData.Type        = ShapeData.PhysicsShapeType.SHAPE_AVATAR;
            shapeData.Position    = _position;
            shapeData.Rotation    = _orientation;
            shapeData.Velocity    = _velocity;
            shapeData.Scale       = _scale;
            shapeData.Mass        = _mass;
            shapeData.Buoyancy    = _buoyancy;
            shapeData.Static      = ShapeData.numericFalse;
            shapeData.Friction    = PhysicsScene.Params.avatarFriction;
            shapeData.Restitution = PhysicsScene.Params.avatarRestitution;

            // do actual create at taint time
            PhysicsScene.TaintedObject("BSCharacter.create", delegate()
            {
                DetailLog("{0},BSCharacter.create,taint", LocalID);
                BulletSimAPI.CreateObject(PhysicsScene.WorldID, shapeData);

                // Set the buoyancy for flying. This will be refactored when all the settings happen in C#.
                // If not set at creation, the avatar will stop flying when created after crossing a region boundry.
                BulletSimAPI.SetObjectBuoyancy(PhysicsScene.WorldID, LocalID, _buoyancy);

                BSBody = new BulletBody(LocalID, BulletSimAPI.GetBodyHandle2(PhysicsScene.World.ptr, LocalID));

                // This works here because CreateObject has already put the character into the physical world.
                BulletSimAPI.SetCollisionFilterMask2(BSBody.ptr,
                                                     (uint)CollisionFilterGroups.AvatarFilter, (uint)CollisionFilterGroups.AvatarMask);
            });
            return;
        }
示例#15
0
        public override void ZeroAngularMotion(bool inTaintTime)
        {
            _rotationalVelocity = OMV.Vector3.Zero;

            PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.ZeroMotion", delegate()
            {
                if (PhysBody.HasPhysicalBody)
                {
                    PhysicsScene.PE.SetInterpolationAngularVelocity(PhysBody, OMV.Vector3.Zero);
                    PhysicsScene.PE.SetAngularVelocity(PhysBody, OMV.Vector3.Zero);
                    // The next also get rid of applied linear force but the linear velocity is untouched.
                    PhysicsScene.PE.ClearForces(PhysBody);
                }
            });
        }
示例#16
0
        // Set motion values to zero.
        // Do it to the properties so the values get set in the physics engine.
        // Push the setting of the values to the viewer.
        // Called at taint time!
        public override void ZeroMotion(bool inTaintTime)
        {
            RawVelocity         = OMV.Vector3.Zero;
            _acceleration       = OMV.Vector3.Zero;
            _rotationalVelocity = OMV.Vector3.Zero;

            // Zero some other properties directly into the physics engine
            PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.ZeroMotion", delegate()
            {
                if (PhysBody.HasPhysicalBody)
                {
                    PhysicsScene.PE.ClearAllForces(PhysBody);
                }
            });
        }
示例#17
0
        public BSCharacter(uint localID, String avName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size, bool isFlying)
            : base(parent_scene, localID, avName, "BSCharacter")
        {
            _physicsActorType = (int)ActorTypes.Agent;
            _position         = pos;

            _flying          = isFlying;
            _orientation     = OMV.Quaternion.Identity;
            _velocity        = OMV.Vector3.Zero;
            _buoyancy        = ComputeBuoyancyFromFlying(isFlying);
            _currentFriction = BSParam.AvatarStandingFriction;
            _avatarDensity   = BSParam.AvatarDensity;

            // Old versions of ScenePresence passed only the height. If width and/or depth are zero,
            //     replace with the default values.
            _size = size;
            if (_size.X == 0f)
            {
                _size.X = BSParam.AvatarCapsuleDepth;
            }
            if (_size.Y == 0f)
            {
                _size.Y = BSParam.AvatarCapsuleWidth;
            }

            // The dimensions of the physical capsule are kept in the scale.
            // Physics creates a unit capsule which is scaled by the physics engine.
            Scale = ComputeAvatarScale(_size);
            // set _avatarVolume and _mass based on capsule size, _density and Scale
            ComputeAvatarVolumeAndMass();

            SetupMovementMotor();

            DetailLog("{0},BSCharacter.create,call,size={1},scale={2},density={3},volume={4},mass={5}",
                      LocalID, _size, Scale, _avatarDensity, _avatarVolume, RawMass);

            // do actual creation in taint time
            PhysicsScene.TaintedObject("BSCharacter.create", delegate()
            {
                DetailLog("{0},BSCharacter.create,taint", LocalID);
                // New body and shape into PhysBody and PhysShape
                PhysicsScene.Shapes.GetBodyAndShape(true, PhysicsScene.World, this);

                SetPhysicalProperties();
            });
            return;
        }
示例#18
0
        // A version of the sanity check that also makes sure a new position value is
        //    pushed back to the physics engine. This routine would be used by anyone
        //    who is not already pushing the value.
        private bool PositionSanityCheck2()
        {
            bool ret = false;

            if (PositionSanityCheck())
            {
                // The new position value must be pushed into the physics engine but we can't
                //    just assign to "Position" because of potential call loops.
                PhysicsScene.TaintedObject("BSCharacter.PositionSanityCheck", delegate()
                {
                    DetailLog("{0},BSCharacter.PositionSanityCheck,taint,pos={1},orient={2}", LocalID, _position, _orientation);
                    BulletSimAPI.SetObjectTranslation(PhysicsScene.WorldID, LocalID, _position, _orientation);
                });
                ret = true;
            }
            return(ret);
        }
示例#19
0
        public BSPrimLinkable(uint localID, String primName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size,
                              OMV.Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical, int material, float friction,
                              float restitution, float gravityMultiplier, float density)
            : base(localID, primName, parent_scene, pos, size, rotation, pbs, pisPhysical)
        {
            Linkset = BSLinkset.Factory(PhysicsScene, this);

            PhysicsScene.TaintedObject("BSPrimLinksetCompound.Refresh", delegate()
            {
                base.SetMaterial(material);
                base.Friction          = friction;
                base.Restitution       = restitution;
                base.GravityMultiplier = gravityMultiplier;
                base.Density           = density;
                Linkset.Refresh(this);
            });
        }
示例#20
0
        // A version of the sanity check that also makes sure a new position value is
        //    pushed back to the physics engine. This routine would be used by anyone
        //    who is not already pushing the value.
        private bool PositionSanityCheck(bool inTaintTime)
        {
            bool ret = false;

            if (PositionSanityCheck())
            {
                // The new position value must be pushed into the physics engine but we can't
                //    just assign to "Position" because of potential call loops.
                PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.PositionSanityCheck", delegate()
                {
                    DetailLog("{0},BSCharacter.PositionSanityCheck,taint,pos={1},orient={2}", LocalID, _position, _orientation);
                    ForcePosition = _position;
                });
                ret = true;
            }
            return(ret);
        }
示例#21
0
        // When physical properties are changed the linkset needs to recalculate
        //   its internal properties.
        // Called at runtime.
        public void Refresh(BSPhysObject requestor)
        {
            // If there are no children, there can't be any constraints to recompute
            if (!HasAnyChildren)
            {
                return;
            }

            // Only the root does the recomputation
            if (IsRoot(requestor))
            {
                PhysicsScene.TaintedObject("BSLinkSet.Refresh", delegate()
                {
                    RecomputeLinksetConstraintVariables();
                });
            }
        }
示例#22
0
 public override void AddForce(OMV.Vector3 force, bool pushforce)
 {
     if (force.IsFinite())
     {
         _force.X += force.X;
         _force.Y += force.Y;
         _force.Z += force.Z;
         // m_log.DebugFormat("{0}: AddForce. adding={1}, newForce={2}", LogHeader, force, _force);
         PhysicsScene.TaintedObject("BSCharacter.AddForce", delegate()
         {
             DetailLog("{0},BSCharacter.setAddForce,taint,addedForce={1}", LocalID, _force);
             BulletSimAPI.SetObjectForce2(BSBody.ptr, _force);
         });
     }
     else
     {
         m_log.ErrorFormat("{0}: Got a NaN force applied to a Character", LogHeader);
     }
     //m_lastUpdateSent = false;
 }
示例#23
0
        // Subscribe for collision events.
        // Parameter is the millisecond rate the caller wishes collision events to occur.
        public override void SubscribeEvents(int ms)
        {
            // DetailLog("{0},{1}.SubscribeEvents,subscribing,ms={2}", LocalID, TypeName, ms);
            SubscribedEventsMs = ms;
            if (ms > 0)
            {
                // make sure first collision happens
                NextCollisionOkTime = Util.EnvironmentTickCountSubtract(SubscribedEventsMs);

                PhysicsScene.TaintedObject(TypeName + ".SubscribeEvents", delegate()
                {
                    CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(BSBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
                });
            }
            else
            {
                // Subscribing for zero or less is the same as unsubscribing
                UnSubscribeEvents();
            }
        }
示例#24
0
        private void AddForce(OMV.Vector3 force, bool pushforce, bool inTaintTime)
        {
            if (force.IsFinite())
            {
                OMV.Vector3 addForce = Util.ClampV(force, BSParam.MaxAddForceMagnitude);

                PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.AddForce", delegate()
                {
                    // Bullet adds this central force to the total force for this tick
                    if (PhysBody.HasPhysicalBody)
                    {
                        PhysicsScene.PE.ApplyCentralForce(PhysBody, addForce);
                    }
                });
            }
            else
            {
                MainConsole.Instance.WarnFormat("{0}: Got a NaN force applied to a character. LocalID={1}", LogHeader, LocalID);
                return;
            }
        }
示例#25
0
        // Subscribe for collision events.
        // Parameter is the millisecond rate the caller wishes collision events to occur.
        public override void SubscribeEvents(int ms)
        {
            SubscribedEventsMs = ms;
            if (ms > 0)
            {
                // make sure first collision happens
                NextCollisionOkTime = Util.EnvironmentTickCountSubtract(SubscribedEventsMs);

                PhysicsScene.TaintedObject(TypeName + ".SubscribeEvents", delegate()
                {
                    if (PhysBody.HasPhysicalBody)
                    {
                        CurrentCollisionFlags = PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
                    }
                });
            }
            else
            {
                // Subscribing for zero or less is the same as unsubscribing
                UnSubscribeEvents();
            }
        }
示例#26
0
        // If called with no mapInfo for the terrain, this will create a new mapInfo and terrain
        //     based on the passed information. The 'id' should be either the terrain id or
        //     BSScene.CHILDTERRAIN_ID. If the latter, a new child terrain ID will be allocated and used.
        //     The latter feature is for creating child terrains for mega-regions.
        // If called with a mapInfo in m_heightMaps but the terrain has no body yet (mapInfo.terrainBody.Ptr == 0)
        //     then a new body and shape is created and the mapInfo is filled.
        //     This call is used for doing the initial terrain creation.
        // If called with a mapInfo in m_heightMaps and there is an existing terrain body, a new
        //     terrain shape is created and added to the body.
        //     This call is most often used to update the heightMap and parameters of the terrain.
        // The 'doNow' boolean says whether to do all the unmanaged activities right now (like when
        //     calling this routine from initialization or taint-time routines) or whether to delay
        //     all the unmanaged activities to taint-time.
        private void UpdateOrCreateTerrain(uint id, float[] heightMap, Vector3 minCoords, Vector3 maxCoords, bool atTaintTime)
        {
            DetailLog("{0},BSTerrainManager.UpdateOrCreateTerrain,call,minC={1},maxC={2},atTaintTime={3}",
                      BSScene.DetailLogZero, minCoords, maxCoords, atTaintTime);

            float   minZ = float.MaxValue;
            float   maxZ = float.MinValue;
            Vector2 terrainRegionBase = new Vector2(minCoords.X, minCoords.Y);

            int heightMapSize = heightMap.Length;

            for (int ii = 0; ii < heightMapSize; ii++)
            {
                float height = heightMap[ii];
                if (height < minZ)
                {
                    minZ = height;
                }
                if (height > maxZ)
                {
                    maxZ = height;
                }
            }

            // The shape of the terrain is from its base to its extents.
            minCoords.Z = minZ;
            maxCoords.Z = maxZ;

            BulletHeightMapInfo mapInfo;

            if (m_heightMaps.TryGetValue(terrainRegionBase, out mapInfo))
            {
                // If this is terrain we know about, it's easy to update

                mapInfo.heightMap = heightMap;
                mapInfo.minCoords = minCoords;
                mapInfo.maxCoords = maxCoords;
                mapInfo.minZ      = minZ;
                mapInfo.maxZ      = maxZ;
                mapInfo.sizeX     = maxCoords.X - minCoords.X;
                mapInfo.sizeY     = maxCoords.Y - minCoords.Y;
                DetailLog("{0},UpdateOrCreateTerrain:UpdateExisting,call,terrainBase={1},minC={2}, maxC={3}, szX={4}, szY={5}",
                          BSScene.DetailLogZero, terrainRegionBase, mapInfo.minCoords, mapInfo.maxCoords, mapInfo.sizeX, mapInfo.sizeY);

                BSScene.TaintCallback rebuildOperation = delegate()
                {
                    if (MegaRegionParentPhysicsScene != null)
                    {
                        // It's possible that Combine() was called after this code was queued.
                        // If we are a child of combined regions, we don't create any terrain for us.
                        DetailLog("{0},UpdateOrCreateTerrain:AmACombineChild,taint", BSScene.DetailLogZero);

                        // Get rid of any terrain that may have been allocated for us.
                        ReleaseGroundPlaneAndTerrain();

                        // I hate doing this, but just bail
                        return;
                    }

                    if (mapInfo.terrainBody.ptr != IntPtr.Zero)
                    {
                        // Updating an existing terrain.
                        DetailLog("{0},UpdateOrCreateTerrain:UpdateExisting,taint,terrainBase={1},minC={2}, maxC={3}, szX={4}, szY={5}",
                                  BSScene.DetailLogZero, terrainRegionBase, mapInfo.minCoords, mapInfo.maxCoords, mapInfo.sizeX, mapInfo.sizeY);

                        // Remove from the dynamics world because we're going to mangle this object
                        BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, mapInfo.terrainBody.ptr);

                        // Get rid of the old terrain
                        BulletSimAPI.DestroyObject2(PhysicsScene.World.ptr, mapInfo.terrainBody.ptr);
                        BulletSimAPI.ReleaseHeightMapInfo2(mapInfo.Ptr);
                        mapInfo.Ptr = IntPtr.Zero;

                        /*
                         * // NOTE: This routine is half here because I can't get the terrain shape replacement
                         * //   to work. In the short term, the above three lines completely delete the old
                         * //   terrain and the code below recreates one from scratch.
                         * // Hopefully the Bullet community will help me out on this one.
                         *
                         * // First, release the old collision shape (there is only one terrain)
                         * BulletSimAPI.DeleteCollisionShape2(m_physicsScene.World.Ptr, mapInfo.terrainShape.Ptr);
                         *
                         * // Fill the existing height map info with the new location and size information
                         * BulletSimAPI.FillHeightMapInfo2(m_physicsScene.World.Ptr, mapInfo.Ptr, mapInfo.ID,
                         *              mapInfo.minCoords, mapInfo.maxCoords, mapInfo.heightMap, TERRAIN_COLLISION_MARGIN);
                         *
                         * // Create a terrain shape based on the new info
                         * mapInfo.terrainShape = new BulletShape(BulletSimAPI.CreateTerrainShape2(mapInfo.Ptr));
                         *
                         * // Stuff the shape into the existing terrain body
                         * BulletSimAPI.SetBodyShape2(m_physicsScene.World.Ptr, mapInfo.terrainBody.Ptr, mapInfo.terrainShape.Ptr);
                         */
                    }
                    // else
                    {
                        // Creating a new terrain.
                        DetailLog("{0},UpdateOrCreateTerrain:CreateNewTerrain,taint,baseX={1},baseY={2},minZ={3},maxZ={4}",
                                  BSScene.DetailLogZero, mapInfo.minCoords.X, mapInfo.minCoords.Y, minZ, maxZ);

                        mapInfo.ID  = id;
                        mapInfo.Ptr = BulletSimAPI.CreateHeightMapInfo2(PhysicsScene.World.ptr, mapInfo.ID,
                                                                        mapInfo.minCoords, mapInfo.maxCoords, mapInfo.heightMap, TERRAIN_COLLISION_MARGIN);

                        // The terrain object initial position is at the center of the object
                        Vector3 centerPos;
                        centerPos.X = minCoords.X + (mapInfo.sizeX / 2f);
                        centerPos.Y = minCoords.Y + (mapInfo.sizeY / 2f);
                        centerPos.Z = minZ + ((maxZ - minZ) / 2f);

                        // Create the terrain shape from the mapInfo
                        mapInfo.terrainShape = new BulletShape(BulletSimAPI.CreateTerrainShape2(mapInfo.Ptr),
                                                               ShapeData.PhysicsShapeType.SHAPE_TERRAIN);

                        mapInfo.terrainBody = new BulletBody(mapInfo.ID,
                                                             BulletSimAPI.CreateBodyWithDefaultMotionState2(mapInfo.terrainShape.ptr,
                                                                                                            id, centerPos, Quaternion.Identity));
                    }

                    // Make sure the entry is in the heightmap table
                    m_heightMaps[terrainRegionBase] = mapInfo;

                    // Set current terrain attributes
                    BulletSimAPI.SetFriction2(mapInfo.terrainBody.ptr, PhysicsScene.Params.terrainFriction);
                    BulletSimAPI.SetHitFraction2(mapInfo.terrainBody.ptr, PhysicsScene.Params.terrainHitFraction);
                    BulletSimAPI.SetRestitution2(mapInfo.terrainBody.ptr, PhysicsScene.Params.terrainRestitution);
                    BulletSimAPI.SetCollisionFlags2(mapInfo.terrainBody.ptr, CollisionFlags.CF_STATIC_OBJECT);

                    BulletSimAPI.SetMassProps2(mapInfo.terrainBody.ptr, 0f, Vector3.Zero);
                    BulletSimAPI.UpdateInertiaTensor2(mapInfo.terrainBody.ptr);

                    // Return the new terrain to the world of physical objects
                    BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, mapInfo.terrainBody.ptr);

                    // redo its bounding box now that it is in the world
                    BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, mapInfo.terrainBody.ptr);

                    BulletSimAPI.SetCollisionFilterMask2(mapInfo.terrainBody.ptr,
                                                         (uint)CollisionFilterGroups.TerrainFilter,
                                                         (uint)CollisionFilterGroups.TerrainMask);

                    // Make sure the new shape is processed.
                    // BulletSimAPI.Activate2(mapInfo.terrainBody.ptr, true);
                    BulletSimAPI.ForceActivationState2(mapInfo.terrainBody.ptr, ActivationState.DISABLE_SIMULATION);

                    m_terrainModified = true;
                };

                // There is the option to do the changes now (we're already in 'taint time'), or
                //     to do the Bullet operations later.
                if (atTaintTime)
                {
                    rebuildOperation();
                }
                else
                {
                    PhysicsScene.TaintedObject("BSScene.UpdateOrCreateTerrain:UpdateExisting", rebuildOperation);
                }
            }
            else
            {
                // We don't know about this terrain so either we are creating a new terrain or
                //    our mega-prim child is giving us a new terrain to add to the phys world

                // if this is a child terrain, calculate a unique terrain id
                uint newTerrainID = id;
                if (newTerrainID >= BSScene.CHILDTERRAIN_ID)
                {
                    newTerrainID = ++m_terrainCount;
                }

                float[] heightMapX = heightMap;
                Vector3 minCoordsX = minCoords;
                Vector3 maxCoordsX = maxCoords;

                DetailLog("{0},UpdateOrCreateTerrain:NewTerrain,call,id={1}, minC={2}, maxC={3}",
                          BSScene.DetailLogZero, newTerrainID, minCoords, minCoords);

                // Code that must happen at taint-time
                BSScene.TaintCallback createOperation = delegate()
                {
                    DetailLog("{0},UpdateOrCreateTerrain:NewTerrain,taint,baseX={1},baseY={2}", BSScene.DetailLogZero, minCoords.X, minCoords.Y);
                    // Create a new mapInfo that will be filled with the new info
                    mapInfo = new BulletHeightMapInfo(id, heightMapX,
                                                      BulletSimAPI.CreateHeightMapInfo2(PhysicsScene.World.ptr, newTerrainID,
                                                                                        minCoordsX, maxCoordsX, heightMapX, TERRAIN_COLLISION_MARGIN));
                    // Put the unfilled heightmap info into the collection of same
                    m_heightMaps.Add(terrainRegionBase, mapInfo);
                    // Build the terrain
                    UpdateOrCreateTerrain(newTerrainID, heightMap, minCoords, maxCoords, true);

                    m_terrainModified = true;
                };

                // If already in taint-time, just call Bullet. Otherwise queue the operations for the safe time.
                if (atTaintTime)
                {
                    createOperation();
                }
                else
                {
                    PhysicsScene.TaintedObject("BSScene.UpdateOrCreateTerrain:NewTerrain", createOperation);
                }
            }
        }