mirror of https://github.com/buggins/dlangui.git
Tetris example: refactoring
This commit is contained in:
parent
75cb2325cb
commit
1bab98e87e
|
@ -190,6 +190,14 @@ struct FigurePosition {
|
||||||
@property uint color() const {
|
@property uint color() const {
|
||||||
return _figureColors[index - 1];
|
return _figureColors[index - 1];
|
||||||
}
|
}
|
||||||
|
/// return true if figure index is not initialized
|
||||||
|
@property empty() const {
|
||||||
|
return index == 0;
|
||||||
|
}
|
||||||
|
/// clears content
|
||||||
|
void reset() {
|
||||||
|
index = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -201,6 +209,15 @@ struct Cup {
|
||||||
private int[] _cup;
|
private int[] _cup;
|
||||||
private int _cols;
|
private int _cols;
|
||||||
private int _rows;
|
private int _rows;
|
||||||
|
|
||||||
|
private FigurePosition _currentFigure;
|
||||||
|
/// current figure index, orientation, position
|
||||||
|
@property ref FigurePosition currentFigure() { return _currentFigure; }
|
||||||
|
|
||||||
|
private FigurePosition _nextFigure;
|
||||||
|
/// next figure
|
||||||
|
@property ref FigurePosition nextFigure() { return _nextFigure; }
|
||||||
|
|
||||||
/// returns number of columns
|
/// returns number of columns
|
||||||
@property int cols() {
|
@property int cols() {
|
||||||
return _cols;
|
return _cols;
|
||||||
|
@ -229,14 +246,15 @@ struct Cup {
|
||||||
return; // ignore modification of cells outside cup
|
return; // ignore modification of cells outside cup
|
||||||
_cup[row * _cols + col] = value;
|
_cup[row * _cols + col] = value;
|
||||||
}
|
}
|
||||||
/// put figure at specified position
|
/// put current figure into cup at current position and orientation
|
||||||
void putFigure(FigurePosition pos) {
|
void putFigure() {
|
||||||
FigureShape shape = pos.shape;
|
FigureShape shape = _currentFigure.shape;
|
||||||
foreach(cell; shape.cells) {
|
foreach(cell; shape.cells) {
|
||||||
this[pos.x + cell.dx, pos.y + cell.dy] = pos.index;
|
this[_currentFigure.x + cell.dx, _currentFigure.y + cell.dy] = _currentFigure.index;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// check if all cells where figire is located are free
|
|
||||||
|
/// check if all cells where specified figure is located are free
|
||||||
bool isPositionFree(in FigurePosition pos) {
|
bool isPositionFree(in FigurePosition pos) {
|
||||||
FigureShape shape = pos.shape;
|
FigureShape shape = pos.shape;
|
||||||
foreach(cell; shape.cells) {
|
foreach(cell; shape.cells) {
|
||||||
|
@ -246,6 +264,67 @@ struct Cup {
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// check if all cells where current figire is located are free
|
||||||
|
bool isPositionFree() {
|
||||||
|
return isPositionFree(_currentFigure);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// check if all cells where current figire is located are free
|
||||||
|
bool isPositionFreeBelow() {
|
||||||
|
return isPositionFree(_currentFigure.move(0, -1));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// try to rotate current figure, returns true if figure rotated
|
||||||
|
bool rotate(int angle, bool falling) {
|
||||||
|
FigurePosition newpos = _currentFigure.rotate(angle);
|
||||||
|
if (isPositionFree(newpos)) {
|
||||||
|
if (falling) {
|
||||||
|
// special handling for fall animation
|
||||||
|
if (!isPositionFree(newpos.move(0, -1))) {
|
||||||
|
if (isPositionFreeBelow())
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_currentFigure = newpos;
|
||||||
|
return true;
|
||||||
|
} else if (isPositionFree(newpos.move(0, -1))) {
|
||||||
|
_currentFigure = newpos.move(0, -1);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// try to move current figure, returns true if figure rotated
|
||||||
|
bool move(int deltaX, int deltaY, bool falling) {
|
||||||
|
FigurePosition newpos = _currentFigure.move(deltaX, deltaY);
|
||||||
|
if (isPositionFree(newpos)) {
|
||||||
|
if (falling && !isPositionFree(newpos.move(0, -1))) {
|
||||||
|
if (isPositionFreeBelow())
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
_currentFigure = newpos;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void genNextFigure() {
|
||||||
|
_nextFigure.index = uniform(FIGURE1, FIGURE6 + 1);
|
||||||
|
_nextFigure.orientation = ORIENTATION0;
|
||||||
|
_nextFigure.x = _cols / 2;
|
||||||
|
_nextFigure.y = _rows - _nextFigure.shape.extent + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool dropNextFigure() {
|
||||||
|
if (_nextFigure.empty)
|
||||||
|
genNextFigure();
|
||||||
|
_currentFigure = _nextFigure;
|
||||||
|
_currentFigure.x = _cols / 2;
|
||||||
|
_currentFigure.y = _rows - 1 - _currentFigure.shape.y0;
|
||||||
|
return isPositionFree();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Cup widget
|
/// Cup widget
|
||||||
|
@ -257,10 +336,6 @@ class CupWidget : Widget {
|
||||||
/// cup data
|
/// cup data
|
||||||
Cup _cup;
|
Cup _cup;
|
||||||
|
|
||||||
/// current figure index, orientation, position
|
|
||||||
FigurePosition _currentFigure;
|
|
||||||
/// next figure id
|
|
||||||
FigurePosition _nextFigure;
|
|
||||||
|
|
||||||
/// Level 1..10
|
/// Level 1..10
|
||||||
int _level;
|
int _level;
|
||||||
|
@ -343,62 +418,32 @@ class CupWidget : Widget {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool rotate(int angle) {
|
|
||||||
FigurePosition newpos = _currentFigure.rotate(angle);
|
|
||||||
if (_cup.isPositionFree(newpos)) {
|
|
||||||
if (_state == CupState.FallingFigure) {
|
|
||||||
// special handling for fall animation
|
|
||||||
if (!_cup.isPositionFree(newpos.move(0, -1))) {
|
|
||||||
if (isPositionFreeBelow())
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_currentFigure = newpos;
|
|
||||||
return true;
|
|
||||||
} else if (_cup.isPositionFree(newpos.move(0, -1))) {
|
|
||||||
_currentFigure = newpos.move(0, -1);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool move(int deltaX) {
|
|
||||||
FigurePosition newpos = _currentFigure.move(deltaX);
|
|
||||||
if (_cup.isPositionFree(newpos)) {
|
|
||||||
if (_state == CupState.FallingFigure && !_cup.isPositionFree(newpos.move(0, -1))) {
|
|
||||||
if (isPositionFreeBelow())
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
_currentFigure = newpos;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void onAnimationFinished() {
|
protected void onAnimationFinished() {
|
||||||
switch (_state) {
|
switch (_state) {
|
||||||
case CupState.NewFigure:
|
case CupState.NewFigure:
|
||||||
_fastDownFlag = false;
|
_fastDownFlag = false;
|
||||||
genNextFigure();
|
_cup.genNextFigure();
|
||||||
setCupState(CupState.HangingFigure, 75);
|
setCupState(CupState.HangingFigure, 75);
|
||||||
break;
|
break;
|
||||||
case CupState.FallingFigure:
|
case CupState.FallingFigure:
|
||||||
if (isPositionFreeBelow()) {
|
if (_cup.isPositionFreeBelow()) {
|
||||||
_currentFigure.y--;
|
_cup.move(0, -1, false);
|
||||||
if (_fastDownFlag)
|
if (_fastDownFlag)
|
||||||
setCupState(CupState.FallingFigure, 10);
|
setCupState(CupState.FallingFigure, 10);
|
||||||
else
|
else
|
||||||
setCupState(CupState.HangingFigure, 75);
|
setCupState(CupState.HangingFigure, 75);
|
||||||
} else {
|
} else {
|
||||||
// At bottom of cup
|
// At bottom of cup
|
||||||
_cup.putFigure(_currentFigure);
|
_cup.putFigure();
|
||||||
_fastDownFlag = false;
|
_fastDownFlag = false;
|
||||||
if (!dropNextFigure()) {
|
if (!_cup.dropNextFigure()) {
|
||||||
// Game Over
|
// Game Over
|
||||||
setCupState(CupState.GameOver);
|
setCupState(CupState.GameOver);
|
||||||
Widget popupWidget = new TextWidget("popup", "Game Over!"d);
|
Widget popupWidget = new TextWidget("popup", "Game Over!"d);
|
||||||
popupWidget.padding(Rect(30, 30, 30, 30)).backgroundImageId("popup_background").alpha(0x40).fontWeight(800).fontSize(30);
|
popupWidget.padding(Rect(30, 30, 30, 30)).backgroundImageId("popup_background").alpha(0x40).fontWeight(800).fontSize(30);
|
||||||
_gameOverPopup = window.showPopup(popupWidget, this);
|
_gameOverPopup = window.showPopup(popupWidget, this);
|
||||||
|
} else {
|
||||||
|
setCupState(CupState.NewFigure, 100, 255);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -422,23 +467,6 @@ class CupWidget : Widget {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void genNextFigure() {
|
|
||||||
_nextFigure.index = uniform(FIGURE1, FIGURE6 + 1);
|
|
||||||
_nextFigure.orientation = ORIENTATION0;
|
|
||||||
_nextFigure.x = _cols / 2;
|
|
||||||
_nextFigure.y = _rows - _nextFigure.shape.extent + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool dropNextFigure() {
|
|
||||||
if (_nextFigure.index == 0)
|
|
||||||
genNextFigure();
|
|
||||||
_currentFigure = _nextFigure;
|
|
||||||
_currentFigure.x = _cols / 2;
|
|
||||||
_currentFigure.y = _rows - 1 - _currentFigure.shape.y0;
|
|
||||||
setCupState(CupState.NewFigure, 100, 255);
|
|
||||||
return isPositionFree();
|
|
||||||
}
|
|
||||||
|
|
||||||
void init(int cols, int rows) {
|
void init(int cols, int rows) {
|
||||||
_cup.init(cols, rows);
|
_cup.init(cols, rows);
|
||||||
_cols = cols;
|
_cols = cols;
|
||||||
|
@ -456,14 +484,6 @@ class CupWidget : Widget {
|
||||||
return Rect(x0, y0, x0 + dd, y0 + dd);
|
return Rect(x0, y0, x0 + dd, y0 + dd);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected bool isPositionFree() {
|
|
||||||
return _cup.isPositionFree(_currentFigure);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected bool isPositionFreeBelow() {
|
|
||||||
return _cup.isPositionFree(_currentFigure.move(0, -1));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Handle keys
|
/// Handle keys
|
||||||
override bool onKeyEvent(KeyEvent event) {
|
override bool onKeyEvent(KeyEvent event) {
|
||||||
if (event.action == KeyAction.KeyDown && _state == CupState.GameOver) {
|
if (event.action == KeyAction.KeyDown && _state == CupState.GameOver) {
|
||||||
|
@ -545,22 +565,21 @@ class CupWidget : Widget {
|
||||||
// draw current figure falling
|
// draw current figure falling
|
||||||
if (_state == CupState.FallingFigure || _state == CupState.HangingFigure) {
|
if (_state == CupState.FallingFigure || _state == CupState.HangingFigure) {
|
||||||
int dy = 0;
|
int dy = 0;
|
||||||
if (_state == CupState.FallingFigure && isPositionFreeBelow()) {
|
if (falling && _cup.isPositionFreeBelow())
|
||||||
dy = _animation.getProgress(topLeft.height);
|
dy = _animation.getProgress(topLeft.height);
|
||||||
}
|
drawFigure(buf, rc, _cup.currentFigure, dy, 0);
|
||||||
drawFigure(buf, rc, _currentFigure, dy, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// draw next figure
|
||||||
if (_nextFigure.index != 0) {
|
if (!_cup._nextFigure.empty) {
|
||||||
//auto shape = _nextFigure.shape;
|
//auto shape = _nextFigure.shape;
|
||||||
uint nextFigureAlpha = 0;
|
uint nextFigureAlpha = 0;
|
||||||
if (_state == CupState.NewFigure) {
|
if (_state == CupState.NewFigure) {
|
||||||
nextFigureAlpha = _animation.progress;
|
nextFigureAlpha = _animation.progress;
|
||||||
drawFigure(buf, rc, _currentFigure, 0, 255 - nextFigureAlpha);
|
drawFigure(buf, rc, _cup.currentFigure, 0, 255 - nextFigureAlpha);
|
||||||
}
|
}
|
||||||
if (_state != CupState.GameOver) {
|
if (_state != CupState.GameOver) {
|
||||||
drawFigure(buf, rc, _nextFigure, 0, blendAlpha(0xA0, nextFigureAlpha));
|
drawFigure(buf, rc, _cup.nextFigure, 0, blendAlpha(0xA0, nextFigureAlpha));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -571,17 +590,21 @@ class CupWidget : Widget {
|
||||||
measuredContent(parentWidth, parentHeight, 350, 550);
|
measuredContent(parentWidth, parentHeight, 350, 550);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@property bool falling() {
|
||||||
|
return _state == CupState.FallingFigure;
|
||||||
|
}
|
||||||
|
|
||||||
/// override to handle specific actions
|
/// override to handle specific actions
|
||||||
override bool handleAction(const Action a) {
|
override bool handleAction(const Action a) {
|
||||||
switch (a.id) {
|
switch (a.id) {
|
||||||
case TetrisAction.MoveLeft:
|
case TetrisAction.MoveLeft:
|
||||||
move(-1);
|
_cup.move(-1, 0, falling);
|
||||||
return true;
|
return true;
|
||||||
case TetrisAction.MoveRight:
|
case TetrisAction.MoveRight:
|
||||||
move(1);
|
_cup.move(1, 0, falling);
|
||||||
return true;
|
return true;
|
||||||
case TetrisAction.RotateCCW:
|
case TetrisAction.RotateCCW:
|
||||||
rotate(1);
|
_cup.rotate(1, falling);
|
||||||
return true;
|
return true;
|
||||||
case TetrisAction.FastDown:
|
case TetrisAction.FastDown:
|
||||||
handleFastDown(true);
|
handleFastDown(true);
|
||||||
|
@ -596,7 +619,8 @@ class CupWidget : Widget {
|
||||||
void newGame() {
|
void newGame() {
|
||||||
setLevel(1);
|
setLevel(1);
|
||||||
init(_cols, _rows);
|
init(_cols, _rows);
|
||||||
dropNextFigure();
|
_cup.dropNextFigure();
|
||||||
|
setCupState(CupState.NewFigure, 100, 255);
|
||||||
if (window && _gameOverPopup) {
|
if (window && _gameOverPopup) {
|
||||||
window.removePopup(_gameOverPopup);
|
window.removePopup(_gameOverPopup);
|
||||||
_gameOverPopup = null;
|
_gameOverPopup = null;
|
||||||
|
|
Loading…
Reference in New Issue