2016-05-06 24 views
2

ich eine 2D-Fliese Matrix (von Wänden bis jetzt) ​​und für jede Wand ich überprüfen, ob mein Player nächstes Rectangle (nächste wie in wo es in nächster Frame seine) kollidiert mit dieser Wand, und wenn es so ist, möchte ich, dass mein Spieler direkt daneben steht, ohne hineinzugehen. Hier2D-Physik/Kollision Formel funktioniert nicht wie beabsichtigt

ist die Formel, ich kam mit (dies ist nur für linke und rechte Kollision):

//*move entity 
if (KState.Down(Keys.W)) en.AddForce(new Vector2(0, -10)); 
if (KState.Down(Keys.S)) en.AddForce(new Vector2(0, 10)); 
if (KState.Down(Keys.A)) en.AddForce(new Vector2(-10, 0)); 
if (KState.Down(Keys.D)) en.AddForce(new Vector2(10, 0)); 

foreach(Item i in map.Items) 
{ 
    //resolve left-right collision 
    if (en.NextBody(elapsedTime).Intersects(i.Body)) 
    { 
     //check distance between top left corners 
     int distance = (int)Math.Abs(i.Position.X - en.Position.X); 

     //stop player in his horisontal movement 
     en.AddForce(new Vector2(-en.Force.X, 0)); 

     //place player next to the wall his about to collide with 
     en.Position = new Vector2(en.Position.X - distance + i.Body.Width, en.Position.Y); 
    } 
} 

//stop player in place 
if (KState.Clicked(Keys.Space)) en.AddForce(en.Force*-1); 

en.Update(elapsedTime); 
** 

Was mir dieses Ergebnis gab (beachten Sie, dass fps nicht stabil ist und dass zur Zeit Rechtecke Quadrate 32x32) :

description

Top Textzeile ist Spieler Rectangle, und unten ist Rectangle der Wand, dass Spieler mit dem letzten kollidierte.
Jetzt, wenn der Felsen (Spieler) sich nach links bewegt, halte ich die linke Taste für einige Zeit, und wenn ich nach rechts gehe, halte ich die rechte Taste für einige Zeit.

Problem: Wie Sie in gif sehen können, wenn der Spieler nach links geht, bewegt er 1 Pixel von und zur linken Wand. Und wenn er sich nach rechts bewegt, springt er einmal und bleibt dann direkt neben der rechten Wand. Ich möchte nicht springen, aber ich weiß nicht, wie ich das in der Logik, die ich verwende, beheben kann.

Auch, wenn Sie gute Logik wissen, wie Rectangle Kollision zu lösen, so dass sie nicht von irgendwelchen Seiten schneiden, würde ich appriciate es mit mir zu teilen.

Edit 1: Ich schaffte es, die Kollision auf das richtige Problem zu lösen. Anstelle des obigen Codes habe ich

int sign = Math.Sign(i.Position.X - en.Position.X); 
en.AddForce(new Vector2(-en.Force.X, 0)); 
//wall is right and player is left 
if (sign > 0) en.Position = new Vector2(i.Body.Left - en.Body.Width, en.Position.Y); 
//wall is left and player is right 
if (sign < 0) en.Position = new Vector2(i.Body.Right, en.Position.Y); 

gesetzt, aber das Problem mit der linken Seitenkollision ist das gleiche. Ich versuchte
if (sign < 0) en.Position = new Vector2(i.Body.Right + 1, en.Position.Y); und
if (sign < 0) en.Position = new Vector2(i.Body.Right - 1, en.Position.Y); nur für den Fall, aber das Problem ist das gleiche (auf "...- 1 ..." Fall Player wird in der Wand stecken).

Bearbeiten 2: Wie @paste angefordert, hier ist der Code für NextBody(float elapsedTime) von Spielerklasse.

public Rectangle NextBody(float elapsedTime) 
{ return new Rectangle((int)(force.X * elapsedTime) + body.X, (int)(force.Y * elapsedTime) + body.Y, body.Width, body.Height); } 
+1

Haben Sie eine 'en.SetForce()' Methode? Es kann ein Genauigkeitsproblem geben, wenn ein "gleicher" Betrag von der aktuellen Kraft subtrahiert wird, die Restkraft immer noch in dem "en" -Objekt belässt. Das könnte behoben werden, indem man 'en.SetForce (Vector2.Zero)' ' – paste

+0

anruft. Gut geraten, aber ich habe es überprüft und es war wirklich 0. – Monset

+0

Kannst du deinen' NextBody() 'Code posten? – paste

Antwort

1

Dies ist, was passiert:

Das erste Mal, wenn die Objekte kollidieren, während die Felsen links bewegen, der Algorithmus funktioniert, wie es sollte. Es sieht, dass die Objekte sich überlappen, setzt die Kraft auf Vector2.Zero und verschiebt die en so, dass sie die rechte Seite der berührt. Gut. Ihr Objekt ist gestoppt und am richtigen Ort.

Was im nächsten Frame passiert, ist, wo etwas schief läuft. Sie richten Ihren Kraftvektor ein und rufen dann NextBody(). Schauen wir uns einfach die X-Koordinate an. Es wird gesetzt:

(int)(force.X * elapsedTime) + body.X 

Was bewertet dies?force.X ist nicht Null und elapsedTime ist auch nicht Null, aber sie sind weniger als 1, also, wenn sie in int konvertiert werden, ist das Ergebnis gleich Null. Daher ist Ihre body an der gleichen Stelle wie zuvor, was bedeutet, dass die Rectangle s nicht überlappen. Das bedeutet, dass Ihr Kollisions-Antwortcode übersprungen wird und Ihr force Vektor immer noch nicht Null ist!

Dann, weiter unten, rufen Sie die Update() Methode Ihres Spielers. Ich schätze, dass Sie in diesem Code die Position und Body des Spielers aktualisieren. Aber da force nicht Null ist, und Sie eine Vector2 für Position verwenden, wird die X-Koordinate am Ende etwa 31.841304... statt 32 sein. Wenn Sie diese Zahl verwenden, um die neue Body zu berechnen und sie in Ihrer Draw Methode zu verwenden, werden Sie am Ende bei x = 31 zeichnen. Das nächste Mal, wenn Sie es überprüfen, wird eine Kollision erkannt, und der Player springt wieder aus .

Es gibt eine Reihe von Möglichkeiten, dies zu beheben. Was ich in meinem Kollisionscode tue, ist, die Objekte tatsächlich zuerst zu bewegen und eine Aufzeichnung darüber zu führen, wo sie sich im vorherigen Frame befanden. Auf diese Weise ist die letzte Anpassung an ihre Position, wenn sie aus dem Kollisionsbereich bewegt werden.

+1

Sie haben es gefunden! Ich habe gerade * body.X * in baces wie folgt eingefügt * (int) (force.X * elaphredTime + body.X) * (dasselbe gilt für Y), und jetzt funktioniert es einwandfrei. Daran hätte ich nie gedacht. – Monset