Exemplo n.º 1
0
        public Block(BlockType blockType, InstancedMesh <VertexData> .Instance instance, CompoundChild entity)
        {
            BlockType = blockType;
            Instance  = instance;
            Entity    = entity;

            HitPoints = blockType.HitPoints;
        }
Exemplo n.º 2
0
        ///<summary>
        /// Constructs a new compound hierarchy.
        ///</summary>
        ///<param name="owner">Owner of the hierarchy.</param>
        public CompoundHierarchy(CompoundCollidable owner)
        {
            Owner = owner;
            CompoundChild[] children = new CompoundChild[owner.children.Count];
            Array.Copy(owner.children.Elements, children, owner.children.Count);
            //In order to initialize a good tree, the local space bounding boxes should first be computed.
            //Otherwise, the tree would try to create a hierarchy based on a bunch of zeroed out bounding boxes!
            for (int i = 0; i < children.Length; i++)
            {
                children[i].CollisionInformation.worldTransform = owner.Shape.shapes.Elements[i].LocalTransform;
                children[i].CollisionInformation.UpdateBoundingBoxInternal(0);
            }

            Tree = new BoundingBoxTree <CompoundChild>(children);
        }
Exemplo n.º 3
0
        public void AddBlock(String blockType, int x, int y, int z)
        {
            // Obtain compound child for the block
            int           index = x + y * GAME_FIELD_SIZE + z * GAME_FIELD_SIZE * GAME_FIELD_SIZE;
            CompoundChild child = compoundBody.CollisionInformation.Children[index];

            child.CollisionInformation.CollisionRules.Group = null;

            // Obtain instanced mesh for the block
            InstancedMesh instancedMesh = blockInstancedMeshes[blockType];

            // Create instance of the block in instanced mesh
            Matrix transform     = child.Entry.LocalTransform.Matrix; //Matrix.CreateTranslation(x + BLOCK_SIZE * 0.5f, y + BLOCK_SIZE * 0.5f, z + BLOCK_SIZE * 0.5f);
            int    instanceIndex = instancedMesh.AppendInstance(transform);

            // Store new instance to the list
            Block block = new Block(instancedMesh, instanceIndex, child);

            blocks.Add(block);
        }
Exemplo n.º 4
0
        private void RenderEntity(EntityCollidable entity)
        {
            if (entity is CompoundCollidable)
            {
                CompoundCollidable compound = entity as CompoundCollidable;

                for (int i = 0; i < compound.Children.Count; i++)
                {
                    CompoundChild child = compound.Children[i];
                    Matrix4       lt    = child.Entry.LocalTransform.Matrix;
                    GL.MultMatrix(ref lt);

                    RenderEntity(child.CollisionInformation);
                }
            }
            else
            {
                EntityShape shape = entity.Shape;

                if (shape is BoxShape)
                {
                    BoxShape box = shape as BoxShape;
                    RenderCube(box.Width, box.Height, box.Length);
                }
                else if (shape is CylinderShape)
                {
                    CylinderShape cylinder = shape as CylinderShape;
                    RenderCylinder(cylinder.Radius, cylinder.Height);
                }
                else if (shape is ConeShape)
                {
                    ConeShape cone = shape as ConeShape;
                    RenderCone(cone.Radius, cone.Height);
                }
                else if (shape is SphereShape)
                {
                    SphereShape sphere = shape as SphereShape;
                    RenderSphere(sphere.Radius);
                }
            }
        }
