private CompoundChild GetChild(CompoundShapeEntry entry, int index) { var instance = entry.Shape.GetCollidableInstance(); //Establish the link between the child event manager and our event manager. instance.events.Parent = Events; return(new CompoundChild(Shape, instance, index)); }
protected override void OnCollisionObjectScaleChanged() { for (int i = 0; i < Entity.CollisionInformation.Shape.Shapes.Count; i++) { CompoundShapeEntry childShape = Entity.CollisionInformation.Shape.Shapes[i]; if (childShape.Shape is TransformableShape) { ((TransformableShape)childShape.Shape).Transform = Matrix3x3.CreateFromMatrix(Matrix.CreateScale(CollisionObjectScale) * CollisionObjectWorldTransform); } } }
private void CreateCompoundBody() { List <CompoundShapeEntry> shapes = new List <CompoundShapeEntry>(); // Create parts of compound shape Vector3 blockPos = new Vector3(); for (int z = 0; z < GAME_FIELD_SIZE; ++z) { for (int y = 0; y < GAME_FIELD_SIZE; ++y) { for (int x = 0; x < GAME_FIELD_SIZE; ++x) { blockPos.X = (x - GAME_FIELD_SIZE * 0.5f) * BLOCK_SIZE + BLOCK_SIZE * 0.5f; blockPos.Y = (y - GAME_FIELD_SIZE * 0.5f) * BLOCK_SIZE + BLOCK_SIZE * 0.5f; blockPos.Z = (z - GAME_FIELD_SIZE * 0.5f) * BLOCK_SIZE + BLOCK_SIZE * 0.5f; BoxShape blockShape = new BoxShape(BLOCK_SIZE, BLOCK_SIZE, BLOCK_SIZE); CompoundShapeEntry entry = new CompoundShapeEntry(blockShape, blockPos); 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; // Add constraint prevents compound body from moving constraint = new MaximumLinearSpeedConstraint(compoundBody, 0.0f); // Create collision group for removed blocks removedBlocksGroup = new CollisionGroup(); // Mark all chapes in compound body to be removed for now foreach (CompoundChild child in compoundBody.CollisionInformation.Children) { child.CollisionInformation.CollisionRules.Group = removedBlocksGroup; } // Add compound body and its constraints to physics space space.Add(compoundBody); space.Add(constraint); //compoundBody.CollisionInformation.Events.ContactCreated += handleContactCreated; }
/// <summary> /// Constructs a new demo. /// </summary> /// <param name="game">Game owning this demo.</param> public SpaceshipDemo(DemosGame game) : base(game) { //Build the ship var shipFuselage = new CompoundShapeEntry(new CylinderShape(3, .7m), new Vector3(0, 5, 0), 4); var shipNose = new CompoundShapeEntry(new ConeShape(2, .7m), new Vector3(0, 7, 0), 2); var shipWing = new CompoundShapeEntry(new BoxShape(5, 2, .2m), new Vector3(0, 5, 0), 3); var shipThrusters = new CompoundShapeEntry(new ConeShape(1, .5m), new Vector3(0, 3.25m, 0), 1); var bodies = new List <CompoundShapeEntry>(); bodies.Add(shipFuselage); bodies.Add(shipNose); bodies.Add(shipWing); bodies.Add(shipThrusters); var ship = new CompoundBody(bodies, 10); //Setup the launch pad and ramp Entity toAdd = new Box(new Vector3(10, 4, 0), 26, 1, 6); Space.Add(toAdd); toAdd = new Box(new Vector3(32, 7.8m, 0), 20, 1, 6); toAdd.Orientation = Quaternion.CreateFromAxisAngle(Vector3.Forward, -MathHelper.Pi / 8); Space.Add(toAdd); toAdd = new Box(new Vector3(32, 8.8m, -3.5m), 20, 1, 1); toAdd.Orientation = Quaternion.CreateFromAxisAngle(Vector3.Forward, -MathHelper.Pi / 8); Space.Add(toAdd); toAdd = new Box(new Vector3(32, 8.8m, 3.5m), 20, 1, 1); toAdd.Orientation = Quaternion.CreateFromAxisAngle(Vector3.Forward, -MathHelper.Pi / 8); Space.Add(toAdd); toAdd = new Box(new Vector3(-2.75m, 5.5m, 0), .5m, 2, 3); Space.Add(toAdd); //Blast-off! ship.AngularDamping = .4m; //Helps keep the rocket on track for a little while longer :D var thruster = new Thruster(ship, new Vector3(0, -2, 0), new Vector3(0, 300, 0), 0); Space.Add(thruster); ship.Orientation = Quaternion.CreateFromAxisAngle(Vector3.Right, MathHelper.Pi / 2) * Quaternion.CreateFromAxisAngle(Vector3.Forward, MathHelper.Pi / 2); Space.Add(ship); game.Camera.Position = new Vector3(-14, 12, 25); game.Camera.Yaw(MathHelper.Pi / -4); }
/// <summary> /// Constructs a compound collidable containing only the specified subset of children. /// </summary> /// <param name="shape">Shape to base the compound collidable on.</param> /// <param name="childIndices">Indices of child shapes from the CompoundShape to include in the compound collidable.</param> /// <returns>Compound collidable containing only the specified subset of children.</returns> public static CompoundCollidable CreatePartialCompoundCollidable(CompoundShape shape, IList <int> childIndices) { if (childIndices.Count == 0) { throw new ArgumentException("Cannot create a compound from zero shapes."); } CompoundCollidable compound = new CompoundCollidable(); Vector3 center = new Vector3(); float totalWeight = 0; for (int i = 0; i < childIndices.Count; i++) { //Create and add the child object itself. CompoundShapeEntry entry = shape.shapes[childIndices[i]]; compound.children.Add(new CompoundChild(shape, entry.Shape.GetCollidableInstance(), childIndices[i])); //Grab its entry to compute the center of mass of this subset. Vector3 toAdd; Vector3.Multiply(ref entry.LocalTransform.Position, entry.Weight, out toAdd); Vector3.Add(ref center, ref toAdd, out center); totalWeight += entry.Weight; } if (totalWeight <= 0) { throw new ArgumentException("Compound has zero total weight; invalid configuration."); } Vector3.Divide(ref center, totalWeight, out center); //Our subset of the compound is not necessarily aligned with the shape's origin. //By default, an object will rotate around the center of the collision shape. //We can't modify the shape data itself since it could be shared, which leaves //modifying the local position of the collidable. //We have the subset position in shape space, so pull the collidable back into alignment //with the origin. //This approach matches the rest of the CompoundHelper's treatment of subsets. compound.LocalPosition = -center; //Recompute the hierarchy for the compound. compound.hierarchy.Tree.Reconstruct(compound.children); compound.Shape = shape; return(compound); }
public SpaceShip(PlayerIndex player, Color color, Microsoft.Xna.Framework.Vector3 position) { this.playerIndex = player; var shape = new ProceduralCuboid(1, 1, 1); shape.SetColor(color); ShipObject = new GameObject(); ShipObject.AddComponent(new RenderGeometryComponent(shape)); ShipObject.AddComponent(new EffectRenderComponent(EffectLoader.LoadSM5Effect("flatshaded"))); ShipObject.AddComponent(new ShadowCasterComponent()); SystemCore.GameObjectManager.AddAndInitialiseGameObject(ShipObject); //Build the ship var shipFuselage = new CompoundShapeEntry(new BoxShape(1, 1f, 1), new BEPUutilities.Vector3(0, 0, 0), 4); bodies = new List <CompoundShapeEntry>(); bodies.Add(shipFuselage); PhysicsBody = new CompoundBody(bodies, 10); PhysicsBody.Orientation = BEPUutilities.Quaternion.CreateFromAxisAngle(BEPUutilities.Vector3.Right, (float)Math.PI / 2) * BEPUutilities.Quaternion.CreateFromAxisAngle(BEPUutilities.Vector3.Forward, (float)Math.PI / 2); PhysicsBody.Position = position.ToBepuVector(); SystemCore.PhysicsSimulation.Add(PhysicsBody); PhysicsBody.IsAffectedByGravity = false; //used by the gravitational field to opt out of its effects PhysicsBody.Tag = "spaceship"; PhysicsBody.AngularDamping = 0.99f; PhysicsBody.LinearDamping = 0.99f; }
private CompoundChild GetChild(CompoundShapeEntry entry, int index) { var instance = entry.Shape.GetCollidableInstance(); return(new CompoundChild(Shape, instance, index)); }
/// <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); }
/// <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); }
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); }