public new void Update(GameTime gameTime) { MouseState mouseState = Mouse.GetState(); RectangleBody mouseCollision = new RectangleBody(mouseState.Position.ToVector2(), new Vector2(0, 0)); Vector2 coordOffset = new Vector2((this._grid.Info.TileWidth * this.Data.Size.Width - this._grid.Info.TileWidth) / 2, (this._grid.Info.TileHeight * this.Data.Size.Height - this._grid.Info.TileHeight) / 2); if (_grid == null) { throw new Exception("Grid not initialized in GhostStructure"); } if (mouseCollision.CollidesWith(new RectangleBody(_grid.Info.GridRectangle))) { _grid.PixelToTile((int)(mouseCollision.Position.X - coordOffset.X), (int)(mouseCollision.Position.Y - coordOffset.Y), out int tileX, out int tileY); if (tileX < 0 || tileY < 0) { this.Collision.Position = mouseState.Position.ToVector2() - (this.Collision.Region().Size.ToVector2() / 2); } else { Rectangle loc = _grid.TileToPixelRect(tileX, tileY); loc.Size = new Vector2(loc.Width * Data.Width, loc.Height * Data.Height).ToPoint(); this.Collision = new RectangleBody(loc); if (mouseState.LeftButton.HasFlag(ButtonState.Pressed)) { this.Data.X1 = tileX; this.Data.Y1 = tileY; _town.FinalizeStructurePlacement(this.ToStructure(), tileX, tileY); if (_town.CanCreateStructure(this)) { _town.BeginStructurePlacement(this.Data.Type); } } } } else { this.Collision.Position = mouseState.Position.ToVector2() - (this.Collision.Region().Size.ToVector2() / 2); } /* * if (mouseState.RightButton == ButtonState.Pressed && !wasPressed) * { * wasPressed = true; * this.RotateRight(); * } * else if (mouseState.RightButton == ButtonState.Released && wasPressed) * { * wasPressed = false; * } * //*/ }
public bool CalculateCollisionData(RectangleBody bodyA, RectangleBody bodyB, ref Vector2 contactPoint, ref Vector2 contactNormal, ref float penetrationDepth) { Vector2[] verticesA = new Vector2[4]; Vector2[] verticesB = new Vector2[4]; bodyA.GetWorldSpaceVertices(ref verticesA); bodyB.GetWorldSpaceVertices(ref verticesB); //liste aus collisiondata, da steht drin um welchen punkt es geht -> index vom vertex, penetration depth(die mindest heruasgefundene), und penetration normal //List<CollisionData> collisionDatasA = new List<CollisionData>(4); //List<CollisionData> collisionDatasB = new List<CollisionData>(4); List <CollisionData> collisionDatasA = new List <CollisionData> { new CollisionData(verticesA[0]), new CollisionData(verticesA[1]), new CollisionData(verticesA[2]), new CollisionData(verticesA[3]) }; List <CollisionData> collisionDatasB = new List <CollisionData> { new CollisionData(verticesB[0]), new CollisionData(verticesB[1]), new CollisionData(verticesB[2]), new CollisionData(verticesB[3]) }; //VERTICES VON B IN A //alle achsen von a durchgehen(kombination punkt 0 auf 1, 1 auf 2 usw., jede achse wird mit den punkten von b verglichen, //man speichert den index für den anfangspunkt { int p0Index = 3; for (int i = 0; i < 4; i++) { //vertex 3 zu 0, 0 zu 1 usw. Vector2 axis = (verticesA[i] - verticesA[p0Index]).normalized; Vector2 norm = new Vector2(axis.y, -axis.x); for (int ii = 0; ii < collisionDatasB.Count; ii++) { float depth = -Vector2.Dot(norm, collisionDatasB[ii].vertexPosition - verticesA[p0Index]); if (depth <= 0) //liegt ausserhalb { collisionDatasB.RemoveAt(ii); ii--; } else { if (depth < collisionDatasB[ii].penetrationDepth) { CollisionData collisionData = collisionDatasB[ii]; collisionData.penetrationDepth = depth; collisionData.penetrationNormal = norm; collisionDatasB[ii] = collisionData; } } } //int p1Index = i; //p0Index = p1Index; p0Index = i; } } { //VERTICES VON A IN B int p0Index = 3; for (int i = 0; i < 4; i++) { //vertex 3 zu 0, 0 zu 1 usw. Vector2 axis = (verticesB[i] - verticesB[p0Index]).normalized; Vector2 norm = new Vector2(axis.y, -axis.x); for (int ii = 0; ii < collisionDatasA.Count; ii++) { float depth = -Vector2.Dot(norm, collisionDatasA[ii].vertexPosition - verticesB[p0Index]); if (depth <= 0) //liegt ausserhalb { collisionDatasA.RemoveAt(ii); ii--; } else { if (depth < collisionDatasA[ii].penetrationDepth) { CollisionData collisionData = collisionDatasA[ii]; collisionData.penetrationDepth = depth; collisionData.penetrationNormal = norm; collisionDatasA[ii] = collisionData; } } } //int p1Index = i; //p0Index = p1Index; p0Index = i; } } //get most penetration depth penetrationDepth = Mathf.NegativeInfinity; //wir wollen die kleinstmögliche penetration kleinster wert foreach (CollisionData collisionData in collisionDatasB) { if (collisionData.penetrationDepth > penetrationDepth) { penetrationDepth = collisionData.penetrationDepth; contactNormal = collisionData.penetrationNormal; contactPoint = collisionData.vertexPosition; } } foreach (CollisionData collisionData in collisionDatasA) { if (collisionData.penetrationDepth > penetrationDepth) { penetrationDepth = collisionData.penetrationDepth; contactNormal = -collisionData.penetrationNormal; //pen normal negieren contactPoint = collisionData.vertexPosition; } } return(penetrationDepth != Mathf.NegativeInfinity); }
public bool CalculateCollisionData(PhysicsBodySphere bodyA, RectangleBody bodyB, ref Vector2 contactPoint, ref Vector2 contactNormal, ref float penetrationDepth) { //center a in den local space from rectangle bekommen, viel leichter zu berechnen wenn man sichs im lokal space vorstellt, weil das rectangle dann axis aligned ist, un dman spart sich viele vektor berechenungen, skalarprodukte etc. //die rotation zurücksetzen und dann wieder zurückdrehen, deswegen mal -bodyB.rotation Vector2 centerA = PhysicsBody.RotateVector2(bodyA.GetCenter() - bodyB.GetCenter(), -bodyB.rotation); //wie weit center von sphere vom center vom rectangle entfernt ist //vergrößerte bounding box (extents) um zu checken obs innerhalb oder außerhalb liegt, bei den faces workeds, aber bei den ecken dann nichtmehr, da braucht man noch einen check Vector2 inflatedExtents = bodyB.extent + Vector2.one * bodyA.radius; //jetzt checken ob centerA (den sphere mittelpunkt) innerhalb von diesen inflatedExtents liegt, es kann aber immer noch in den ecken liegen! if (centerA.x <= inflatedExtents.x /*zumindest nicht rechts von der box*/ && centerA.x >= -inflatedExtents.x /*nicht links von der box*/ && centerA.y <= inflatedExtents.y && centerA.y >= -inflatedExtents.y) { //Check ob wir in den ecken liegen //absolut wert von x und y Vector2 absolutCenterA = new Vector2(Mathf.Abs(centerA.x), Mathf.Abs(centerA.y)); if (absolutCenterA.x >= bodyB.extent.x && absolutCenterA.y >= bodyB.extent.y) //wenn wir in dem rechteck (ecke) liegen { if ((absolutCenterA - bodyB.extent).sqrMagnitude <= bodyA.radius * bodyA.radius) //ob wir wirklich mit der ecke collidieren { Vector2 mirrorDir = new Vector2(Mathf.Sign(centerA.x), Mathf.Sign(centerA.y)); //mathf.Sign liefert +1, -1, oder 0 zurück, kommt drauf an was der input war z.B. 10 = 1, -5 = -1 usw. //nur für ++ space also oberes viertel, deswegen y achse -1 multiplizieren zum spiegeln contactPoint = bodyB.extent; contactNormal = (contactPoint - absolutCenterA).normalized * mirrorDir; //* mirrorDir weil es druaf ankommt in welcher ecke es liegt contactPoint *= mirrorDir; penetrationDepth = bodyA.radius - (absolutCenterA - bodyB.extent) /* hier ist man rechts oben*/.magnitude; //magnitude weil man will die tatsächliche distanz haben //radius - die distanz von center zum point --> da bekommt man die pendepth //jetzt wieder in den World space !!! contactPoint = bodyB.GetCenter() + PhysicsBody.RotateVector2(contactPoint, bodyB.rotation); /*local contactpoint muss rotiert werden */ //normalized Vector muss rotiert werden contactNormal = PhysicsBody.RotateVector2(contactNormal, bodyB.rotation); return(true); } else { return(false); } } //Berechnung ob es an den flächen links rechts oben unten liegt, und nicht in den ecken //RIGHT else if (centerA.x > bodyB.extent.x) { //hier wieder in local space, ContactPoint bie face to face is in der mitte (kann auf der edge sein, oder der punkt der am weitesten drin is contactPoint = new Vector2((bodyB.extent.x + centerA.x - bodyA.radius) * 0.5f /*mittelwert*/, centerA.y); contactNormal = Vector2.left; //weil wir rechts liegen penetrationDepth = Mathf.Abs(bodyB.extent.x - (centerA.x - bodyA.radius)); //weider in world space contactPoint = bodyB.GetCenter() + PhysicsBody.RotateVector2(contactPoint, bodyB.rotation); contactNormal = PhysicsBody.RotateVector2(contactNormal, bodyB.rotation); return(true); } //Left else if (centerA.x < -bodyB.extent.x) { contactPoint = new Vector2((-bodyB.extent.x + centerA.x + bodyA.radius) * 0.5f /*mittelwert*/, centerA.y); contactNormal = Vector2.right; penetrationDepth = Mathf.Abs(-bodyB.extent.x - (centerA.x + bodyA.radius)); contactPoint = bodyB.GetCenter() + PhysicsBody.RotateVector2(contactPoint, bodyB.rotation); contactNormal = PhysicsBody.RotateVector2(contactNormal, bodyB.rotation); return(true); } //UP else if (centerA.y > bodyB.extent.y) { contactPoint = new Vector2(centerA.x, (bodyB.extent.y + centerA.y - bodyA.radius) * 0.5f); contactNormal = Vector2.down; penetrationDepth = Mathf.Abs(bodyB.extent.y - (centerA.y - bodyA.radius)); contactPoint = bodyB.GetCenter() + PhysicsBody.RotateVector2(contactPoint, bodyB.rotation); contactNormal = PhysicsBody.RotateVector2(contactNormal, bodyB.rotation); return(true); } //Down else if (centerA.y < -bodyB.extent.y) { contactPoint = new Vector2(centerA.x, (-bodyB.extent.y + centerA.y + bodyA.radius) * 0.5f); contactNormal = Vector2.up; penetrationDepth = Mathf.Abs(-bodyB.extent.y - (centerA.y + bodyA.radius)); contactPoint = bodyB.GetCenter() + PhysicsBody.RotateVector2(contactPoint, bodyB.rotation); contactNormal = PhysicsBody.RotateVector2(contactNormal, bodyB.rotation); return(true); } else { return(false); } } return(false); }