Frage

Ich arbeite ein Tetris-Klon in XNA C # auf Codierung und bin nicht sicher, der beste Weg, um die Datenstruktur Seite des Spiels auf einem hohen Niveau zu nähern.

Ich bin völlig in Ordnung mit der Kollisionserkennung, Drehungen, Animation usw. Was ich den besten Weg, wissen, muß die Speicherung von „fiel gelassen Blöcke“ zu tun - dh Blöcke, die unter tha Spieler Kontrolle nicht mehr.

Ich denke, dass jeder Tetromino Block sollte in seiner eigenen Klasse gespeichert werden, die von einer 4x4-Matrix besteht, so dass der Block leicht gedreht werden kann. Das Problem ist dann, wie ich speichern die Endposition des tetromino in das Spielraster durch dann in einzelne Blöcke, die die tetromino Schneiden (für jede Zelle) und dann die Haupt entsprechenden Positionen des Spielraster die gleichen Blöcke zu halten, wird der tetromino verschwinden einmal es hat seine Endposition erreicht. Vielleicht gibt es einigen Nachteil meine Methode.

Soll ich eine 10x20-Matrix für das Hauptspiel Raster erstellen, die dann speichern? oder soll ich Stapel oder Warteschlangen, um irgendwie die abgelegten Blöcke zu speichern. Oder vielleicht gibt es einige bessere Methode / Datenstruktur Dinge zu speichern?

Ich bin sicher, dass meine Art und Weise funktionieren wird, aber ich bin zu erreichen, um zu sehen, ob jemand einen besseren Weg kennt oder wenn mein Weg ist gut genug?

P. S. Nicht Hausaufgaben, das wird ein Projekt für meinen Portfolio sein. Danke.

War es hilfreich?

Lösung

Sobald ein Block unbeweglich ist, gibt es nichts, was es von einem anderen Block unterscheidet, die nun unbeweglich ist. In diesem Zusammenhang halte ich es am meisten Sinn macht das gesamte Raster als Matrix zu speichern, wobei jedes Quadrat entweder gefüllt ist oder nicht (zusammen mit der Farbe des Blockes, wenn es ist).

Ich fühle mich wie die Matrix hat viele Vorteile. Es wird Kollisionserkennung einfach machen (nicht mit mehreren Objekten vergleichen mit, nur Stellen auf einer Matrix). Speichern sie als Matrix wird es auch leichter zu bestimmen, wann eine vollständige Linie erstellt wurde. Hinzu kommt, dass, müssen Sie sich nicht über Spleißen eine immobile Tetromino sorgen, wenn eine Linie verschwindet. Und wenn man tut, kann man einfach die gesamte Matrix herunterschalten auf einen Schlag.

Andere Tipps

Das riecht wie Hausaufgaben, aber mein nehmen auf einem objektorientierten Ansatz zu Tetris würde jeder einzelne Platz ein Objekt sein, haben sein, und beide „Blöcke“ (Tetrominos) und das Gitter würde sich Sammlungen von den gleichen quadratischen Objekten sein .

Blockobjekte verwalten die Rotation und Position der fallenden Quadrate, und das Gitter Griff deren Anzeige und detroying abgeschlossen Reihen. Jeder Block würde eine Farbe oder Textur mit ihm verbunden, die von dem ursprünglichen Block Objekt zur Verfügung gestellt werden, wäre es kam, aber sonst Quadrate an der Basis des Gitters habe keine anderen Anzeichen dafür, dass sie immer Teil des gleichen ursprünglichen Blockes waren.

Um dies näher auszuführen, wenn Sie ein neues Block-Objekt erstellen, es erzeugt einen Satz von 4 Quadraten mit der gleichen Farbe / Textur auf dem Gitter. Das Raster verwaltet ihre Anzeige. Also, wenn der Block den Boden trifft, einfach vergessen Sie den Block und die Quadrate bleiben durch das Gitter verwiesen wird.

Rotationen und Ablegen sind Operationen nur einen Block muss mit beschäftigen, und nur eine seiner vier Quadrate (obwohl es müssen in der Lage sein, das Netz abfragen, um sicherzustellen, dass die Drehung passen).