Exemplo n.º 5
0
        public void LoadLevel(String fileName)
        {
            // Load level data
            GameLevelContent levelData = Game.Content.Load <GameLevelContent>(fileName);
            int blocksCount            = levelData.BlocksCount();

            // List of blocks chapes for compound body
            List <CompoundShapeEntry> shapes = new List <CompoundShapeEntry>();

            // Create block groups and block physics
            foreach (BlockGroupData blockGroup in levelData.BlockGroups)
            {
                // Create block group
                LoadBlockType(blockGroup.BlockTypeName, blocksCount);

                // Create physical representation of blocks in this group
                Vector3    scale;
                Quaternion rotation;
                Vector3    translation;
                foreach (BlockData blockData in blockGroup.Blocks)
                {
                    // Extract size, position and orientation values from block data transform
                    blockData.Transform.Decompose(out scale, out rotation, out translation);
                    blockData.Scale = scale;

                    // Create physical shape of the block to be part of compound body of blocks
                    BoxShape blockShape = new BoxShape(scale.X, scale.Y, scale.Z);

                    // Create compound shape entry for compund body of blocks
                    CompoundShapeEntry entry = new CompoundShapeEntry(blockShape, new RigidTransform(translation, rotation));
                    shapes.Add(entry);
                }
            }

            // Create compound body
            compoundBody = new CompoundBody(shapes, COMPOUND_BODY_MASS);

            compoundBody.PositionUpdateMode = BEPUphysics.PositionUpdating.PositionUpdateMode.Continuous;
            compoundBody.AngularDamping     = COMPOUND_BODY_ANGULAR_DAMPING;

            // Compound body has Position and LocalPosition (in Collision information)
            // Position property is position of mass center in global space - it is calculated automatically.
            // LocalPosition property is position of geometry of the body in its local space.
            // So in order to create compound body which is rotated around desired position ((0,0,0) for now)
            // We should switch Position and LocalPosition properties of our compound body.
            compoundBody.CollisionInformation.LocalPosition = compoundBody.Position;
            compoundBody.Position = Vector3.Zero;

            // Add constraint prevents compound body from moving
            constraint = new MaximumLinearSpeedConstraint(compoundBody, 0.0f);

            // Create collision group for removed blocks
            removedBlocksGroup = new CollisionGroup();

            // Create blocks
            int childCollidableIndex = 0;

            foreach (BlockGroupData blockGroup in levelData.BlockGroups)
            {
                Matrix localPosTransform = Matrix.CreateTranslation(compoundBody.CollisionInformation.LocalPosition);

                foreach (BlockData blockData in blockGroup.Blocks)
                {
                    // Obtain block type and instanced mesh for the block
                    BlockType blockType = blockTypes[blockGroup.BlockTypeName];
                    InstancedMesh <VertexData> instancedMesh = blockInstancedMeshes[blockGroup.BlockTypeName];

                    // Obtain physics body (a part of compound body) for the block
                    CompoundChild child = compoundBody.CollisionInformation.Children[childCollidableIndex];

                    // Create instance of the block in instanced mesh
                    InstancedMesh <VertexData> .Instance instance = instancedMesh.AppendInstance(Matrix.CreateScale(blockData.Scale) * child.Entry.LocalTransform.Matrix * localPosTransform);

                    // Store new block instance to the list
                    Block block = new Block(blockType, instance, child);
                    blocks.Add(block);

                    block.Scale = blockData.Scale;

                    childCollidableIndex++;
                }
            }

            // Add compound body and its constraints to physics space
            space.Add(compoundBody);
            space.Add(constraint);
        }
Exemplo n.º 6
0
        /// <summary>
        /// Handles contact
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="other"></param>
        /// <param name="pair"></param>
        /// <param name="contact"></param>
        private void handleContactCreated(EntityCollidable sender, Collidable other, CollidablePairHandler pair, ContactData contact)
        {
            var compoundBody = sender as CompoundCollidable;
            var ballEntity   = other as EntityCollidable;


            // Find exact block being hit by ball
            float         minDistance  = 0;
            CompoundChild closestChild = null;

            foreach (CompoundChild child in compoundBody.Children)
            {
                if (child.CollisionInformation.CollisionRules.Group != gameLevel.RemovedBlocksGroup)
                {
                    Vector3 p = Vector3.Transform(child.Entry.LocalTransform.Position, compoundBody.WorldTransform.Matrix);

                    float distance = 0.0f;
                    Vector3.DistanceSquared(ref contact.Position, ref p, out distance);

                    if (closestChild != null)
                    {
                        if (minDistance > distance)
                        {
                            closestChild = child;
                            minDistance  = distance;
                        }
                    }
                    else
                    {
                        closestChild = child;
                        minDistance  = distance;
                    }
                }
            }

            // Obtain block instance
            Block hittedBlock = null;

            foreach (Block block in gameLevel.Blocks)
            {
                if (block.Entity == closestChild)
                {
                    hittedBlock = block;
                    break;
                }
            }

            // Obtain ball instance
            Ball hittingBall = null;

            foreach (Platform platform in platforms)
            {
                foreach (Ball ball in platform.Balls)
                {
                    if (ball.Active == true && ball.Entity.CollisionInformation == ballEntity)
                    {
                        hittingBall = ball;
                        break;
                    }
                }
            }

            // We have obtained block and ball which are collided, now we can run game logic
            if (hittedBlock != null && hittingBall != null)
            {
                // Get hit points from the ball
                int ballHitPoints = hittingBall.HitPoints;

                int gainedHitPoints = Math.Min(hittedBlock.HitPoints, hittingBall.HitPoints);
                gainedHitPoints *= hittedBlock.BlockType.ScoresPerHitPoint;

                hittedBlock.HitPoints -= hittingBall.HitPoints;

                // Run block logic
                BlockType blockType = hittedBlock.BlockType;

                gameLevel.AnimateHit(hittedBlock, contact.Position, hittingBall.Platform);

                foreach (BlockEvent blockAction in blockType.Events)
                {
                    blockAction.HandleEvent(hittedBlock);
                }

                if (hittedBlock.HitPoints <= 0)
                {
                    blockType.Owner.RemoveBlock(hittedBlock);
                }
            }
        }
