hallo
ich programmiere im moment ein tetris. es ist mein erstes projekt und bisher hat eigentlich alles ziemlich gut funktioniert.
jetzt habe ich aber ein problem, bei dem ich noch keine brauchbare lösung finden konnte.
ich möchte, dass man einen block noch in letzter sekunde seitwärts unter einen anderen schieben kann.
das funktiniert aber nur, wenn die lücke höher als eine block ist.
ich wäre sehr dankbar, wenn sich jemand den code mal anschauen und mir ein paar lösungsansätze liefern könnte.
ach und noch was:
bei den meisten schriftarten sinkt die framerate vom maximum (60) auf 30 wenn ich sie verwende.
deshalb verwende ich im moment die schrift "Broadway BT", die ist aber ziemlich unpassend und hässlich.
was kann ich tun, um auch andere schriftarten einsetzen zu können?
den source und eine kompillierte version könnt ihr hier downloaden:
http://www.gmbtechnik.ch/yves/code/tetris_source.rar
vielen dank für alle antworten!
Programmieren - alles kontrollieren 4.934 Themen, 20.613 Beiträge
Ich habe mir die exe und den sourcecode jetzt doch mal angeschaut.
Ein paar allgemeine vorschläge:
1. BlockVector in CBlock::ResizeVector nicht immer wieder resizen, sondern im konstruktor einmal auf maximalgröße anlegen (4x4?) und in CBlock::ResizeVector (bzw. in einer neuen methode CBlock::CleanVektor) jedes mal nur den aktiven bereich löschen (=STANDARD). Dadurch können in CBlock::Reset alle BlockVector[0][1] = STANDARD; entfallen.
Also:
ResizeVector(4, 4);
nach CBlock::CBlock() (das gleiche gilt für TempVector in CBlock::Rotate, was in CBlock::CBlock() ja schon halb passiert, aber leider mit undefinierten werten für m_VecRows und m_VecCells)
und neue löschfunktion (CBlock::CleanVektor) für BlockVector (dann gleich auch für TempVector).
2. in fällen wie z.b.
if(DetectCollision(Rows+1, Cells) == true || m_VPosition >= 700-m_VecRows*50)
oder
if(Dir == LEFT && DetectCollision(Rows, Cells-1) == false && m_HPosition-50 >= (SCR_WIDTH-600)/2)
immer die billigen ausdrücke nach links, denn damit erspart man sich oft einen aufwändigen aufruf einer methode, obwohl ein einfacher integer-vergleich auch gereicht hätte (z.b. wenn ich ganz links bin, brauche ich keine kollisionserkennung um zu wissen, dass ich nicht weiter nach links kann).
Um das rutschen in letzter sekunde zu ermöglichen, müsste man eine "eindringtiefe" definieren, die ein block nach unten eindringen könnte, ohne dass die bewegung beendet ist. Ein sinnvoller wert wäre eine halbe bis maximal ganze blockhöhe (evtl. durch schwierigkeitsgrad änderbar).
Sobald eine kollision bemerkt wird, wird die eindringtiefe berechnet. Ist diese klein genug, erfolgt die darstellung um diesen wert höher (also nicht eingetaucht) und es läuft alles weiter wie gehabt. Wird eine seitwärtsbewegung vorgenommen, und die bahn ist wieder frei, wird die nächste kollisionserkennung keine kollision mehr erkennen und die neue eindringtiefe ist 0.
Also:
in class CBlock
kommt
int Penetration;
rein, in
CBlock::Move(int Framerate)
käme die berechnung der aktuellen eindringtiefe hinzu. Aus
if(DetectCollision(Rows+1, Cells) == true || m_VPosition >= 700-m_VecRows*50)
wird
Penetration=0;//soweit kein offset
if(DetectCollision(Rows+1, Cells) != true && m_VPosition < 700-m_VecRows*50)
return;//weder kollision noch boden
int tempPenetration =(int)m_VPosition % 50;
if(tempPenetration<=maxPenetration){//kollision, aber nicht lange/tief genug
Penetration=tempPenetration
return;
}
//richtige kollision, rest wie gehabt
und in
CBlock::Draw
wird aus
rDestRect.top = m_VPosition+j*50;
rDestRect.bottom = m_VPosition+j*50+50;
das hier
rDestRect.top = m_VPosition-Penetration+j*50;
rDestRect.bottom = rDestRect.top+50;
Ich habe das nicht ausprobiert und evtl. muss noch die endposition beim festmachen angepasst werden, aber in etwa sollte das so laufen.
mr.escape