remove unneeded static import to try to help user

This commit is contained in:
Adam D. Ruppe 2017-03-22 08:58:51 -04:00
parent d503ac5011
commit fe3cca9e83
1 changed files with 399 additions and 134 deletions

View File

@ -1,8 +1,3 @@
// Please note when compiling on Win64, you need to explicitly list
// `-Lgdi32.lib -Luser32.lib` on the build command. If you want the Windows
// subsystem too, use `-L/subsystem:windows -L/entry:mainCRTStartup`
//
// On Mac, when compiling with X11, you need XQuartz and -L-L/usr/X11R6/lib passed to dmd.
/*
FIXME:
@ -58,6 +53,31 @@
and may add new features and fix bugs, but It do not expect to
significantly change the API. It has been stable a few years already now.
Installation_instructions:
`simpledisplay.d` does not have any dependencies outside the
operating system and `color.d`, so it should just work most the
time, but there are a few caveats on some systems:
Please note when compiling on Win64, you need to explicitly list
`-Lgdi32.lib -Luser32.lib` on the build command. If you want the Windows
subsystem too, use `-L/subsystem:windows -L/entry:mainCRTStartup`.
On Win32, you can pass `-L/subsystem:windows` if you don't want a
console to be automatically allocated.
On Mac, when compiling with X11, you need XQuartz and -L-L/usr/X11R6/lib passed to dmd.
On Ubuntu, you might need to install X11 development libraries to
successfully link.
$(CONSOLE
$ sudo apt-get install libglc-dev
$ sudo apt-get install libx11-dev
)
Jump_list:
Don't worry, you don't have to read this whole documentation file!
@ -108,7 +128,7 @@
import std.conv;
void main() {
auto window = new SimpleWindow(Size(500, 500), "My D App");
auto window = new SimpleWindow(Size(500, 500), "Event example - simpledisplay.d");
int y = 0;
@ -148,126 +168,6 @@
}
---
$(H3 Pong-example)
This program creates a little Pong-like game. Player one is controlled
with the keyboard. Player two is controlled with the mouse. It demos
the pulse timer, event handling, and some basic drawing.
---
// dmd example.d simpledisplay.d color.d
import arsd.simpledisplay;
enum paddleMovementSpeed = 8;
enum paddleHeight = 48;
void main() {
auto window = new SimpleWindow(600, 400, "Pong game!");
int playerOnePosition, playerTwoPosition;
int playerOneMovement, playerTwoMovement;
int playerOneScore, playerTwoScore;
int ballX, ballY;
int ballDx, ballDy;
void serve() {
import std.random;
ballX = window.width / 2;
ballY = window.height / 2;
ballDx = uniform(-4, 4) * 3;
ballDy = uniform(-4, 4) * 3;
if(ballDx == 0)
ballDx = uniform(0, 2) == 0 ? 3 : -3;
}
serve();
window.eventLoop(50, // set a 50 ms timer pulls
// This runs once per timer pulse
delegate () {
auto painter = window.draw();
painter.clear();
// Update everyone's motion
playerOnePosition += playerOneMovement;
playerTwoPosition += playerTwoMovement;
ballX += ballDx;
ballY += ballDy;
// Bounce off the top and bottom edges of the window
if(ballY + 7 >= window.height)
ballDy = -ballDy;
if(ballY - 8 <= 0)
ballDy = -ballDy;
// Bounce off the paddle, if it is in position
if(ballX - 8 <= 16) {
if(ballY + 7 > playerOnePosition && ballY - 8 < playerOnePosition + paddleHeight) {
ballDx = -ballDx + 1; // add some speed to keep it interesting
ballDy += playerOneMovement; // and y movement based on your controls too
ballX = 24; // move it past the paddle so it doesn't wiggle inside
} else {
// Missed it
playerTwoScore ++;
serve();
}
}
if(ballX + 7 >= window.width - 16) { // do the same thing but for player 1
if(ballY + 7 > playerTwoPosition && ballY - 8 < playerTwoPosition + paddleHeight) {
ballDx = -ballDx - 1;
ballDy += playerTwoMovement;
ballX = window.width - 24;
} else {
// Missed it
playerOneScore ++;
serve();
}
}
// Draw the paddles
painter.outlineColor = Color.black;
painter.drawLine(Point(16, playerOnePosition), Point(16, playerOnePosition + paddleHeight));
painter.drawLine(Point(window.width - 16, playerTwoPosition), Point(window.width - 16, playerTwoPosition + paddleHeight));
// Draw the ball
painter.fillColor = Color.red;
painter.outlineColor = Color.yellow;
painter.drawEllipse(Point(ballX - 8, ballY - 8), Point(ballX + 7, ballY + 7));
// Draw the score
painter.outlineColor = Color.blue;
import std.conv;
painter.drawText(Point(64, 4), to!string(playerOneScore));
painter.drawText(Point(window.width - 64, 4), to!string(playerTwoScore));
},
delegate (KeyEvent event) {
// Player 1's controls are the arrow keys on the keyboard
if(event.key == Key.Down)
playerOneMovement = event.pressed ? paddleMovementSpeed : 0;
if(event.key == Key.Up)
playerOneMovement = event.pressed ? -paddleMovementSpeed : 0;
},
delegate (MouseEvent event) {
// Player 2's controls are mouse movement while the left button is held down
if(event.type == MouseEventType.motion && (event.modifierState & ModifierState.leftButtonDown)) {
if(event.dy > 0)
playerTwoMovement = paddleMovementSpeed;
else if(event.dy < 0)
playerTwoMovement = -paddleMovementSpeed;
} else {
playerTwoMovement = 0;
}
}
);
}
---
If you are interested in more game writing with D, check out my gamehelpers.d which builds upon simpledisplay, and its other stand-alone support modules, simpleaudio.d and joystick.d, too.
This program displays a pie chart. Clicking on a color will increase its share of the pie.
@ -515,6 +415,347 @@
+/
module arsd.simpledisplay;
// FIXME: tetris demo
// FIXME: space invaders demo
// FIXME: asteroids demo
/++ $(ID Pong-example)
$(H3 Pong)
This program creates a little Pong-like game. Player one is controlled
with the keyboard. Player two is controlled with the mouse. It demos
the pulse timer, event handling, and some basic drawing.
+/
unittest {
// dmd example.d simpledisplay.d color.d
import arsd.simpledisplay;
enum paddleMovementSpeed = 8;
enum paddleHeight = 48;
void main() {
auto window = new SimpleWindow(600, 400, "Pong game!");
int playerOnePosition, playerTwoPosition;
int playerOneMovement, playerTwoMovement;
int playerOneScore, playerTwoScore;
int ballX, ballY;
int ballDx, ballDy;
void serve() {
import std.random;
ballX = window.width / 2;
ballY = window.height / 2;
ballDx = uniform(-4, 4) * 3;
ballDy = uniform(-4, 4) * 3;
if(ballDx == 0)
ballDx = uniform(0, 2) == 0 ? 3 : -3;
}
serve();
window.eventLoop(50, // set a 50 ms timer pulls
// This runs once per timer pulse
delegate () {
auto painter = window.draw();
painter.clear();
// Update everyone's motion
playerOnePosition += playerOneMovement;
playerTwoPosition += playerTwoMovement;
ballX += ballDx;
ballY += ballDy;
// Bounce off the top and bottom edges of the window
if(ballY + 7 >= window.height)
ballDy = -ballDy;
if(ballY - 8 <= 0)
ballDy = -ballDy;
// Bounce off the paddle, if it is in position
if(ballX - 8 <= 16) {
if(ballY + 7 > playerOnePosition && ballY - 8 < playerOnePosition + paddleHeight) {
ballDx = -ballDx + 1; // add some speed to keep it interesting
ballDy += playerOneMovement; // and y movement based on your controls too
ballX = 24; // move it past the paddle so it doesn't wiggle inside
} else {
// Missed it
playerTwoScore ++;
serve();
}
}
if(ballX + 7 >= window.width - 16) { // do the same thing but for player 1
if(ballY + 7 > playerTwoPosition && ballY - 8 < playerTwoPosition + paddleHeight) {
ballDx = -ballDx - 1;
ballDy += playerTwoMovement;
ballX = window.width - 24;
} else {
// Missed it
playerOneScore ++;
serve();
}
}
// Draw the paddles
painter.outlineColor = Color.black;
painter.drawLine(Point(16, playerOnePosition), Point(16, playerOnePosition + paddleHeight));
painter.drawLine(Point(window.width - 16, playerTwoPosition), Point(window.width - 16, playerTwoPosition + paddleHeight));
// Draw the ball
painter.fillColor = Color.red;
painter.outlineColor = Color.yellow;
painter.drawEllipse(Point(ballX - 8, ballY - 8), Point(ballX + 7, ballY + 7));
// Draw the score
painter.outlineColor = Color.blue;
import std.conv;
painter.drawText(Point(64, 4), to!string(playerOneScore));
painter.drawText(Point(window.width - 64, 4), to!string(playerTwoScore));
},
delegate (KeyEvent event) {
// Player 1's controls are the arrow keys on the keyboard
if(event.key == Key.Down)
playerOneMovement = event.pressed ? paddleMovementSpeed : 0;
if(event.key == Key.Up)
playerOneMovement = event.pressed ? -paddleMovementSpeed : 0;
},
delegate (MouseEvent event) {
// Player 2's controls are mouse movement while the left button is held down
if(event.type == MouseEventType.motion && (event.modifierState & ModifierState.leftButtonDown)) {
if(event.dy > 0)
playerTwoMovement = paddleMovementSpeed;
else if(event.dy < 0)
playerTwoMovement = -paddleMovementSpeed;
} else {
playerTwoMovement = 0;
}
}
);
}
}
/++ $(ID example-minesweeper)
This minesweeper demo shows how we can implement another classic
game with simpledisplay and shows some mouse input and basic output
code.
+/
unittest {
import arsd.simpledisplay;
enum GameSquare {
mine = 0,
clear,
m1, m2, m3, m4, m5, m6, m7, m8
}
enum UserSquare {
unknown,
revealed,
flagged,
questioned
}
enum GameState {
inProgress,
lose,
win
}
GameSquare[] board;
UserSquare[] userState;
GameState gameState;
int boardWidth;
int boardHeight;
bool isMine(int x, int y) {
if(x < 0 || y < 0 || x >= boardWidth || y >= boardHeight)
return false;
return board[y * boardWidth + x] == GameSquare.mine;
}
GameState reveal(int x, int y) {
if(board[y * boardWidth + x] == GameSquare.clear) {
floodFill(userState, boardWidth, boardHeight,
UserSquare.unknown, UserSquare.revealed,
x, y,
(x, y) {
if(board[y * boardWidth + x] == GameSquare.clear)
return true;
else {
userState[y * boardWidth + x] = UserSquare.revealed;
return false;
}
});
} else {
userState[y * boardWidth + x] = UserSquare.revealed;
if(isMine(x, y))
return GameState.lose;
}
foreach(state; userState) {
if(state == UserSquare.unknown || state == UserSquare.questioned)
return GameState.inProgress;
}
return GameState.win;
}
void initializeBoard(int width, int height, int numberOfMines) {
boardWidth = width;
boardHeight = height;
board.length = width * height;
userState.length = width * height;
userState[] = UserSquare.unknown;
import std.algorithm, std.random, std.range;
board[] = GameSquare.clear;
foreach(minePosition; randomSample(iota(0, board.length), numberOfMines))
board[minePosition] = GameSquare.mine;
int x;
int y;
foreach(idx, ref square; board) {
if(square == GameSquare.clear) {
int danger = 0;
danger += isMine(x-1, y-1)?1:0;
danger += isMine(x-1, y)?1:0;
danger += isMine(x-1, y+1)?1:0;
danger += isMine(x, y-1)?1:0;
danger += isMine(x, y+1)?1:0;
danger += isMine(x+1, y-1)?1:0;
danger += isMine(x+1, y)?1:0;
danger += isMine(x+1, y+1)?1:0;
square = cast(GameSquare) (danger + 1);
}
x++;
if(x == width) {
x = 0;
y++;
}
}
}
void redraw(SimpleWindow window) {
import std.conv;
auto painter = window.draw();
painter.clear();
final switch(gameState) with(GameState) {
case inProgress:
break;
case win:
painter.fillColor = Color.green;
painter.drawRectangle(Point(0, 0), window.width, window.height);
return;
case lose:
painter.fillColor = Color.red;
painter.drawRectangle(Point(0, 0), window.width, window.height);
return;
}
int x = 0;
int y = 0;
foreach(idx, square; board) {
auto state = userState[idx];
final switch(state) with(UserSquare) {
case unknown:
painter.outlineColor = Color.black;
painter.fillColor = Color(128,128,128);
painter.drawRectangle(
Point(x * 20, y * 20),
20, 20
);
break;
case revealed:
if(square == GameSquare.clear) {
painter.outlineColor = Color.white;
painter.fillColor = Color.white;
painter.drawRectangle(
Point(x * 20, y * 20),
20, 20
);
} else {
painter.outlineColor = Color.black;
painter.fillColor = Color.white;
painter.drawText(
Point(x * 20, y * 20),
to!string(square)[1..2],
Point(x * 20 + 20, y * 20 + 20),
TextAlignment.Center | TextAlignment.VerticalCenter);
}
break;
case flagged:
painter.outlineColor = Color.black;
painter.fillColor = Color.red;
painter.drawRectangle(
Point(x * 20, y * 20),
20, 20
);
break;
case questioned:
painter.outlineColor = Color.black;
painter.fillColor = Color.yellow;
painter.drawRectangle(
Point(x * 20, y * 20),
20, 20
);
break;
}
x++;
if(x == boardWidth) {
x = 0;
y++;
}
}
}
void main() {
auto window = new SimpleWindow(200, 200);
initializeBoard(10, 10, 10);
redraw(window);
window.eventLoop(0,
delegate (MouseEvent me) {
if(me.type != MouseEventType.buttonPressed)
return;
auto x = me.x / 20;
auto y = me.y / 20;
if(x >= 0 && x < boardWidth && y >= 0 && y < boardHeight) {
if(me.button == MouseButton.left) {
gameState = reveal(x, y);
} else {
userState[y*boardWidth+x] = UserSquare.flagged;
}
redraw(window);
}
}
);
}
}
version(Windows) {
import core.sys.windows.windows;
static import gdi = core.sys.windows.wingdi;
@ -1681,22 +1922,22 @@ class Timer {
} else version(linux) {
static import ep = core.sys.linux.epoll;
static import tfd = core.sys.linux.timerfd;
import core.sys.linux.timerfd;
fd = tfd.timerfd_create(tfd.CLOCK_MONOTONIC, 0);
fd = timerfd_create(CLOCK_MONOTONIC, 0);
if(fd == -1)
throw new Exception("timer create failed");
mapping[fd] = this;
tfd.itimerspec value;
itimerspec value;
value.it_value.tv_sec = cast(int) (intervalInMilliseconds / 1000);
value.it_value.tv_nsec = (intervalInMilliseconds % 1000) * 1000_000;
value.it_interval.tv_sec = cast(int) (intervalInMilliseconds / 1000);
value.it_interval.tv_nsec = (intervalInMilliseconds % 1000) * 1000_000;
if(tfd.timerfd_settime(fd, 0, &value, null) == -1)
if(timerfd_settime(fd, 0, &value, null) == -1)
throw new Exception("couldn't make pulse timer");
version(with_eventloop) {
@ -2815,6 +3056,30 @@ enum MouseEventType : int {
// FIXME: mouse move should be distinct from presses+releases, so we can avoid subscribing to those events in X unnecessarily
/++
Listen for this on your event listeners if you are interested in mouse action.
Note that [button] is used on mouse press and release events. If you are curious about which button is being held in during motion, use [modifierState] and check the bitmask for [ModifierState.leftButtonDown], etc.
Examples:
This will draw boxes on the window with the mouse as you hold the left button.
---
import arsd.simpledisplay;
void main() {
auto window = new SimpleWindow();
window.eventLoop(0,
(MouseEvent ev) {
if(ev.modifierState & ModifierState.leftButtonDown) {
auto painter = window.draw();
painter.fillColor = Color.red;
painter.outlineColor = Color.black;
painter.drawRectangle(Point(ev.x / 16 * 16, ev.y / 16 * 16), 16, 16);
}
}
);
}
---
+/
struct MouseEvent {
MouseEventType type; /// movement, press, release, double click. See [MouseEventType]
@ -6203,7 +6468,7 @@ version(X11) {
static import unix = core.sys.posix.unistd;
static import err = core.stdc.errno;
static import tfd = core.sys.linux.timerfd;
import core.sys.linux.timerfd;
prepareEventLoop();
ep.epoll_event[16] events = void;
@ -6226,18 +6491,18 @@ version(X11) {
}
if(pulseTimeout) {
pulseFd = tfd.timerfd_create(tfd.CLOCK_MONOTONIC, 0);
pulseFd = timerfd_create(CLOCK_MONOTONIC, 0);
if(pulseFd == -1)
throw new Exception("pulse timer create failed");
tfd.itimerspec value;
itimerspec value;
value.it_value.tv_sec = cast(int) (pulseTimeout / 1000);
value.it_value.tv_nsec = (pulseTimeout % 1000) * 1000_000;
value.it_interval.tv_sec = cast(int) (pulseTimeout / 1000);
value.it_interval.tv_nsec = (pulseTimeout % 1000) * 1000_000;
if(tfd.timerfd_settime(pulseFd, 0, &value, null) == -1)
if(timerfd_settime(pulseFd, 0, &value, null) == -1)
throw new Exception("couldn't make pulse timer");
ep.epoll_event ev = void;