Exemplo n.º 7
0
        /// <summary>
        /// Removes a child from a compound collidable.
        /// </summary>
        /// <param name="compound">Compound collidable to remove a child from.</param>
        /// <param name="removalPredicate">Callback which analyzes a child and determines if it should be removed from the compound.</param>
        /// <param name="childContributions">Distribution contributions from all shapes in the compound shape.  This can include shapes which are not represented in the compound.</param>
        /// <param name="distributionInfo">Distribution information of the new compound.</param>
        /// <param name="weight">Total weight of the new compound.</param>
        /// <param name="removedWeight">Weight removed from the compound.</param>
        /// <param name="removedCenter">Center of the chunk removed from the compound.</param>
        /// <returns>Whether or not any removal took place.</returns>
        public static bool RemoveChildFromCompound(CompoundCollidable compound,
                                                   Func <CompoundChild, bool> removalPredicate, IList <ShapeDistributionInformation> childContributions,
                                                   out ShapeDistributionInformation distributionInfo, out float weight, out float removedWeight,
                                                   out Vector3 removedCenter)
        {
            bool removalOccurred = false;

            removedWeight = 0;
            removedCenter = new Vector3();
            for (int i = compound.children.Count - 1; i >= 0; i--)
            {
                //The shape doesn't change during this process.  The entity could, though.
                //All of the other collidable information, like the Tag, CollisionRules, Events, etc. all stay the same.
                CompoundChild child = compound.children.Elements[i];
                if (removalPredicate(child))
                {
                    removalOccurred = true;
                    CompoundShapeEntry entry = child.Entry;
                    removedWeight += entry.Weight;
                    Vector3 toAdd;
                    Vector3.Multiply(ref entry.LocalTransform.Position, entry.Weight, out toAdd);
                    Vector3.Add(ref removedCenter, ref toAdd, out removedCenter);
                    //The child event handler must be unhooked from the compound.
                    child.CollisionInformation.events.Parent = null;
                    compound.children.FastRemoveAt(i);
                }
            }

            if (!removalOccurred)
            {
                //No removal occurred, so we cannot proceed.
                distributionInfo = new ShapeDistributionInformation();
                weight           = 0;
                return(false);
            }

            if (removedWeight > 0)
            {
                Vector3.Divide(ref removedCenter, removedWeight, out removedCenter);
            }

            //Compute the contributions from the original shape to the new form of the original collidable.
            distributionInfo = new ShapeDistributionInformation();
            weight           = 0;
            for (int i = compound.children.Count - 1; i >= 0; i--)
            {
                CompoundChild                child        = compound.children.Elements[i];
                CompoundShapeEntry           entry        = child.Entry;
                ShapeDistributionInformation contribution = childContributions[child.shapeIndex];
                Vector3.Add(ref contribution.Center, ref entry.LocalTransform.Position, out contribution.Center);
                Vector3.Multiply(ref contribution.Center, child.Entry.Weight, out contribution.Center);
                Vector3.Add(ref contribution.Center, ref distributionInfo.Center, out distributionInfo.Center);
                distributionInfo.Volume += contribution.Volume;
                weight += entry.Weight;
            }

            //Average the center out.
            Vector3.Divide(ref distributionInfo.Center, weight, out distributionInfo.Center);

            //Note that the 'entry' is from the Shape, and so the translations are local to the shape's center.
            //That is not technically the center of the new collidable- distributionInfo.Center is.
            //Offset the child collidables by -distributionInfo.Center using their local offset.
            Vector3 offset;

            Vector3.Negate(ref distributionInfo.Center, out offset);

            //Compute the unscaled inertia tensor.
            for (int i = compound.children.Count - 1; i >= 0; i--)
            {
                CompoundChild      child = compound.children.Elements[i];
                CompoundShapeEntry entry = child.Entry;
                Vector3            transformedOffset;
                Quaternion         conjugate;
                Quaternion.Conjugate(ref entry.LocalTransform.Orientation, out conjugate);
                Quaternion.Transform(ref offset, ref conjugate, out transformedOffset);
                child.CollisionInformation.localPosition = transformedOffset;
                ShapeDistributionInformation contribution = childContributions[child.shapeIndex];
                CompoundShape.TransformContribution(ref entry.LocalTransform, ref distributionInfo.Center,
                                                    ref contribution.VolumeDistribution, entry.Weight, out contribution.VolumeDistribution);
                //Vector3.Add(ref entry.LocalTransform.Position, ref offsetA, out entry.LocalTransform.Position);
                Matrix3x3.Add(ref contribution.VolumeDistribution, ref distributionInfo.VolumeDistribution,
                              out distributionInfo.VolumeDistribution);
            }

            //Normalize the volume distribution.
            Matrix3x3.Multiply(ref distributionInfo.VolumeDistribution, 1 / weight,
                               out distributionInfo.VolumeDistribution);

            //Update the hierarchies of the compounds.
            //TODO: Create a new method that does this quickly without garbage.  Requires a new Reconstruct method which takes a pool which stores the appropriate node types.
            compound.hierarchy.Tree.Reconstruct(compound.children);

            return(true);
        }