Nicht machen Blöcke tatsächlich aussehen autonome Blöcke ist - meiner Meinung nach - ein großes Versagen vieler Tetris-Klon. Ich habe besondere Anstrengungen zu gewährleisten mein Klon immer richtig sah, ob der Block noch „im Spiel“ oder fallen gelassen. Dies bedeutete, etwas über die einfache Matrix-Datenstruktur zu gehen und mit etwas kommen, die das Konzept der „Verbindung“ zwischen Blockteilen unterstützt.

Ich hatte eine Klasse namens BlockGrid, die als Basisklasse verwendet wird, sowohl eine Block und der Board. BlockGrid hat ein abstraktes (rein virtuellen in C ++), die Methode aufgerufen AreBlockPartsSameBlock Subklassen außer Kraft setzen müssen, um zu bestimmen, ob zwei verschiedene Blockteile zu dem gleichen Block gehören. Für die Umsetzung in Block, gibt es einfach true wenn Blockteile an beiden Standorten sind. Für die Umsetzung in Board, gibt sie true wenn beide Standorte die gleiche Block enthalten.

Die BlockGrid Klasse verwendet diese Informationen, um die Details in den gerenderten Blöcken „ausfüllen“, so dass sie wie Blöcke tatsächlich aussehen.

Arrays wäre der einfachste Weg, tetris zu handhaben. Es gibt eine direkte Korrelation zwischen dem, was Sie sehen auf dem Bildschirm und die im Speicher verwendeten Strukturen. Mit Stapel / Warteschlangen wäre zuviel des Guten und unnötig kompliziert sein.

Sie können zwei Kopien eines fallenden Block haben. Man wird für die Anzeige sein (Alpha) und der andere wird Bewegung (Beta).

Sie müssen eine Struktur wie


class FallingBlock
{
  int pos_grid_x;
  int pos_grid_y;
  int blocks_alpha[4][4];
  int blocks_beta[4][4];

  function movedDown();
  function rotate(int direction();
  function checkCollision();
  function revertToAlpha();
  function copyToBeta()
};

Die _beta Array wäre bewegen oder gedreht und geprüft gegen das Brett für Kollisionen. Im Falle einer Kollision ist, kehren sie zu _alpha, wenn nicht, kopieren _beta auf _alpha.

Und wenn es eine Kollision auf movedDown () ist, das Leben des Bausteins ist vorbei und das _alpha Gitter müßte auf das Spielbrett kopieren und das FallingBlock Objekt gelöscht.

Der Vorstand habe natürlich eine andere Struktur wie sein:


class Board
{
  int gameBoard[10][20];

  //some functions go here
}

I int verwendet, um einen Block zu repräsentieren, wobei jeder Wert (wie 1,2,3), die eine unterschiedliche Textur oder Farbe (0 würde bedeuten, eine leere Stelle).

Wenn der Block Teil des Spielplans ist, wäre es nur eine Textur / Farbkennung angezeigt werden müssen.

Ich habe eigentlich nur dies vor ein paar Tagen, außer in WPF nicht XNA. Hier ist, was ich getan habe:

Edit: Scheint, wie ich „Block“ anders als andere Menschen definieren. Was ich definieren als Baustein eines von 4 Zellen, die eine Tetromino bilden, und eine tatsächliche Tetromino sich als Stück.

Haben Sie einen Block als eine Struktur, die X, Y-Koordinaten und Farbe hatte. (Ich habe später einen Bool IsSet um anzuzeigen, ob es in einem schwebenden Stück oder auf dem tatsächlichen Bord war, aber das war nur, weil ich sie visuell unterscheiden wollte)

Als Verfahren auf Block, hatte ich links, rechts, unten, und drehen (Block Center), die ein neues zurück verschoben blockieren. Das erlaubte mir, ohne zu wissen, die Form oder die Ausrichtung des Stückes zu drehen oder ein Stück zu bewegen.

Ich hatte ein allgemeines Stück Objekt, das eine Liste aller Blöcke hatte darin enthaltenen und den Index des Blocks, der das Zentrum war, das als Rotationszentrum verwendet wird.

Ich habe dann eine PieceFactory, die die verschiedenen Stücke produzieren könnte, und mit einem Stück nicht wissen zu müssen, welche Art von Stück es war, konnte ich (und habe) leicht Variation Stück in die aus mehr oder weniger als 4 Blocks ohne dass irgendwelche neue Klassen erstellen

Der Vorstand bestand aus einem Wörterbuch, das alle Blöcke waren, die gegenwärtig auf dem Brett waren, sowie die Dimensionen der Platte, die konfigurierbar ist. Sie können genauso gut eine Matrix verwenden, wahrscheinlich, aber mit einem Wörterbuch ich nur durch Blöcke iteriert benötigt ohne Leerräume.

Meine Lösung (Design), mit Beispielen in Python als guter Ersatz für Pseudo-Code.

Verwenden Sie ein Raster 20 x 10, dass die tetrominoes nach unten fallen.

Tetrominoes besteht aus Blöcken, die Attribute der Koordinate (x, y) und Farbe hat.

So zum Beispiel die T-Form tetrominoe sieht wie folgt aus ...

