Example #1
0
        public void ImpactHandler(object sender, UpdateStepEventArgs e)
        {
            GameResources.ActorManager.PostPhysicsUpdateStep -= ImpactHandler;
            // TODO: P2: Some boooom sound effects...

            TransformComponent myXForm = Owner.GetComponent <TransformComponent>(ActorComponent.ComponentType.Transform);
            // Do a sphere cast to get actors in the blast radius
            List <RayCastResult> inRangeActors = new List <RayCastResult>();
            SphereShape          blastZone     = new SphereShape(mBlastRadius);
            RigidTransform       blastPosition = new RigidTransform(BepuConverter.Convert(myXForm.Translation));

            BEPUutilities.Vector3 bepuZero = BEPUutilities.Vector3.Zero;
            GameResources.ActorManager.SimSpace.ConvexCast(blastZone, ref blastPosition, ref bepuZero, inRangeActors);

            RayCastDistanceComparer rcdc = new RayCastDistanceComparer();

            for (int a = 0; a < inRangeActors.Count; ++a)
            {
                EntityCollidable inRangeEntityCollidable = inRangeActors[a].HitObject as EntityCollidable;
                if (inRangeEntityCollidable != null &&
                    inRangeEntityCollidable.Entity != null &&
                    inRangeEntityCollidable.Entity.Tag != null)
                {
                    Actor      blastedActor = GameResources.ActorManager.GetActorById((int)(inRangeEntityCollidable.Entity.Tag));
                    IDamagable actorDamage  = blastedActor.GetBehaviorThatImplementsType <IDamagable>();
                    DynamicCollisionComponent actorCollidable = blastedActor.GetComponent <DynamicCollisionComponent>(ActorComponent.ComponentType.Physics);
                    BepuVec3 blastToActorCenter = actorCollidable.Entity.Position - blastPosition.Position;
                    BepuRay  loeRay             = new BepuRay(blastPosition.Position, blastToActorCenter);
                    bool     hasCover           = false;
                    float    distance           = mBlastRadius;
                    if (actorDamage != null || (actorCollidable != null && actorCollidable.IsDynamic && !(actorCollidable.Entity.CollisionInformation.CollisionRules.Personal.HasFlag(BEPUphysics.CollisionRuleManagement.CollisionRule.NoSolver))))
                    {
                        List <RayCastResult> loeResults = new List <RayCastResult>();
                        GameResources.ActorManager.SimSpace.RayCast(loeRay, mBlastRadius, loeResults);
                        loeResults.Sort(rcdc);

                        for (int c = 0; c < loeResults.Count; ++c)
                        {
                            EntityCollidable possibleCover = loeResults[c].HitObject as EntityCollidable;
                            if (possibleCover != null &&
                                possibleCover.Entity == inRangeEntityCollidable.Entity)
                            {
                                // Hit
                                distance = loeResults[c].HitData.T;
                                break;
                            }
                            Terrain possibleCoverTerrain = loeResults[c].HitObject as Terrain;
                            if (possibleCoverTerrain != null)
                            {
                                hasCover = true;
                                break;
                            }
                            if (possibleCover != null &&
                                possibleCover.Entity != null &&
                                !possibleCover.Entity.IsDynamic)
                            {
                                hasCover = true;
                                break;
                            }
                        }
                    }

                    if (!hasCover && actorDamage != null)
                    {
                        actorDamage.TakeDamage((int)(MathHelper.Lerp(1.0f, 0.25f, distance / mBlastRadius) * mDamage));
                    }

                    if (!hasCover && actorCollidable != null && actorCollidable.IsDynamic && !(actorCollidable.Entity.CollisionInformation.CollisionRules.Personal.HasFlag(BEPUphysics.CollisionRuleManagement.CollisionRule.NoSolver)))
                    {
                        blastToActorCenter.Normalize();
                        blastToActorCenter = blastToActorCenter * 1200; // Math.Min(5000.0f / (distance + 1.0f));
                        actorCollidable.Entity.ApplyLinearImpulse(ref blastToActorCenter);
                        if (!actorCollidable.Entity.ActivityInformation.IsActive)
                        {
                            actorCollidable.Entity.ActivityInformation.Activate();
                        }
                    }
                }
            }

            DynamicCollisionComponent dcc = Owner.GetComponent <DynamicCollisionComponent>(ActorComponent.ComponentType.Physics);
            Vector3            myVelocity = BepuConverter.Convert(dcc.Entity.LinearVelocity);
            Actor              fireball   = GameResources.ActorManager.SpawnTemplate("ExplosionFire");
            TransformComponent fireXForm  = fireball.GetComponent <TransformComponent>(ActorComponent.ComponentType.Transform);

            fireXForm.Translation = myXForm.Translation;
            ExplosionFire fireBehavior = fireball.GetBehavior <ExplosionFire>();

            fireBehavior.Emit(myVelocity);
            Actor smoke = GameResources.ActorManager.SpawnTemplate("ExplosionSmoke");
            TransformComponent smokeXForm = smoke.GetComponent <TransformComponent>(ActorComponent.ComponentType.Transform);

            smokeXForm.Translation = myXForm.Translation;
            ExplosionSmoke smokeBehavior = smoke.GetBehavior <ExplosionSmoke>();

            smokeBehavior.Emit(myVelocity);

            Owner.Despawn();
        }