Exemplo n.º 8
0
        /// <summary>
        /// Splits a single compound collidable into two separate compound collidables and computes information needed by the simulation.
        /// </summary>
        /// <param name="splitPredicate">Delegate which determines if a child in the original compound should be moved to the new compound.</param>
        /// <param name="a">Original compound to be split.  Children in this compound will be removed and added to the other compound.</param>
        /// <param name="b">Compound to receive children removed from the original compound.</param>
        /// <param name="distributionInfoA">Volume, volume distribution, and center information about the new form of the original compound collidable.</param>
        /// <param name="distributionInfoB">Volume, volume distribution, and center information about the new compound collidable.</param>
        /// <param name="weightA">Total weight associated with the new form of the original compound collidable.</param>
        /// <param name="weightB">Total weight associated with the new compound collidable.</param>
        /// <returns>Whether or not the predicate returned true for any element in the original compound and split the compound.</returns>
        public static bool SplitCompound(Func <CompoundChild, bool> splitPredicate,
                                         CompoundCollidable a, CompoundCollidable b,
                                         out ShapeDistributionInformation distributionInfoA, out ShapeDistributionInformation distributionInfoB,
                                         out float weightA, out float weightB)
        {
            bool splitOccurred = false;

            for (int i = a.children.Count - 1; i >= 0; i--)
            {
                //The shape doesn't change during this process.  The entity could, though.
                //All of the other collidable information, like the Tag, CollisionRules, Events, etc. all stay the same.
                CompoundChild child = a.children.Elements[i];
                if (splitPredicate(child))
                {
                    splitOccurred = true;

                    a.children.FastRemoveAt(i);
                    b.children.Add(child);
                    //The child event handler must be unhooked from the old compound and given to the new one.
                    child.CollisionInformation.events.Parent = b.Events;
                }
            }

            if (!splitOccurred)
            {
                //No split occurred, so we cannot proceed.
                distributionInfoA = new ShapeDistributionInformation();
                distributionInfoB = new ShapeDistributionInformation();
                weightA           = 0;
                weightB           = 0;
                return(false);
            }

            //Compute the contributions from the original shape to the new form of the original collidable.
            distributionInfoA = new ShapeDistributionInformation();
            weightA           = 0;
            distributionInfoB = new ShapeDistributionInformation();
            weightB           = 0;
            for (int i = a.children.Count - 1; i >= 0; i--)
            {
                CompoundChild      child = a.children.Elements[i];
                CompoundShapeEntry entry = child.Entry;
                Vector3            weightedCenter;
                Vector3.Multiply(ref entry.LocalTransform.Position, entry.Weight, out weightedCenter);
                Vector3.Add(ref weightedCenter, ref distributionInfoA.Center, out distributionInfoA.Center);
                distributionInfoA.Volume += entry.Shape.Volume;
                weightA += entry.Weight;
            }

            for (int i = b.children.Count - 1; i >= 0; i--)
            {
                CompoundChild      child = b.children.Elements[i];
                CompoundShapeEntry entry = child.Entry;
                Vector3            weightedCenter;
                Vector3.Multiply(ref entry.LocalTransform.Position, entry.Weight, out weightedCenter);
                Vector3.Add(ref weightedCenter, ref distributionInfoB.Center, out distributionInfoB.Center);
                distributionInfoB.Volume += entry.Shape.Volume;
                weightB += entry.Weight;
            }

            //Average the center out.
            if (weightA > 0)
            {
                Vector3.Divide(ref distributionInfoA.Center, weightA, out distributionInfoA.Center);
            }

            if (weightB > 0)
            {
                Vector3.Divide(ref distributionInfoB.Center, weightB, out distributionInfoB.Center);
            }

            //Note that the 'entry' is from the Shape, and so the translations are local to the shape's center.
            //That is not technically the center of the new collidable- distributionInfoA.Center is.
            //Offset the child collidables by -distributionInfoA.Center using their local offset.
            Vector3 offsetA;

            Vector3.Negate(ref distributionInfoA.Center, out offsetA);
            Vector3 offsetB;

            Vector3.Negate(ref distributionInfoB.Center, out offsetB);

            //Compute the unscaled inertia tensor.
            for (int i = a.children.Count - 1; i >= 0; i--)
            {
                CompoundChild      child = a.children.Elements[i];
                CompoundShapeEntry entry = child.Entry;
                Vector3            transformedOffset;
                Quaternion         conjugate;
                Quaternion.Conjugate(ref entry.LocalTransform.Orientation, out conjugate);
                Quaternion.Transform(ref offsetA, ref conjugate, out transformedOffset);
                child.CollisionInformation.localPosition = transformedOffset;
                Matrix3x3 contribution;
                CompoundShape.TransformContribution(ref entry.LocalTransform, ref distributionInfoA.Center,
                                                    ref entry.Shape.volumeDistribution, entry.Weight, out contribution);
                Matrix3x3.Add(ref contribution, ref distributionInfoA.VolumeDistribution,
                              out distributionInfoA.VolumeDistribution);
            }

            for (int i = b.children.Count - 1; i >= 0; i--)
            {
                CompoundChild      child = b.children.Elements[i];
                CompoundShapeEntry entry = child.Entry;
                Vector3            transformedOffset;
                Quaternion         conjugate;
                Quaternion.Conjugate(ref entry.LocalTransform.Orientation, out conjugate);
                Quaternion.Transform(ref offsetB, ref conjugate, out transformedOffset);
                child.CollisionInformation.localPosition = transformedOffset;
                Matrix3x3 contribution;
                CompoundShape.TransformContribution(ref entry.LocalTransform, ref distributionInfoB.Center,
                                                    ref entry.Shape.volumeDistribution, entry.Weight, out contribution);
                Matrix3x3.Add(ref contribution, ref distributionInfoB.VolumeDistribution,
                              out distributionInfoB.VolumeDistribution);
            }

            //Normalize the volume distribution.
            Matrix3x3.Multiply(ref distributionInfoA.VolumeDistribution, 1 / weightA,
                               out distributionInfoA.VolumeDistribution);
            Matrix3x3.Multiply(ref distributionInfoB.VolumeDistribution, 1 / weightB,
                               out distributionInfoB.VolumeDistribution);

            //Update the hierarchies of the compounds.
            //TODO: Create a new method that does this quickly without garbage.  Requires a new Reconstruct method which takes a pool which stores the appropriate node types.
            a.hierarchy.Tree.Reconstruct(a.children);
            b.hierarchy.Tree.Reconstruct(b.children);

            return(true);
        }