     . 4 5 6 7 8 .
  .
  19     # # #
  20       #
  .   

Somit ist die T-Form ist eine Sammlung von Blöcken mit den Koordinaten (5,19), (6,19), (7,19), (6,20).

, um die Form zu bewegen ist eine Frage der eine einfache Transformation zu allen coords in der Gruppe angewendet wird. z.B. die Form nach unten add (0,1), links (-1,0) oder rechts (1,0) an alle coords in der Sammlung zu bewegen, die die Form zu machen.

Auf diese Weise können Sie auch einige einfache trigonometrische verwenden, um die Form um 90 Grad zu drehen. Die Regel ist, daß, wenn 90 Grad relativ zu einem Ursprung zu drehen, dann (x, y) gleich wird zu (-y, x).

Hier ist ein Beispiel, es zu erklären. Unter der T-Form von oben, verwenden, um die (6,19) als Mittelblock herum zu drehen. Der Einfachheit halber machen dies die erste in der Sammlung koordinieren, so ...

 t_shape = [ [6,19], [5,19], [7,19], [6,20] ]

Dann ist hier eine einfache Funktion, die Sammlung von Koordinaten um 90-Grad

drehen
def rotate( shape ):
    X=0      # for selecting the X and Y coords
    Y=1

    # get the middle block
    middle = shape[0]   

    # work out the coordinates of the other blocks relative to the
    # middle block
    rel = []
    for coords in shape:
        rel.append( [ coords[X]-middle[X], coords[Y]-middle[Y] ] )

    # now rotate 90-degrees; x,y = -y, x
    new_shape = []
    for coords in rel:
        new_shape.append( [ middle[X]-coords[Y], middle[Y]+coords[X] ] )

    return new_shape

Nun, wenn Sie diese Funktion zu unserer Sammlung gelten für die T-Form von Koordinaten ...

    new_t_shape = rotate( t_shape )

    new_t_shape
    [[6, 19], [6, 18], [6, 20], [5, 19]]

Dieses Grundstück im Koordinatensystem aus und es sieht so aus ...