Example #2
0
        // Steer away from obstacles in the way. This method returns a zero vector if no correction is required.
        // It should be high priority and the steering from other behaviors should blend into the remaining space.
        // So if this returns a length 1.0f vector, avoiding the obstacle is most urgent and there is no room for other
        // steering.
        private Vector2 AvoidObstacles(Actor owner)
        {
            BipedControllerComponent bcc = owner.GetComponent <BipedControllerComponent>(ActorComponent.ComponentType.Control);

            // Conditions where we do not want to use this steering force.
            if (GetAngleFromVertical(bcc.Controller.Body.LinearVelocity) < MathHelper.PiOver4 ||    // We're probably falling...
                !bcc.Controller.SupportFinder.HasSupport ||
                !bcc.Controller.SupportFinder.HasTraction)
            {
                return(Vector2.Zero);
            }

            // Sphere cast ahead along facing.
            List <RayCastResult> obstacles          = new List <RayCastResult>();
            SphereShape          probe              = new SphereShape(bcc.Controller.BodyRadius * 1.1f);
            RigidTransform       probeStartPosition = new RigidTransform(bcc.Controller.Body.Position);
            // Add a small constant to the probe length because we want a minimum amount of forward probing, even if we are not moving.
            float          probeLength = Math.Max(BepuVec3.Dot(bcc.Controller.Body.LinearVelocity, bcc.Controller.ViewDirection), 0.0f) + 1.0f;
            BepuVec3       probeSweep  = bcc.Controller.ViewDirection * probeLength;
            ObstacleFilter filter      = new ObstacleFilter(bcc.Controller.Body.CollisionInformation);

            GameResources.ActorManager.SimSpace.ConvexCast(probe, ref probeStartPosition, ref probeSweep, filter.Test, obstacles);

            RayCastDistanceComparer rcdc = new RayCastDistanceComparer();

            obstacles.Sort(rcdc);

            BEPUutilities.Vector3 cross = BEPUutilities.Vector3.Zero;
            int obstacleIndex           = 0;

            do
            {
                if (obstacles.Count == obstacleIndex)
                {
                    return(Vector2.Zero);
                }

                cross = BEPUutilities.Vector3.Cross(bcc.Controller.ViewDirection, -obstacles[obstacleIndex++].HitData.Normal);
            }while (cross.X > 0.7f); // if cross.X > 0.7f, the obstacle is some kind of gentle ramp; ignore it.

            // dot will typically be negative and magnitude indicates how directly ahead the obstacle is.
            float dot = BEPUutilities.Vector3.Dot(bcc.Controller.ViewDirection, -obstacles[0].HitData.Normal);

            if (dot >= 0.0f) // The obstacle won't hinder us if we touch it.
            {
                return(Vector2.Zero);
            }

            // When cross.Y is positive, the object is generally to the right, so veer left (and vice versa).
            float directionSign = cross.Y >= 0.0f ? -1.0f : 1.0f;

            BEPUutilities.Vector2 result = BEPUutilities.Vector2.UnitX * directionSign * -dot;

            // Also scale response by how close the obstacle is.
            float distance = (obstacles[0].HitData.Location - bcc.Controller.Body.Position).Length();

            result *= MathHelper.Clamp((1.0f - distance / probeLength), 0.0f, 1.0f); // / Math.Abs(dot);


            // So far the result is in terms of 'velocity space'. Rotate it to align with the controller facing.
            float velocityTheta = (float)(Math.Atan2(-probeSweep.X, -probeSweep.Z));

            BEPUutilities.Matrix2x2 velocityWorld = SpaceUtils.Create2x2RotationMatrix(velocityTheta);
            float facingTheta = (float)(Math.Atan2(-bcc.Controller.HorizontalViewDirection.X, -bcc.Controller.HorizontalViewDirection.Z));

            BEPUutilities.Matrix2x2 facingWorldInv = SpaceUtils.Create2x2RotationMatrix(facingTheta);
            facingWorldInv.Transpose(); // We want the transpose/inverse of the facing transform because we want to transform the movement into 'facing space'.

            return(BepuConverter.Convert(SpaceUtils.TransformVec2(SpaceUtils.TransformVec2(result, velocityWorld), facingWorldInv)));
        }