mirror of https://github.com/buggins/dlangui.git
Tetris example improvements
This commit is contained in:
parent
af5a631051
commit
a77a20e6e7
|
@ -1,14 +1,29 @@
|
||||||
module gui;
|
module gui;
|
||||||
|
|
||||||
import dlangui.all;
|
|
||||||
import dlangui.widgets.popup;
|
|
||||||
import dlangui.graphics.drawbuf;
|
|
||||||
//import std.stdio;
|
|
||||||
import std.conv;
|
|
||||||
import std.utf;
|
|
||||||
import model;
|
import model;
|
||||||
|
|
||||||
|
import dlangui.all;
|
||||||
|
|
||||||
|
/// game action codes
|
||||||
|
enum TetrisAction : int {
|
||||||
|
MoveLeft = 10000,
|
||||||
|
MoveRight,
|
||||||
|
RotateCCW,
|
||||||
|
FastDown,
|
||||||
|
Pause,
|
||||||
|
LevelUp,
|
||||||
|
}
|
||||||
|
|
||||||
|
const Action ACTION_MOVE_LEFT = (new Action(TetrisAction.MoveLeft, KeyCode.LEFT)).addAccelerator(KeyCode.KEY_A);
|
||||||
|
const Action ACTION_MOVE_RIGHT = (new Action(TetrisAction.MoveRight, KeyCode.RIGHT)).addAccelerator(KeyCode.KEY_D);
|
||||||
|
const Action ACTION_ROTATE = (new Action(TetrisAction.RotateCCW, KeyCode.UP)).addAccelerator(KeyCode.KEY_W);
|
||||||
|
const Action ACTION_FAST_DOWN = (new Action(TetrisAction.FastDown, KeyCode.SPACE)).addAccelerator(KeyCode.KEY_S);
|
||||||
|
const Action ACTION_PAUSE = (new Action(TetrisAction.Pause, KeyCode.ESCAPE)).addAccelerator(KeyCode.PAUSE);
|
||||||
|
const Action ACTION_LEVEL_UP = (new Action(TetrisAction.LevelUp, KeyCode.ADD)).addAccelerator(KeyCode.INS);
|
||||||
|
|
||||||
|
const Action[] CUP_ACTIONS = [ACTION_MOVE_LEFT, ACTION_MOVE_RIGHT, ACTION_ROTATE, ACTION_FAST_DOWN, ACTION_PAUSE, ACTION_LEVEL_UP];
|
||||||
|
|
||||||
|
/// about dialog
|
||||||
Widget createAboutWidget()
|
Widget createAboutWidget()
|
||||||
{
|
{
|
||||||
LinearLayout res = new VerticalLayout();
|
LinearLayout res = new VerticalLayout();
|
||||||
|
@ -26,16 +41,24 @@ Widget createAboutWidget()
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum TetrisAction : int {
|
/// Cup States
|
||||||
MoveLeft = 10000,
|
enum CupState : int {
|
||||||
MoveRight,
|
/// New figure appears
|
||||||
RotateCCW,
|
NewFigure,
|
||||||
FastDown,
|
/// Game is paused
|
||||||
Pause,
|
Paused,
|
||||||
LevelUp,
|
/// Figure is falling
|
||||||
|
FallingFigure,
|
||||||
|
/// Figure is hanging - pause between falling by one row
|
||||||
|
HangingFigure,
|
||||||
|
/// destroying complete rows
|
||||||
|
DestroyingRows,
|
||||||
|
/// falling after some rows were destroyed
|
||||||
|
FallingRows,
|
||||||
|
/// Game is over
|
||||||
|
GameOver,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Cup widget
|
/// Cup widget
|
||||||
class CupWidget : Widget {
|
class CupWidget : Widget {
|
||||||
/// cup columns count
|
/// cup columns count
|
||||||
|
@ -54,37 +77,21 @@ class CupWidget : Widget {
|
||||||
long _movementDuration;
|
long _movementDuration;
|
||||||
/// When true, figure is falling down fast
|
/// When true, figure is falling down fast
|
||||||
bool _fastDownFlag;
|
bool _fastDownFlag;
|
||||||
|
/// animation helper for fade and movement in different states
|
||||||
AnimationHelper _animation;
|
AnimationHelper _animation;
|
||||||
|
/// GameOver popup
|
||||||
private PopupWidget _gameOverPopup;
|
private PopupWidget _gameOverPopup;
|
||||||
|
/// Status widget
|
||||||
/// Cup States
|
private StatusWidget _status;
|
||||||
enum CupState : int {
|
/// Current state
|
||||||
/// New figure appears
|
|
||||||
NewFigure,
|
|
||||||
/// Game is paused
|
|
||||||
Paused,
|
|
||||||
/// Figure is falling
|
|
||||||
FallingFigure,
|
|
||||||
/// Figure is hanging - pause between falling by one row
|
|
||||||
HangingFigure,
|
|
||||||
/// destroying complete rows
|
|
||||||
DestroyingRows,
|
|
||||||
/// falling after some rows were destroyed
|
|
||||||
FallingRows,
|
|
||||||
/// Game is over
|
|
||||||
GameOver,
|
|
||||||
}
|
|
||||||
|
|
||||||
protected CupState _state;
|
protected CupState _state;
|
||||||
|
|
||||||
|
protected int _totalRowsDestroyed;
|
||||||
|
|
||||||
static const int[10] LEVEL_SPEED = [15000000, 10000000, 7000000, 6000000, 5000000, 4000000, 3500000, 3000000, 2500000, 2000000];
|
static const int[10] LEVEL_SPEED = [15000000, 10000000, 7000000, 6000000, 5000000, 4000000, 3500000, 3000000, 2500000, 2000000];
|
||||||
|
|
||||||
|
|
||||||
static const int RESERVED_ROWS = 5; // reserved for next figure
|
static const int RESERVED_ROWS = 5; // reserved for next figure
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// set difficulty level 1..10
|
/// set difficulty level 1..10
|
||||||
void setLevel(int level) {
|
void setLevel(int level) {
|
||||||
_level = level;
|
_level = level;
|
||||||
|
@ -93,8 +100,10 @@ class CupWidget : Widget {
|
||||||
}
|
}
|
||||||
|
|
||||||
static const int MIN_FAST_FALLING_INTERVAL = 600000;
|
static const int MIN_FAST_FALLING_INTERVAL = 600000;
|
||||||
static const int ROWS_FALLING_INTERVAL = 600000;
|
|
||||||
|
|
||||||
|
static const int ROWS_FALLING_INTERVAL = 1200000;
|
||||||
|
|
||||||
|
/// change game state, init state animation when necessary
|
||||||
void setCupState(CupState state) {
|
void setCupState(CupState state) {
|
||||||
int animationIntervalPercent = 100;
|
int animationIntervalPercent = 100;
|
||||||
switch (state) {
|
switch (state) {
|
||||||
|
@ -114,6 +123,8 @@ class CupWidget : Widget {
|
||||||
animationIntervalPercent = 50;
|
animationIntervalPercent = 50;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
// no animation for other states
|
||||||
|
animationIntervalPercent = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
_state = state;
|
_state = state;
|
||||||
|
@ -128,18 +139,14 @@ class CupWidget : Widget {
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// returns true is widget is being animated - need to call animate() and redraw
|
void addScore(int score) {
|
||||||
override @property bool animating() {
|
_score += score;
|
||||||
switch (_state) {
|
_status.setScore(_score);
|
||||||
case CupState.NewFigure:
|
}
|
||||||
case CupState.FallingFigure:
|
|
||||||
case CupState.HangingFigure:
|
/// returns true if figure is in falling - movement state
|
||||||
case CupState.DestroyingRows:
|
@property bool falling() {
|
||||||
case CupState.FallingRows:
|
return _state == CupState.FallingFigure;
|
||||||
return true;
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Turn on / off fast falling down
|
/// Turn on / off fast falling down
|
||||||
|
@ -167,6 +174,8 @@ class CupWidget : Widget {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const int[] NEXT_LEVEL_SCORE = [0, 20, 50, 100, 200, 350, 500, 750, 1000, 1500, 2000];
|
||||||
|
|
||||||
/// try start next figure
|
/// try start next figure
|
||||||
protected void nextFigure() {
|
protected void nextFigure() {
|
||||||
if (!_cup.dropNextFigure()) {
|
if (!_cup.dropNextFigure()) {
|
||||||
|
@ -177,6 +186,8 @@ class CupWidget : Widget {
|
||||||
_gameOverPopup = window.showPopup(popupWidget, this);
|
_gameOverPopup = window.showPopup(popupWidget, this);
|
||||||
} else {
|
} else {
|
||||||
setCupState(CupState.NewFigure);
|
setCupState(CupState.NewFigure);
|
||||||
|
if (_level < 10 && _totalRowsDestroyed >= NEXT_LEVEL_SCORE[_level])
|
||||||
|
setLevel(_level + 1); // level up
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -214,6 +225,8 @@ class CupWidget : Widget {
|
||||||
break;
|
break;
|
||||||
case CupState.DestroyingRows:
|
case CupState.DestroyingRows:
|
||||||
int rowsDestroyed = _cup.destroyFullRows();
|
int rowsDestroyed = _cup.destroyFullRows();
|
||||||
|
_totalRowsDestroyed += rowsDestroyed;
|
||||||
|
_status.setRowsDestroyed(_totalRowsDestroyed);
|
||||||
int scorePerRow = 0;
|
int scorePerRow = 0;
|
||||||
for (int i = 0; i < rowsDestroyed; i++) {
|
for (int i = 0; i < rowsDestroyed; i++) {
|
||||||
scorePerRow += 10;
|
scorePerRow += 10;
|
||||||
|
@ -245,14 +258,23 @@ class CupWidget : Widget {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// animates window; interval is time left from previous draw, in hnsecs (1/10000000 of second)
|
/// start new game
|
||||||
override void animate(long interval) {
|
void newGame() {
|
||||||
_animation.animate(interval);
|
setLevel(1);
|
||||||
if (_animation.finished) {
|
init(_cols, _rows);
|
||||||
onAnimationFinished();
|
_cup.dropNextFigure();
|
||||||
|
setCupState(CupState.NewFigure);
|
||||||
|
if (window && _gameOverPopup) {
|
||||||
|
window.removePopup(_gameOverPopup);
|
||||||
|
_gameOverPopup = null;
|
||||||
}
|
}
|
||||||
|
_score = 0;
|
||||||
|
_status.setScore(0);
|
||||||
|
_totalRowsDestroyed = 0;
|
||||||
|
_status.setRowsDestroyed(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// init cup
|
||||||
void init(int cols, int rows) {
|
void init(int cols, int rows) {
|
||||||
_cup.init(cols, rows);
|
_cup.init(cols, rows);
|
||||||
_cols = cols;
|
_cols = cols;
|
||||||
|
@ -321,6 +343,31 @@ class CupWidget : Widget {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//=================================================================================================
|
||||||
|
// Overrides of Widget methods
|
||||||
|
|
||||||
|
/// returns true is widget is being animated - need to call animate() and redraw
|
||||||
|
override @property bool animating() {
|
||||||
|
switch (_state) {
|
||||||
|
case CupState.NewFigure:
|
||||||
|
case CupState.FallingFigure:
|
||||||
|
case CupState.HangingFigure:
|
||||||
|
case CupState.DestroyingRows:
|
||||||
|
case CupState.FallingRows:
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// animates window; interval is time left from previous draw, in hnsecs (1/10000000 of second)
|
||||||
|
override void animate(long interval) {
|
||||||
|
_animation.animate(interval);
|
||||||
|
if (_animation.finished) {
|
||||||
|
onAnimationFinished();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Draw widget at its position to buffer
|
/// Draw widget at its position to buffer
|
||||||
override void onDraw(DrawBuf buf) {
|
override void onDraw(DrawBuf buf) {
|
||||||
super.onDraw(buf);
|
super.onDraw(buf);
|
||||||
|
@ -387,15 +434,6 @@ class CupWidget : Widget {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
|
||||||
/// Measure widget according to desired width and height constraints. (Step 1 of two phase layout).
|
|
||||||
override void measure(int parentWidth, int parentHeight) {
|
|
||||||
/// fixed size 350 x 550
|
|
||||||
measuredContent(parentWidth, parentHeight, 350, 550);
|
|
||||||
}
|
|
||||||
|
|
||||||
@property bool falling() {
|
|
||||||
return _state == CupState.FallingFigure;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// override to handle specific actions
|
/// override to handle specific actions
|
||||||
|
@ -428,54 +466,30 @@ class CupWidget : Widget {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void addScore(int score) {
|
/// Measure widget according to desired width and height constraints. (Step 1 of two phase layout).
|
||||||
_score += score;
|
override void measure(int parentWidth, int parentHeight) {
|
||||||
_status.setScore(_score);
|
measuredContent(parentWidth, parentHeight, parentWidth * 3 / 5, parentHeight);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// start new game
|
|
||||||
void newGame() {
|
|
||||||
setLevel(1);
|
|
||||||
_score = 0;
|
|
||||||
init(_cols, _rows);
|
|
||||||
_cup.dropNextFigure();
|
|
||||||
setCupState(CupState.NewFigure);
|
|
||||||
if (window && _gameOverPopup) {
|
|
||||||
window.removePopup(_gameOverPopup);
|
|
||||||
_gameOverPopup = null;
|
|
||||||
}
|
|
||||||
_status.setScore(_score);
|
|
||||||
}
|
|
||||||
|
|
||||||
private StatusWidget _status;
|
|
||||||
this(StatusWidget status) {
|
this(StatusWidget status) {
|
||||||
super("CUP");
|
super("CUP");
|
||||||
this._status = status;
|
this._status = status;
|
||||||
layoutWidth(FILL_PARENT).layoutHeight(FILL_PARENT).layoutWeight(3);
|
layoutWidth(FILL_PARENT).layoutHeight(FILL_PARENT).layoutWeight(3).setState(State.Default).focusable(true).padding(Rect(20, 20, 20, 20));
|
||||||
setState(State.Default);
|
|
||||||
//backgroundColor = 0xC0808080;
|
_cols = 10;
|
||||||
padding(Rect(20, 20, 20, 20));
|
_rows = 18;
|
||||||
_cols = 11;
|
|
||||||
_rows = 15;
|
|
||||||
newGame();
|
newGame();
|
||||||
|
|
||||||
focusable = true;
|
focusable = true;
|
||||||
|
|
||||||
acceleratorMap.add( [
|
acceleratorMap.add(CUP_ACTIONS);
|
||||||
(new Action(TetrisAction.MoveLeft, KeyCode.LEFT)).addAccelerator(KeyCode.KEY_A),
|
|
||||||
(new Action(TetrisAction.MoveRight, KeyCode.RIGHT)).addAccelerator(KeyCode.KEY_D),
|
|
||||||
(new Action(TetrisAction.RotateCCW, KeyCode.UP)).addAccelerator(KeyCode.KEY_W),
|
|
||||||
(new Action(TetrisAction.FastDown, KeyCode.SPACE)).addAccelerator(KeyCode.KEY_S),
|
|
||||||
(new Action(TetrisAction.Pause, KeyCode.ESCAPE)).addAccelerator(KeyCode.PAUSE),
|
|
||||||
(new Action(TetrisAction.LevelUp, KeyCode.ADD)).addAccelerator(KeyCode.INS),
|
|
||||||
]);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Panel to show game status
|
/// Panel to show game status
|
||||||
class StatusWidget : VerticalLayout {
|
class StatusWidget : VerticalLayout {
|
||||||
private TextWidget _level;
|
private TextWidget _level;
|
||||||
|
private TextWidget _rowsDestroyed;
|
||||||
private TextWidget _score;
|
private TextWidget _score;
|
||||||
private CupWidget _cup;
|
private CupWidget _cup;
|
||||||
void setCup(CupWidget cup) {
|
void setCup(CupWidget cup) {
|
||||||
|
@ -483,26 +497,27 @@ class StatusWidget : VerticalLayout {
|
||||||
}
|
}
|
||||||
TextWidget createTextWidget(dstring str, uint color) {
|
TextWidget createTextWidget(dstring str, uint color) {
|
||||||
TextWidget res = new TextWidget(null, str);
|
TextWidget res = new TextWidget(null, str);
|
||||||
res.layoutWidth(FILL_PARENT).alignment(Align.Center);
|
res.layoutWidth(FILL_PARENT).alignment(Align.Center).fontSize(25).textColor(color);
|
||||||
res.fontSize(30);
|
|
||||||
res.textColor(color);
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
this() {
|
this() {
|
||||||
super("CUP_STATUS");
|
super("CUP_STATUS");
|
||||||
//backgroundColor = 0xC080FF80;
|
|
||||||
addChild(new VSpacer());
|
addChild(new VSpacer());
|
||||||
addChild(new ImageWidget(null, "tetris_logo_big"));
|
addChild((new ImageWidget(null, "tetris_logo_big")).layoutWidth(FILL_PARENT).alignment(Align.Center));
|
||||||
addChild(new VSpacer());
|
addChild(new VSpacer());
|
||||||
addChild(createTextWidget("Level:"d, 0x008000));
|
addChild(createTextWidget("Level:"d, 0x008000));
|
||||||
addChild((_level = createTextWidget(""d, 0x008000)));
|
addChild((_level = createTextWidget(""d, 0x008000)));
|
||||||
addChild(new VSpacer());
|
addChild(new VSpacer());
|
||||||
|
addChild(createTextWidget("Rows:"d, 0x202080));
|
||||||
|
addChild((_rowsDestroyed = createTextWidget(""d, 0x202080)));
|
||||||
|
addChild(new VSpacer());
|
||||||
addChild(createTextWidget("Score:"d, 0x800000));
|
addChild(createTextWidget("Score:"d, 0x800000));
|
||||||
addChild((_score = createTextWidget(""d, 0x800000)));
|
addChild((_score = createTextWidget(""d, 0x800000)));
|
||||||
addChild(new VSpacer());
|
addChild(new VSpacer());
|
||||||
addChild(new VSpacer());
|
addChild(new VSpacer());
|
||||||
layoutWidth(FILL_PARENT).layoutHeight(FILL_PARENT).layoutWeight(2);
|
|
||||||
padding(Rect(20, 20, 20, 20));
|
layoutWidth(FILL_PARENT).layoutHeight(FILL_PARENT).layoutWeight(2).padding(Rect(20, 20, 20, 20));
|
||||||
}
|
}
|
||||||
|
|
||||||
void setLevel(int level) {
|
void setLevel(int level) {
|
||||||
|
@ -513,17 +528,16 @@ class StatusWidget : VerticalLayout {
|
||||||
_score.text = toUTF32(to!string(score));
|
_score.text = toUTF32(to!string(score));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Measure widget according to desired width and height constraints. (Step 1 of two phase layout).
|
void setRowsDestroyed(int rows) {
|
||||||
override void measure(int parentWidth, int parentHeight) {
|
_rowsDestroyed.text = toUTF32(to!string(rows));
|
||||||
super.measure(parentWidth, parentHeight);
|
|
||||||
/// fixed size 350 x 550
|
|
||||||
measuredContent(parentWidth, parentHeight, 150, 550);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override bool handleAction(const Action a) {
|
override bool handleAction(const Action a) {
|
||||||
return _cup.handleAction(a);
|
return _cup.handleAction(a);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Cup page: cup widget + status widget
|
||||||
class CupPage : HorizontalLayout {
|
class CupPage : HorizontalLayout {
|
||||||
CupWidget _cup;
|
CupWidget _cup;
|
||||||
StatusWidget _status;
|
StatusWidget _status;
|
||||||
|
@ -539,13 +553,13 @@ class CupPage : HorizontalLayout {
|
||||||
/// Measure widget according to desired width and height constraints. (Step 1 of two phase layout).
|
/// Measure widget according to desired width and height constraints. (Step 1 of two phase layout).
|
||||||
override void measure(int parentWidth, int parentHeight) {
|
override void measure(int parentWidth, int parentHeight) {
|
||||||
super.measure(parentWidth, parentHeight);
|
super.measure(parentWidth, parentHeight);
|
||||||
/// fixed size 350 x 550
|
/// fixed size
|
||||||
measuredContent(parentWidth, parentHeight, 500, 550);
|
measuredContent(parentWidth, parentHeight, 550, 550);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//FrameLayout
|
//
|
||||||
class GameWidget : HorizontalLayout {
|
class GameWidget : FrameLayout {
|
||||||
|
|
||||||
CupPage _cupPage;
|
CupPage _cupPage;
|
||||||
this() {
|
this() {
|
||||||
|
@ -555,9 +569,4 @@ class GameWidget : HorizontalLayout {
|
||||||
//showChild(_cupPage.id, Visibility.Invisible, true);
|
//showChild(_cupPage.id, Visibility.Invisible, true);
|
||||||
backgroundImageId = "tx_fabric.tiled";
|
backgroundImageId = "tx_fabric.tiled";
|
||||||
}
|
}
|
||||||
/// Measure widget according to desired width and height constraints. (Step 1 of two phase layout).
|
|
||||||
override void measure(int parentWidth, int parentHeight) {
|
|
||||||
super.measure(parentWidth, parentHeight);
|
|
||||||
measuredContent(parentWidth, parentHeight, 500, 550);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,10 +19,9 @@ import dlangui.all;
|
||||||
import model;
|
import model;
|
||||||
import gui;
|
import gui;
|
||||||
|
|
||||||
|
/// Required for Windows platform: DMD cannot find WinMain if it's in library
|
||||||
mixin APP_ENTRY_POINT;
|
mixin APP_ENTRY_POINT;
|
||||||
|
|
||||||
|
|
||||||
/// entry point for dlangui based application
|
/// entry point for dlangui based application
|
||||||
extern (C) int UIAppMain(string[] args) {
|
extern (C) int UIAppMain(string[] args) {
|
||||||
|
|
||||||
|
@ -50,14 +49,10 @@ extern (C) int UIAppMain(string[] args) {
|
||||||
// load theme from file "theme_default.xml"
|
// load theme from file "theme_default.xml"
|
||||||
Platform.instance.uiTheme = "theme_default";
|
Platform.instance.uiTheme = "theme_default";
|
||||||
|
|
||||||
//drawableCache.get("tx_fabric.tiled");
|
|
||||||
|
|
||||||
// create window
|
// create window
|
||||||
Window window = Platform.instance.createWindow("DLangUI: Tetris game example", null, WindowFlag.Modal);
|
Window window = Platform.instance.createWindow("DLangUI: Tetris game example"d, null, WindowFlag.Modal);
|
||||||
|
|
||||||
GameWidget game = new GameWidget();
|
window.mainWidget = new GameWidget();
|
||||||
|
|
||||||
window.mainWidget = game;
|
|
||||||
|
|
||||||
window.windowIcon = drawableCache.getImage("dtetris-logo1");
|
window.windowIcon = drawableCache.getImage("dtetris-logo1");
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,28 @@ module model;
|
||||||
|
|
||||||
import std.random : uniform;
|
import std.random : uniform;
|
||||||
|
|
||||||
|
/// Cell codes
|
||||||
|
enum : int {
|
||||||
|
WALL = -1,
|
||||||
|
EMPTY = 0,
|
||||||
|
FIGURE1,
|
||||||
|
FIGURE2,
|
||||||
|
FIGURE3,
|
||||||
|
FIGURE4,
|
||||||
|
FIGURE5,
|
||||||
|
FIGURE6,
|
||||||
|
FIGURE7,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Orientations
|
||||||
|
enum : int {
|
||||||
|
ORIENTATION0,
|
||||||
|
ORIENTATION90,
|
||||||
|
ORIENTATION180,
|
||||||
|
ORIENTATION270
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Cell offset
|
/// Cell offset
|
||||||
struct FigureCell {
|
struct FigureCell {
|
||||||
// horizontal offset
|
// horizontal offset
|
||||||
|
@ -22,8 +44,9 @@ struct FigureShape {
|
||||||
int extent;
|
int extent;
|
||||||
/// upper y coordinate - initial Y offset to place figure to cup
|
/// upper y coordinate - initial Y offset to place figure to cup
|
||||||
int y0;
|
int y0;
|
||||||
this(int[2] c1, int[2] c2, int[2] c3, int[2] c4) {
|
/// Init cells (cell 0 is [0,0])
|
||||||
cells[0] = FigureCell(c1);
|
this(int[2] c2, int[2] c3, int[2] c4) {
|
||||||
|
cells[0] = FigureCell([0, 0]);
|
||||||
cells[1] = FigureCell(c2);
|
cells[1] = FigureCell(c2);
|
||||||
cells[2] = FigureCell(c3);
|
cells[2] = FigureCell(c3);
|
||||||
cells[3] = FigureCell(c4);
|
cells[3] = FigureCell(c4);
|
||||||
|
@ -37,6 +60,7 @@ struct FigureShape {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Figure data - shapes for 4 orientations
|
||||||
struct Figure {
|
struct Figure {
|
||||||
FigureShape[4] shapes; // by orientation
|
FigureShape[4] shapes; // by orientation
|
||||||
this(FigureShape[4] v) {
|
this(FigureShape[4] v) {
|
||||||
|
@ -44,71 +68,69 @@ struct Figure {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const Figure[6] FIGURES = [
|
/// All shapes
|
||||||
|
const Figure[7] FIGURES = [
|
||||||
|
// FIGURE1 ===========================================
|
||||||
// ## ####
|
// ## ####
|
||||||
// 00## 00##
|
// 00## 00##
|
||||||
// ##
|
// ##
|
||||||
Figure([FigureShape([0, 0], [1, 0], [1, 1], [0, -1]),
|
Figure([FigureShape([1, 0], [1, 1], [0, -1]),
|
||||||
FigureShape([0, 0], [0, 1], [-1, 1], [1, 0]),
|
FigureShape([0, 1], [-1, 1], [1, 0]),
|
||||||
FigureShape([0, 0], [1, 0], [1, 1], [0, -1]),
|
FigureShape([1, 0], [1, 1], [0, -1]),
|
||||||
FigureShape([0, 0], [0, 1], [-1, 1], [1, 0])]),
|
FigureShape([0, 1], [-1, 1], [1, 0])]),
|
||||||
|
// FIGURE2 ===========================================
|
||||||
// ## ####
|
// ## ####
|
||||||
// 00## ##00
|
// 00## ##00
|
||||||
// ##
|
// ##
|
||||||
Figure([FigureShape([0, 0], [1, 0], [0, 1], [1, 1]),
|
Figure([FigureShape([1, 0], [0, 1], [1, 1]),
|
||||||
FigureShape([0, 0], [0, 1], [1, 1], [-1, 0]),
|
FigureShape([0, 1], [1, 1], [-1, 0]),
|
||||||
FigureShape([0, 0], [1, 0], [0, 1], [1, 1]),
|
FigureShape([1, 0], [0, 1], [1, 1]),
|
||||||
FigureShape([0, 0], [0, 1], [1, 1], [-1, 0])]),
|
FigureShape([0, 1], [1, 1], [-1, 0])]),
|
||||||
|
// FIGURE3 ===========================================
|
||||||
// ## ## ####
|
// ## ## ####
|
||||||
// ##00## 00 ##00## 00
|
// ##00## 00 ##00## 00
|
||||||
// ## #### ##
|
// ## #### ##
|
||||||
Figure([FigureShape([0, 0], [1, 0], [-1,0], [-1,-1]),
|
Figure([FigureShape([1, 0], [-1,0], [-1,-1]),
|
||||||
FigureShape([0, 0], [0, 1], [0,-1], [ 1,-1]),
|
FigureShape([0, 1], [0,-1], [ 1,-1]),
|
||||||
FigureShape([0, 0], [1, 0], [-1,0], [1, 1]),
|
FigureShape([1, 0], [-1,0], [1, 1]),
|
||||||
FigureShape([0, 0], [0, 1], [-1,1], [0,-1])]),
|
FigureShape([0, 1], [-1,1], [0,-1])]),
|
||||||
|
// FIGURE4 ===========================================
|
||||||
// #### ## ##
|
// #### ## ##
|
||||||
// ##00## 00 ##00## 00
|
// ##00## 00 ##00## 00
|
||||||
// ## ## ####
|
// ## ## ####
|
||||||
Figure([FigureShape([0, 0], [1, 0], [-1,0], [ 1, 1]),
|
Figure([FigureShape([1, 0], [-1,0], [ 1,-1]),
|
||||||
FigureShape([0, 0], [0, 1], [0,-1], [ 1, 1]),
|
FigureShape([0, 1], [0,-1], [ 1, 1]),
|
||||||
FigureShape([0, 0], [1, 0], [-1,0], [-1, 1]),
|
FigureShape([1, 0], [-1,0], [-1, 1]),
|
||||||
FigureShape([0, 0], [0, 1], [-1,-1], [0, -1])]),
|
FigureShape([0, 1], [-1,-1], [0, -1])]),
|
||||||
|
// FIGURE5 ===========================================
|
||||||
// ####
|
// ####
|
||||||
// 00##
|
// 00##
|
||||||
//
|
//
|
||||||
Figure([FigureShape([0, 0], [1, 0], [0, 1], [ 1, 1]),
|
Figure([FigureShape([1, 0], [0, 1], [ 1, 1]),
|
||||||
FigureShape([0, 0], [1, 0], [0, 1], [ 1, 1]),
|
FigureShape([1, 0], [0, 1], [ 1, 1]),
|
||||||
FigureShape([0, 0], [1, 0], [0, 1], [ 1, 1]),
|
FigureShape([1, 0], [0, 1], [ 1, 1]),
|
||||||
FigureShape([0, 0], [1, 0], [0, 1], [ 1, 1])]),
|
FigureShape([1, 0], [0, 1], [ 1, 1])]),
|
||||||
|
// FIGURE6 ===========================================
|
||||||
// ##
|
// ##
|
||||||
// ##
|
// ##
|
||||||
// 00 ##00####
|
// 00 ##00####
|
||||||
// ##
|
// ##
|
||||||
Figure([FigureShape([0, 0], [0, 1], [0, 2], [ 0,-1]),
|
Figure([FigureShape([0, 1], [0, 2], [ 0,-1]),
|
||||||
FigureShape([0, 0], [1, 0], [2, 0], [-1, 0]),
|
FigureShape([1, 0], [2, 0], [-1, 0]),
|
||||||
FigureShape([0, 0], [0, 1], [0, 2], [ 0,-1]),
|
FigureShape([0, 1], [0, 2], [ 0,-1]),
|
||||||
FigureShape([0, 0], [1, 0], [2, 0], [-1, 0])]),
|
FigureShape([1, 0], [2, 0], [-1, 0])]),
|
||||||
|
// FIGURE7 ===========================================
|
||||||
|
// ## ## ##
|
||||||
|
// ##00## 00## ##00## ##00
|
||||||
|
// ## ## ##
|
||||||
|
Figure([FigureShape([1, 0], [-1,0], [ 0,-1]),
|
||||||
|
FigureShape([0, 1], [0,-1], [ 1, 0]),
|
||||||
|
FigureShape([1, 0], [-1,0], [ 0, 1]),
|
||||||
|
FigureShape([0, 1], [0,-1], [-1, 0])]),
|
||||||
];
|
];
|
||||||
|
|
||||||
enum : int {
|
/// colors for different figure types
|
||||||
WALL = -1,
|
const uint[7] _figureColors = [0xC00000, 0x80A000, 0xA00080, 0x0000C0, 0x800020, 0x408000, 0x204000];
|
||||||
EMPTY = 0,
|
|
||||||
FIGURE1,
|
|
||||||
FIGURE2,
|
|
||||||
FIGURE3,
|
|
||||||
FIGURE4,
|
|
||||||
FIGURE5,
|
|
||||||
FIGURE6,
|
|
||||||
}
|
|
||||||
|
|
||||||
enum : int {
|
|
||||||
ORIENTATION0,
|
|
||||||
ORIENTATION90,
|
|
||||||
ORIENTATION180,
|
|
||||||
ORIENTATION270
|
|
||||||
}
|
|
||||||
|
|
||||||
const uint[6] _figureColors = [0xFF0000, 0xA0A000, 0xA000A0, 0x0000FF, 0x800000, 0x408000];
|
|
||||||
|
|
||||||
/// Figure type, orientation and position container
|
/// Figure type, orientation and position container
|
||||||
struct FigurePosition {
|
struct FigurePosition {
|
||||||
|
@ -289,13 +311,15 @@ struct Cup {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// random next figure
|
||||||
void genNextFigure() {
|
void genNextFigure() {
|
||||||
_nextFigure.index = uniform(FIGURE1, FIGURE6 + 1);
|
_nextFigure.index = uniform(FIGURE1, FIGURE7 + 1);
|
||||||
_nextFigure.orientation = ORIENTATION0;
|
_nextFigure.orientation = ORIENTATION0;
|
||||||
_nextFigure.x = _cols / 2;
|
_nextFigure.x = _cols / 2;
|
||||||
_nextFigure.y = _rows - _nextFigure.shape.extent + 1;
|
_nextFigure.y = _rows - _nextFigure.shape.extent + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// New figure: put it on top of cup
|
||||||
bool dropNextFigure() {
|
bool dropNextFigure() {
|
||||||
if (_nextFigure.empty)
|
if (_nextFigure.empty)
|
||||||
genNextFigure();
|
genNextFigure();
|
||||||
|
@ -412,6 +436,7 @@ struct Cup {
|
||||||
return cellGroup(col, row) > 0;
|
return cellGroup(col, row) > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// returns true if next figure is generated
|
||||||
@property bool hasNextFigure() {
|
@property bool hasNextFigure() {
|
||||||
return !_nextFigure.empty;
|
return !_nextFigure.empty;
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,7 +48,8 @@ module dlangui.all;
|
||||||
|
|
||||||
public import dlangui.core.logger;
|
public import dlangui.core.logger;
|
||||||
public import dlangui.core.types;
|
public import dlangui.core.types;
|
||||||
public import dlangui.platforms.common.platform;
|
public import dlangui.core.i18n;
|
||||||
|
public import dlangui.core.files;
|
||||||
public import dlangui.graphics.images;
|
public import dlangui.graphics.images;
|
||||||
public import dlangui.widgets.widget;
|
public import dlangui.widgets.widget;
|
||||||
public import dlangui.widgets.controls;
|
public import dlangui.widgets.controls;
|
||||||
|
@ -61,6 +62,11 @@ public import dlangui.widgets.editors;
|
||||||
public import dlangui.widgets.grid;
|
public import dlangui.widgets.grid;
|
||||||
public import dlangui.widgets.tree;
|
public import dlangui.widgets.tree;
|
||||||
public import dlangui.widgets.combobox;
|
public import dlangui.widgets.combobox;
|
||||||
|
public import dlangui.widgets.popup;
|
||||||
public import dlangui.graphics.fonts;
|
public import dlangui.graphics.fonts;
|
||||||
public import dlangui.core.i18n;
|
public import dlangui.graphics.drawbuf;
|
||||||
public import dlangui.core.files;
|
public import dlangui.platforms.common.platform;
|
||||||
|
|
||||||
|
// some useful imports from Phobos
|
||||||
|
public import std.conv : to;
|
||||||
|
public import std.utf : toUTF32, toUTF8;
|
||||||
|
|
|
@ -140,6 +140,10 @@ class Action {
|
||||||
@property Accelerator[] accelerators() {
|
@property Accelerator[] accelerators() {
|
||||||
return _accelerators;
|
return _accelerators;
|
||||||
}
|
}
|
||||||
|
/// returs const array of accelerators
|
||||||
|
@property const(Accelerator)[] accelerators() const {
|
||||||
|
return _accelerators;
|
||||||
|
}
|
||||||
/// returns text description for first accelerator of action; null if no accelerators
|
/// returns text description for first accelerator of action; null if no accelerators
|
||||||
@property dstring acceleratorText() {
|
@property dstring acceleratorText() {
|
||||||
if (_accelerators.length < 1)
|
if (_accelerators.length < 1)
|
||||||
|
@ -217,6 +221,13 @@ struct ActionMap {
|
||||||
_map[acc] = a;
|
_map[acc] = a;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/// Add array of actions
|
||||||
|
void add(const Action[] items) {
|
||||||
|
foreach(a; items) {
|
||||||
|
foreach(acc; a.accelerators)
|
||||||
|
_map[acc] = a.clone;
|
||||||
|
}
|
||||||
|
}
|
||||||
/// Add action
|
/// Add action
|
||||||
void add(Action a) {
|
void add(Action a) {
|
||||||
foreach(acc; a.accelerators)
|
foreach(acc; a.accelerators)
|
||||||
|
|
Loading…
Reference in New Issue