Tetris - Bitte testen
-
Hallo Pieplz! Mein Tetris ist endlich fertig. Schaut es euch doch bitte mal an und sagt mir, was ihr nicht so gut findet. Ihr findet das Windows-Executable unter www.webfritzi.de.vu in der Projekte-Ecke (ganz unten in der Tabelle).
Da ich auch in Sachen C++ und OOP nicht sooo bewandert bin, hau ich hier auch gleich noch die Haupt-Tetris-Klasse rein. Vielleicht hat ja jemand von euch die Zeit, da mal reinzuschauen.//--------------------------------------------------------------------------- #ifndef TTetrisH #define TTetrisH //--------------------------------------------------------------------------- #include <stdlib> //--------------------------------------------------------------------------- struct CPoint { int x; int y; }; //--------------------------------------------------------------------------- CPoint MakePoint(int x, int y); //--------------------------------------------------------------------------- class TRotationStone { private: int FStoneNumber; // from 0 to 6 int FRotationIndex; // from 0 to 3 public: TRotationStone(); TRotationStone(int stone_number, int rotation_index); void SetStoneNumber(int stone_number); int GetStoneNumber(); int GetRotationIndex(); void GetCoords(CPoint* p); void RotateRight(); void RotateLeft(); void Random(); }; //--------------------------------------------------------------------------- typedef void (*TCallbackFunc)(int); typedef void (*TDeleteLinesFunc)(int*); class TTetris { private: int FPile[10][20]; // Contains: 0 for no stone and 1-7 for stone type TRotationStone FCurStone, FNextStone; CPoint FStonePos; TCallbackFunc FOnVisualUpdate, FOnNewNext, FOnGameOver, FOnTimerStop, FOnTimerGo, FOnNewLevel; TDeleteLinesFunc FOnDeleteLines; int FScore; int FLevel; bool FStopped; int FLines; bool IsDownCollision(); bool IsRightCollision(); bool IsLeftCollision(); bool IsDirectCollision(); void AddStoneToPile(TRotationStone stone, CPoint stone_pos); CPoint GetNewStonePos(TRotationStone stone); void GetFullLines(int* out_lines); void DeleteLines(int* in_lines); bool IsLineFull(int j); void DeleteLine(int j); void ComputeNewScore(int lines); public: TTetris(); ~TTetris(); void Start(); void Pause(); void Reset(); void DoNextStep(); // Call this function in your timer procedure // Input Functions void InputRight(); void InputLeft(); void InputDown(); void InputRotate(); void InputDrop(); // Information on current stone, nest stone and tetris grid int GetPileCoord(int i, int j); void GetCurStoneCoords(CPoint* pp); // Put in a 4-element CPoint array (coords in tetris-grid) void GetNextStoneCoords(CPoint* pp); // Put in a 4-element CPoint array (coords in 4x4-field) int GetCurStoneType(); int GetNextStoneType(); int GetDeletedLines(); bool IsStopped(); int GetLevel(); int GetScore(); // Setter for Callback functions void SetOnVisualUpdateFunc(TCallbackFunc onVisualUpdate); void SetOnNewNextFunc(TCallbackFunc onNewNext); void SetOnGameOverFunc(TCallbackFunc onGameOver); void SetOnDeleteLinesFunc(TDeleteLinesFunc onDeleteLines); // Wird ausgeführt VOR dem Zeilenlöschen void SetOnTimerStopFunc(TCallbackFunc onGameOver); // Turn timer off in this function void SetOnTimerGoFunc(TCallbackFunc onGameOver); // Turn timer on in this function void SetOnNewLevelFunc(TCallbackFunc onNewLevel); }; //--------------------------------------------------------------------------- #endif
Ich poste erstmal nur die Header-Datei. Wenn mehr gewünscht wird (weil man evtl. so noch nicht viel sagen kann), poste ich auch gern die cpp-Datei.
-
Hey. Lässt sich wirklich gut spielen das Game, ist dir sehr gut gelungen ! Aber die Defaultnamen der Highscoreliste solltest du noch ändern ...
Kannst du mal ein paar Daten zum Game geben ? Welche GUI Bibliothek hast du verwendet, etc. ?
MfG mikey. Und poste mal die .cpp Datei !
-
wird es ne linux version geben oder ist das plattformspezifischer code?
also ich habs kurz mit wine getestet und ich muss mich meinem Vorposter (heisst das so?) anschliessen, ist wirklich gut!mfg,
julian
-
Julian__ schrieb:
muss mich mienem vorposter (heisst das so?)
Nein, es heißt "meinem Vorposter". Sorry-CNR
-
sag ich doch.
mfg,
julian
-
muss mich meinem Vorposter (heisst das so?)
Sag doch einfach "mikey"´
-
Lässt sich gut spielen!
Aber die Hiscore-Liste ist ja mal echt peinlich.
Da wir ein Programmierer-Forum sind, wären ein paar technische Daten dazu nicht schlecht.
-
-
Und was hat das jetzt mit WebFritzis Tetris zu tun?
-
http://home.arcor.de/firbach/hmmmmmm.jpg
Das Programm ist aber trotzdem noch weitergelaufen, bis ich irgendwann verloren hatte. Da ich keine Musik gehört habe, war's vielleicht in diesem Thread.
Btw. Die Wiederholrate der Tastatur in Windows zu verstellen ist wirklich ein no-go, sehr unschön.
-
Da wir ein Programmierer-Forum sind, wären ein paar technische Daten dazu nicht schlecht.
Würde ich auch sagen:
mikey schrieb:
Kannst du mal ein paar Daten zum Game geben ? Welche GUI Bibliothek hast du verwendet, etc. ?
-
Artchi schrieb:
vista schrieb:
WebFritzis Seiten schrieb:
300 KB
guck dir mal das an: http://www.256b.com/demo/477
Und was hat das jetzt mit WebFritzis Tetris zu tun?
WebFritzis variante ist 300!!? KB gross.
-
Ja und?
-
Artchi schrieb:
Ja und?
naja, wenn du schon SO fragst, dann vergiss es einfach...
-
@vista: Die 256Byte Variante würde ich aber nicht mit Webfritzis Variante vergleichen ... da sind Welten dazwischen
-
Optimizer schrieb:
http://home.arcor.de/firbach/hmmmmmm.jpg
Das Programm ist aber trotzdem noch weitergelaufen, bis ich irgendwann verloren hatte. Da ich keine Musik gehört habe, war's vielleicht in diesem Thread.Danke für's Testen! Wann ist denn der Fehler aufgetaucht? Direkt nach dem Verlieren?
Optimizer schrieb:
Btw. Die Wiederholrate der Tastatur in Windows zu verstellen ist wirklich ein no-go, sehr unschön.
Wie soll ich das den sonst machen? Wenn jemand ein langsames Delay hat, dann stört das beim Spielen. Beim Schließen des Programmes wird ja wieder der Standard von vorher gesetzt.
CengizS schrieb:
@vista: Die 256Byte Variante würde ich aber nicht mit Webfritzis Variante vergleichen ... da sind Welten dazwischen
Ja. Auf jeden Fall insofern, dass es bei mir besser aussieht und ich Sound verwende. Alleine das fiese Lachen beim Verlieren hat 70 KB.
OK, "technische Daten": Als Bibliothek verwende ich die VCL vom Borland C++Builder, die die WinAPI kapselt (und noch mehr tut). Die Tetris-Klasse ist aber plattform-unabhängig. Man muss nur die GUI schreiben. Die benötigten Callback-Funktionen muss man als Members angeben. Ich hau auf Wunsch mal die cpp-Datei hier rein. Wenn es aber zu viel ist, nehm ich es wieder raus. Mal schauen...
//--------------------------------------------------------------------------- #include "Tetris.h" //--------------------------------------------------------------------------- /* STONES ============= Type 1 ---- ---- ---- ---- -##- -##- -##- -##- -##- -##- -##- -##- ---- ---- ---- ---- Type 2 ---- --#- ---- --#- #### --#- #### --#- ---- --#- ---- --#- ---- --#- ---- --#- Type 3 ---- --#- ---- --#- --## --## --## --## -##- ---# -##- ---# ---- ---- ---- ---- Type 4 ---- ---# ---- ---# -##- --## -##- --## --## --#- --## --#- ---- ---- ---- ---- Type 5 ---- --#- ---# -##- -### --#- -### --#- -#-- --## ---- --#- ---- ---- ---- ---- Type 6 ---- --## -#-- --#- -### --#- -### --#- ---# --#- ---- -##- ---- ---- ---- ---- Type 7 ---- --#- --#- --#- -### --## -### -##- --#- --#- ---- --#- ---- ---- ---- ---- SCORE: (Level n) ------ four rows ("Tetris"): 1200*(n+1) three rows : 300*(n+1) two rows : 100*(n+1) one row : 40*(n+1) drop : n+1 New level after : 10 deleted rows */ //--------------------------------------------------------------------------- const CPoint stones[7][4][4] = { { {{1,1},{2,1},{1,2},{2,2}}, {{1,1},{2,1},{1,2},{2,2}}, {{1,1},{2,1},{1,2},{2,2}}, {{1,1},{2,1},{1,2},{2,2}} }, { {{0,1},{1,1},{2,1},{3,1}}, {{2,0},{2,1},{2,2},{2,3}}, {{0,1},{1,1},{2,1},{3,1}}, {{2,0},{2,1},{2,2},{2,3}} }, { {{2,1},{3,1},{1,2},{2,2}}, {{2,0},{2,1},{3,1},{3,2}}, {{2,1},{3,1},{1,2},{2,2}}, {{2,0},{2,1},{3,1},{3,2}} }, { {{1,1},{2,1},{2,2},{3,2}}, {{3,0},{2,1},{3,1},{2,2}}, {{1,1},{2,1},{2,2},{3,2}}, {{3,0},{2,1},{3,1},{2,2}} }, { {{1,1},{2,1},{3,1},{1,2}}, {{2,0},{2,1},{2,2},{3,2}}, {{3,0},{1,1},{2,1},{3,1}}, {{1,0},{2,0},{2,1},{2,2}} }, { {{1,1},{2,1},{3,1},{3,2}}, {{2,0},{3,0},{2,1},{2,2}}, {{1,0},{1,1},{2,1},{3,1}}, {{2,0},{2,1},{1,2},{2,2}} }, { {{1,1},{2,1},{3,1},{2,2}}, {{2,0},{2,1},{3,1},{2,2}}, {{2,0},{1,1},{2,1},{3,1}}, {{2,0},{1,1},{2,1},{2,2}} } }; //--------------------------------------------------------------------------- CPoint MakePoint(int x, int y) { CPoint p; p.x = x; p.y = y; return p; } //--------------------------------------------------------------------------- TRotationStone::TRotationStone() { FStoneNumber = 0; FRotationIndex = 0; randomize(); } //--------------------------------------------------------------------------- TRotationStone::TRotationStone(int stone_number, int rotation_index) { if(stone_number < 7 && stone_number > -1) FStoneNumber = stone_number; else FStoneNumber = 0; if(rotation_index < 4 && rotation_index > -1) FRotationIndex = rotation_index; else FRotationIndex = 0; randomize(); } //--------------------------------------------------------------------------- void TRotationStone::SetStoneNumber(int stone_number) { if(stone_number < 7 && stone_number > -1) FStoneNumber = stone_number; } //--------------------------------------------------------------------------- int TRotationStone::GetStoneNumber() { return FStoneNumber; } //--------------------------------------------------------------------------- int TRotationStone::GetRotationIndex() { return FRotationIndex; } //--------------------------------------------------------------------------- void TRotationStone::GetCoords(CPoint* p) { CPoint* stone_coords = (CPoint*)stones[FStoneNumber][FRotationIndex]; for(int n=0; n<4; ++n) { p[n].x = stone_coords[n].x; p[n].y = stone_coords[n].y; } } //--------------------------------------------------------------------------- void TRotationStone::RotateLeft() { FRotationIndex--; if(FRotationIndex < 0) FRotationIndex = 3; } //--------------------------------------------------------------------------- void TRotationStone::RotateRight() { FRotationIndex++; if(FRotationIndex > 3) FRotationIndex = 0; } //--------------------------------------------------------------------------- void TRotationStone::Random() { int r = random(19) + 1; // We have 19 different kinds of stones int sn; // Ist die zugehörige Nummer in der Auflistung der Steine (siehe oben) if( r < 8 ) { if( r == 1 ) sn = 1; else { if(r % 2) sn = 2*r; else sn = 2*r + 1; } } else if( r >= 8 ) sn = r + 9; FStoneNumber = (sn - 1) / 4; FRotationIndex = sn - (FStoneNumber * 4) - 1; } //--------------------------------------------------------------------------- //--------------------------------------------------------------------------- /*=========================================================================== CLASS TTetris ===========================================================================*/ TTetris::TTetris() { for(int i=0; i<10; ++i) for(int j=0; j<20; ++j) FPile[i][j] = 0; // No stone anywhere FCurStone.Random(); FNextStone.Random(); FStonePos = GetNewStonePos(FCurStone); FScore = 0; FLevel = 0; FLines = 0; FStopped = true; FOnVisualUpdate = NULL; FOnNewNext = NULL; FOnGameOver = NULL; FOnDeleteLines = NULL; FOnTimerGo = NULL; FOnTimerStop = NULL; } //--------------------------------------------------------------------------- void TTetris::Reset() { for(int i=0; i<10; ++i) for(int j=0; j<20; ++j) FPile[i][j] = 0; // No stone anywhere FCurStone.Random(); FNextStone.Random(); FStonePos = GetNewStonePos(FCurStone); FScore = 0; FLevel = 0; FLines = 0; } //--------------------------------------------------------------------------- TTetris::~TTetris() { } //--------------------------------------------------------------------------- void TTetris::Start() { FStopped = false; if(FOnNewNext) FOnNewNext(0); if(FOnTimerGo) FOnTimerGo(0); if(FOnVisualUpdate) FOnVisualUpdate(1); } //--------------------------------------------------------------------------- void TTetris::Pause() { if(FOnTimerStop) { FOnTimerStop(0); FStopped = true; } } //--------------------------------------------------------------------------- void TTetris::DoNextStep() { static int del_lines[5] = {0,20,20,20,20}; static int stat_level = 0; if( IsDownCollision() ) { if(FStonePos.y <= 0) // Game Over { if(FOnGameOver) { if(FOnTimerStop) { FOnTimerStop(0); FStopped = true; } FOnGameOver(0); } return; } AddStoneToPile(FCurStone, FStonePos); GetFullLines(del_lines); FCurStone = FNextStone; FStonePos = GetNewStonePos(FCurStone); FNextStone.Random(); if( FOnVisualUpdate ) FOnVisualUpdate(0); // Draw only pile if( del_lines[0] ) { FLines += del_lines[0]; ComputeNewScore( del_lines[0] ); stat_level = FLevel; FLevel = FLines / 10; if(stat_level < FLevel) // Level Jump { if(FOnNewLevel) FOnNewLevel(FLevel); } if(FOnDeleteLines) // Blinking lines { if(FOnTimerStop) { FOnTimerStop(0); FStopped = true; } FOnDeleteLines(del_lines); } DeleteLines(del_lines); if(FStopped && FOnTimerGo) { FOnTimerGo(0); FStopped = false; } } if(FOnNewNext) FOnNewNext(0); } else // no down-collision { FStonePos.y++; } if( FOnVisualUpdate ) FOnVisualUpdate(1); } //--------------------------------------------------------------------------- void TTetris::GetFullLines(int* out_lines) { int k = FStonePos.y; int min = (k+3 > 19) ? 19 : k+3; int m = 0; for(int j=k; j<=min; ++j) { if( IsLineFull(j) ) { out_lines[m+1] = j; m++; } } out_lines[0] = m; } //--------------------------------------------------------------------------- void TTetris::DeleteLines(int* in_lines) { /* in_lines is a 5-element array n|m1 m2 m3 m4 where n is the number of full lines and m1-m4 are the indices of the full lines */ int n = in_lines[0]; for(int m=0; m<n; ++m) DeleteLine(in_lines[m+1]); } //--------------------------------------------------------------------------- void TTetris::DeleteLine(int j) { if( j==0 ) // Oberste Line { for(int i=0; i<10; ++i) FPile[i][j] = 0; return; } for(int k=j; k>0; --k) { for(int i=0; i<10; ++i) { FPile[i][k] = FPile[i][k-1]; FPile[i][k-1] = 0; } } } //--------------------------------------------------------------------------- void TTetris::InputRight() { if( !IsRightCollision() ) FStonePos.x++; if( FOnVisualUpdate ) FOnVisualUpdate(1); } //--------------------------------------------------------------------------- void TTetris::InputLeft() { if( !IsLeftCollision() ) FStonePos.x--; if( FOnVisualUpdate ) FOnVisualUpdate(1); } //--------------------------------------------------------------------------- void TTetris::InputDown() { if( !IsDownCollision() ) FStonePos.y++; if( FOnVisualUpdate ) FOnVisualUpdate(1); } //--------------------------------------------------------------------------- void TTetris::InputRotate() { FCurStone.RotateRight(); if( IsDirectCollision() ) FCurStone.RotateLeft(); if( FOnVisualUpdate ) FOnVisualUpdate(1); } //--------------------------------------------------------------------------- void TTetris::InputDrop() { while( !IsDownCollision() ) FStonePos.y++; FScore += FLevel + 1; DoNextStep(); } //--------------------------------------------------------------------------- int TTetris::GetPileCoord(int i, int j) { return FPile[i][j]; } //--------------------------------------------------------------------------- void TTetris::GetCurStoneCoords(CPoint* pp) { CPoint* stone_coords = (CPoint*)stones[FCurStone.GetStoneNumber()][FCurStone.GetRotationIndex()]; for(int n=0; n<4; ++n) { int i = stone_coords[n].x + FStonePos.x; int j = stone_coords[n].y + FStonePos.y; pp[n] = MakePoint(i,j); } } //--------------------------------------------------------------------------- void TTetris::GetNextStoneCoords(CPoint* pp) { CPoint* stone_coords = (CPoint*)stones[FNextStone.GetStoneNumber()][FNextStone.GetRotationIndex()]; for(int n=0; n<4; ++n) { pp[n] = stone_coords[n]; } } //--------------------------------------------------------------------------- int TTetris::GetCurStoneType() { return FCurStone.GetStoneNumber(); } //--------------------------------------------------------------------------- int TTetris::GetNextStoneType() { return FNextStone.GetStoneNumber(); } //--------------------------------------------------------------------------- int TTetris::GetDeletedLines() { return FLines; } //--------------------------------------------------------------------------- int TTetris::GetLevel() { return FLevel; } //--------------------------------------------------------------------------- int TTetris::GetScore() { return FScore; } //--------------------------------------------------------------------------- void TTetris::SetOnVisualUpdateFunc(TCallbackFunc onVisualUpdate) { FOnVisualUpdate = onVisualUpdate; } //--------------------------------------------------------------------------- void TTetris::SetOnNewNextFunc(TCallbackFunc onNewNext) { FOnNewNext = onNewNext; } //--------------------------------------------------------------------------- void TTetris::SetOnGameOverFunc(TCallbackFunc onGameOver) { FOnGameOver = onGameOver; } //--------------------------------------------------------------------------- void TTetris::SetOnTimerGoFunc(TCallbackFunc onTimerGo) { FOnTimerGo = onTimerGo; } //--------------------------------------------------------------------------- void TTetris::SetOnTimerStopFunc(TCallbackFunc onTimerStop) { FOnTimerStop = onTimerStop; } //--------------------------------------------------------------------------- void TTetris::SetOnNewLevelFunc(TCallbackFunc onNewLevel) { FOnNewLevel = onNewLevel; } //--------------------------------------------------------------------------- void TTetris::SetOnDeleteLinesFunc(TDeleteLinesFunc onDeleteLines) { FOnDeleteLines = onDeleteLines; } //--------------------------------------------------------------------------- bool TTetris::IsStopped() { return FStopped; } //--------------------------------------------------------------------------- //--------------------------------------------------------------------------- /*=========================================================================== PRIVATE FUNCTIONS ===========================================================================*/ bool TTetris::IsDownCollision() // Returns true if one step down causes collision { bool collision; FStonePos.y++; collision = IsDirectCollision(); FStonePos.y--; return collision; } //--------------------------------------------------------------------------- bool TTetris::IsRightCollision() // Returns true if one step right causes collision { bool collision; FStonePos.x++; collision = IsDirectCollision(); FStonePos.x--; return collision; } //--------------------------------------------------------------------------- bool TTetris::IsLeftCollision() // Returns true if one step left causes collision { bool collision; FStonePos.x--; collision = IsDirectCollision(); FStonePos.x++; return collision; } //--------------------------------------------------------------------------- void TTetris::AddStoneToPile(TRotationStone stone, CPoint stone_pos) { CPoint* stone_coords = (CPoint*)stones[stone.GetStoneNumber()][stone.GetRotationIndex()]; for(int n=0; n<4; ++n) { int i = stone_coords[n].x + stone_pos.x; int j = stone_coords[n].y + stone_pos.y; FPile[i][j] = stone.GetStoneNumber() + 1; } } //--------------------------------------------------------------------------- bool TTetris::IsDirectCollision() // Returns true if FCurStone collides with pile { CPoint* stone_coords = (CPoint*)stones[FCurStone.GetStoneNumber()][FCurStone.GetRotationIndex()]; for(int n=0; n<4; ++n) { // See if n-th coord of stone collides with pile int i = stone_coords[n].x + FStonePos.x; int j = stone_coords[n].y + FStonePos.y; if( i > 9 || i < 0 || j > 19 ) return true; if( j < 0 ) return false; if( FPile[i][j] ) return true; } return false; } //--------------------------------------------------------------------------- CPoint TTetris::GetNewStonePos(TRotationStone stone) { CPoint p; CPoint* stone_coords = (CPoint*)stones[stone.GetStoneNumber()][stone.GetRotationIndex()]; if( stone_coords[0].y == 0 ) p = MakePoint(3,0); else p = MakePoint(3,-1); return p; } //--------------------------------------------------------------------------- bool TTetris::IsLineFull(int j) { for(int i=0; i<10; ++i) if( !FPile[i][j] ) return false; return true; } //--------------------------------------------------------------------------- void TTetris::ComputeNewScore(int deleted_lines) { switch(deleted_lines) { case 1: FScore += 40 * (FLevel + 1); break; case 2: FScore += 100 * (FLevel + 1); break; case 3: FScore += 300 * (FLevel + 1); break; case 4: FScore += 1200 * (FLevel + 1); break; } } //---------------------------------------------------------------------------