     . 4 5 6 7 8 .
  .
  18       #
  19     # #
  20       #
  .   

Das war das härteste Bit für mich, hoffe, dass dies jemand hilft.

Beachten Sie, dass ein früherer Gewinner des Obfuscated C-Code Contest ein ziemlich gutes tetris Spiel implementiert (für VT100-Terminals auf BSD Unix) in weniger als 512 Bytes von verschleiertem C:

long h[4];t(){h[3]-=h[3]/3000;setitimer(0,h,0);}c,d,l,v[]={(int)t,0,2},w,s,I,K
=0,i=276,j,k,q[276],Q[276],*n=q,*m,x=17,f[]={7,-13,-12,1,8,-11,-12,-1,9,-1,1,
12,3,-13,-12,-1,12,-1,11,1,15,-1,13,1,18,-1,1,2,0,-12,-1,11,1,-12,1,13,10,-12,
1,12,11,-12,-1,1,2,-12,-1,12,13,-12,12,13,14,-11,-1,1,4,-13,-12,12,16,-11,-12,
12,17,-13,1,-1,5,-12,12,11,6,-12,12,24};u(){for(i=11;++i<264;)if((k=q[i])-Q[i]
){Q[i]=k;if(i-++I||i%12<1)printf("\033[%d;%dH",(I=i)/12,i%12*2+28);printf(
"\033[%dm  "+(K-k?0:5),k);K=k;}Q[263]=c=getchar();}G(b){for(i=4;i--;)if(q[i?b+
n[i]:b])return 0;return 1;}g(b){for(i=4;i--;q[i?x+n[i]:x]=b);}main(C,V,a)char*
*V,*a;{h[3]=1000000/(l=C>1?atoi(V[1]):2);for(a=C>2?V[2]:"jkl pq";i;i--)*n++=i<
25||i%12<2?7:0;srand(getpid());system("stty cbreak -echo stop u");sigvec(14,v,
0);t();puts("\033[H\033[J");for(n=f+rand()%7*4;;g(7),u(),g(0)){if(c<0){if(G(x+
12))x+=12;else{g(7);++w;for(j=0;j<252;j=12*(j/12+1))for(;q[++j];)if(j%12==10){
for(;j%12;q[j--]=0);u();for(;--j;q[j+12]=q[j]);u();}n=f+rand()%7*4;G(x=17)||(c
=a[5]);}}if(c==*a)G(--x)||++x;if(c==a[1])n=f+4**(m=n),G(x)||(n=m);if(c==a[2])G
(++x)||--x;if(c==a[3])for(;G(x+12);++w)x+=12;if(c==a[4]||c==a[5]){s=sigblock(
8192);printf("\033[H\033[J\033[0m%d\n",w);if(c==a[5])break;for(j=264;j--;Q[j]=
0);while(getchar()-a[4]);puts("\033[H\033[J\033[7m");sigsetmask(s);}}d=popen(
"stty -cbreak echo stop \023;cat - HI|sort -rn|head -20>/tmp/$$;mv /tmp/$$ HI\
;cat HI","w");fprintf(d,"%4d on level %1d by %s\n",w,l,getlogin());pclose(d);}

http://www.ioccc.org/1989/tromp.hint

Ich bin keineswegs ein Tetris-Experte, aber wie Sie eine 10x20 Matrix scheint mir wie eine natürliche Wahl beschrieben.

Es wird es machen sehr einfach, wenn die Zeit, wenn Sie eine Zeile oder nicht, abgeschlossen haben, um zu überprüfen kommt und den Umgang damit. Einfach über die 2d-Array iterieren Blick auf Boolesche Werte von jeder Position zu sehen, ob sie summieren sich zu 10 Blockpositionen.

Allerdings werden Sie einige manuelle haben aufzuräumen zu tun, wenn es eine abgeschlossene Linie ist. Nachdem alles nach unten zu verschieben. Alle obwohl es nicht, dass große Sache ist, wenn es darum geht, es.

Mit Simon Peverett Logik, hier ist das, was ich mit in c # endete

public class Tetromino 
{
    // Block is composed of a Point called Position and the color
    public Block[] Blocks { get; protected internal set; }

    // Constructors, etc.

    // Rotate the tetromino by 90 degrees, clock-wise
    public void Rotate() 
    {
        Point middle = Blocks[0].Position;
        List<Point> rel = new List<Point>();
        foreach (Block b in Blocks)
            rel.Add(new Point(b.Position.x - middle.x, b.Position.y - middle.y));

        List<Block> shape = new List<Block>();
        foreach (Point p in rel)
            shape.Add(new Block(middle.x - p.y, middle.y + p.x));

        Blocks = shape.ToArray();
    }

    public void Translate(Point p)
    {
        // Block Translation: Position+= p; 
        foreach (Block b in Blocks)
            b.Translate(p);
    }
}

Hinweis: Mit XNA, Point Struktur für Vector2D getauscht werden könnte

in meinem Beispiel (Java) - alle Figuren haben Listen von Blöcken - die entfernt werden können, wann immer erforderlich. Auch in meiner Board Klasse Ich habe eine Liste von Zahlen und eine Feldvariable Figur - die vom Benutzer gesteuert wird. Wenn die Figur „gelandet“ - es geht in die Liste der anderen Figuren, und eine neue Figur wird durch den Benutzer steuerbar gemacht. Eine bessere Erklärung hier: http: // bordiani .wordpress.com / 2014/10/20 / tetris-in-java-Teil-i-Übersicht /

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top