Ich mache ein Testspiel, bei dem das Level ständig gescrollt werden soll. Um diesen Effekt zu erzielen, habe ich eine Kameraklasse eingerichtet, in der einfach eine Vektor2-Position und eine Aufzählungsrichtung gespeichert werden. Es enthält auch eine öffentliche Methode zum 'Bewegen', die einfach die Position mit einer festen Rate ändert. Diese Position benutze ich dann, wenn ich beim Zeichnen durch meine Kacheln gehe. Das alles funktioniert gut.
Mir wurde jedoch gesagt, dass ich eine Transformationsmatrix verwenden sollte, um die Kamera zu bewegen, und dass ich dies bereitstellen sollte, wenn ich den Spritebatch starte. Ich bin ein wenig verwirrt a.) Wie funktioniert das? als ob ich es nur gebe, wenn Spritebatch beginnt, woher weiß es, dass es seine Position ändert? b.) Warum brauche ich denn sicher noch die Kameraposition, wenn ich Kacheln durchschleife?
Im Moment kann ich es nicht zum Laufen bringen, aber das ist keine Überraschung, da ich nicht ganz verstehe, wie es funktionieren soll. Momentan ändert sich bei meinem Versuch (Code zum Folgen), dass die Kacheln gezeichnet werden, was bedeutet, dass sich die Kameraposition ändert, aber die Position des Ansichtsfensters unverändert bleibt (dh am Kameraursprung). Ich würde mich wirklich über einen Rat / eine Anleitung darüber freuen, wie es verwendet werden soll.
Kamera:
class Camera {
// The position of the camera.
public Vector2 Position {
get { return mCameraPosition; }
set { mCameraPosition = value; }
}
Vector2 mCameraPosition;
public Vector2 Origin { get; set; }
public float Zoom { get; set; }
public float Rotation { get; set; }
public ScrollDirection Direction { get; set; }
private Vector2 mScrollSpeed = new Vector2(20, 18);
public Camera() {
Position = Vector2.Zero;
Origin = Vector2.Zero;
Zoom = 1;
Rotation = 0;
}
public Matrix GetTransform() {
return Matrix.CreateTranslation(new Vector3(mCameraPosition, 0.0f)) *
Matrix.CreateRotationZ(Rotation) *
Matrix.CreateScale(Zoom, Zoom, 1.0f) *
Matrix.CreateTranslation(new Vector3(Origin, 0.0f));
}
public void MoveCamera(Level level) {
if (Direction == ScrollDirection.Up)
{
mCameraPosition.Y = MathHelper.Clamp(mCameraPosition.Y - mScrollSpeed.Y, 0, (level.Height * Tile.Height - level.mViewport.Height));
}
}
Niveau:
public void Update(GameTime gameTime, TouchCollection touchState) {
Camera.MoveCamera(this);
}
public void Draw(SpriteBatch spriteBatch) {
//spriteBatch.Begin();
spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend, SamplerState.LinearClamp, DepthStencilState.Default, RasterizerState.CullCounterClockwise, null, mCamera.GetTransform());
DrawTiles(spriteBatch);
spriteBatch.End();
}
Spiel - nennt die Auslosung nur innerhalb des Levels:
protected override void Draw(GameTime gameTime) {
mGraphics.GraphicsDevice.Clear(Color.Black);
//mSpriteBatch.Begin();
// Draw the level.
mLevel.Draw(mSpriteBatch);
//mSpriteBatch.End();
base.Draw(gameTime);
}
================================================ ============================== EDIT:
Zunächst einmal danke craftworkgames für Ihre bisherige Hilfe.
Ich habe mit dem Vorschlag rumgespielt. Als ich alle Kacheln gezogen habe, hat sich der Fr von 30 auf 15 erhöht - wahrscheinlich, weil die Levels ziemlich groß sind.
Also, was ich getan habe, ist die Matrix anzuwenden und im Update zu bewegen (wie vorgeschlagen), aber beim Zeichnen verwende ich die Kameraposition zum Durchlaufen von Kacheln (dh Startzähler am linken und Ende am rechten Kacheln). Das funktioniert alles gut und ich bin zufrieden damit :-)
Mein neues Problem liegt im Player. Da ich jetzt die Kamera und nicht das Level bewege, wird der Spieler offensichtlich von der Kamera zurückgelassen, da seine Position unverändert bleibt. Ich habe mir zwei Lösungen für dieses Problem ausgedacht. Die erste besteht darin, beim Zeichnen des Players einfach die Kameraposition zu berücksichtigen. Dh in der Ziehfunktion wird einfach die Kameraposition zur Spielerposition hinzugefügt. Die zweite ist, einen neuen Sprite-Stapel für den Spieler zu starten, der keine Transformation hat. dh beenden Sie den Spritebatch nach dem Zeichnen der Kacheln und starten Sie dann einen neuen, wenn Sie den Player zeichnen. Ich weiß, dass beide funktionieren werden, aber ich kann keine Schwänze machen, von denen in Bezug auf Leistung / gute Codierung besser wäre? Ich bin nicht sicher, welche Auswirkungen die Leistung hat, wenn ich den Stapel zweimal starte.
Antworten:
Kameramatrixtransformationen sind einfach
Das Erstellen einer einfachen Kamera ist einfach. Im Folgenden werden Sie mit den Grundlagen beginnen. Bewegen, Drehen und Skalieren. Das Verschieben jedes 2D-Sprites ist kein großes Problem, aber wenn Sie entweder die Skalierung oder die Drehung berücksichtigen, wird es sehr schwierig, jedes Sprite einzeln anzuwenden.
Das Konvertieren zwischen Koordinatensystemdefinitionen ist sehr einfach
Einfach vom Bildschirm in den Weltraum. Dies wird häufig verwendet, um die Position der Maus in der Welt für die Objektauswahl zu ermitteln.
Um von der Welt in den Bildschirmraum zu gelangen, machen Sie einfach das Gegenteil.
Es gibt keinen Nachteil, eine Matrix zu verwenden, außer dass ein wenig Lernen erforderlich ist.
Es ist einfach, den sichtbaren Bereich zu erhalten
Sie können die Kameraecken einfach transformieren und ihre Position im Weltraum ermitteln. Min max die x, y-Werte und Sie können ein Rechteck um den sichtbaren Raum erhalten. Sehr nützlich für das Keulen und Optimieren von Draw Calls.
quelle
Durch Anwenden einer Matrix auf Ihren SpriteBatch wird der gesamte Zeichenaufruf auf einmal transformiert. Dies bedeutet, dass Sie Ihre Kamera in Ihrer DrawTiles-Methode überhaupt nicht verwenden müssen.
Es könnte viel einfacher werden:
Der Sinn einer Matrix ist also, dass Sie nicht darüber nachdenken müssen. Zeichnen Sie einfach Dinge und bewegen Sie die Kamera unabhängig voneinander.
Außerdem sieht Ihre MoveCamera-Methode etwas seltsam aus. Es ist sehr ungewöhnlich, eine Kameraklasse zu haben, die eine Stufe als Abhängigkeit nimmt. Eine typischere Implementierung würde folgendermaßen aussehen:
Dann könnten Sie in Ihrer Update-Methode so etwas tun:
Insgesamt ist mein Vorschlag, es einfach zu halten. Bring es auf einfachste Weise zum Laufen und baue darauf auf. Versuchen Sie, keinen hochoptimierten Code zu schreiben, bevor Sie nicht die Grundlagen erarbeitet haben. Sie können feststellen, dass das Rendern jeder Kachel in jedem Frame nicht so schlecht ist.
EDIT: Für den zweiten Teil der Frage.
Während es stimmt, dass Sie Ihre Batch-Anzahl niedrig halten möchten, sollten 2 oder 3 überhaupt kein Problem sein. Wenn Sie also einen guten Grund haben, einen zweiten Sprite-Stapel zu erstellen, tun Sie es einfach.
Allerdings gibt es in diesem Fall wahrscheinlich keinen guten Grund, einen zweiten Sprite-Stapel zu verwenden. Mit größerer Wahrscheinlichkeit möchten Sie Ihren Player genauso zeichnen, wie Sie Kacheln im selben Sprite-Stapel mit der angewendeten Kameratransformation zeichnen.
Es ist ein wenig schwer zu sagen, warum Ihr Spieler zurückbleibt, ohne sich einen Code anzusehen, aber es liegt auf der Hand, dass er / sie an der gleichen Position wie ein Plättchen erscheint, wenn Sie Ihren Spieler genau an dieselbe Position ziehen Sprite Batch.
Wenn Sie zum Beispiel möchten, dass der Spieler auf Kachel 10, 10 erscheint, können Sie dies tun:
Versuchen Sie, in die Denkweise zu kommen, Dinge dort zu zeichnen, wo sie sich befinden, und die Kamera verschiebt buchstäblich die gesamte "Szene" in den Blick. Genau das macht Ihre Matrixtransformation.
quelle