Mouse-based interface for Cube: you left-click anywhere on the grid

and it moves the polyhedron in the general direction of the mouse
pointer. (I had this in my initial throwaway Python implementation
of this game, but never reimplemented it in this version. It's
harder with triangles, but not too much harder.)

Since the logical-to-physical coordinate mapping in Cube is
dynamically computed, this has involved an interface change which
touches all puzzles: make_move() is now passed a pointer to the
game_drawstate, which it may of course completely ignore if it
wishes.

[originally from svn r5877]
This commit is contained in:
Simon Tatham
2005-05-31 11:43:51 +00:00
parent 4a3c26ff14
commit caee305b47
13 changed files with 94 additions and 33 deletions

80
cube.c
View File

@ -11,6 +11,8 @@
#include "puzzles.h"
#define PI 3.14159265358979323846264338327950884197169399
#define MAXVERTICES 20
#define MAXFACES 20
#define MAXORDER 4
@ -1002,7 +1004,11 @@ static void free_ui(game_ui *ui)
{
}
static game_state *make_move(game_state *from, game_ui *ui,
struct game_drawstate {
int ox, oy; /* pixel position of float origin */
};
static game_state *make_move(game_state *from, game_ui *ui, game_drawstate *ds,
int x, int y, int button)
{
int direction;
@ -1016,7 +1022,9 @@ static game_state *make_move(game_state *from, game_ui *ui,
button = button & (~MOD_MASK | MOD_NUM_KEYPAD);
/*
* All moves are made with the cursor keys or numeric keypad.
* Moves can be made with the cursor keys or numeric keypad, or
* alternatively you can left-click and the polyhedron will
* move in the general direction of the mouse pointer.
*/
if (button == CURSOR_UP || button == (MOD_NUM_KEYPAD | '8'))
direction = UP;
@ -1034,7 +1042,69 @@ static game_state *make_move(game_state *from, game_ui *ui,
direction = UP_RIGHT;
else if (button == (MOD_NUM_KEYPAD | '3'))
direction = DOWN_RIGHT;
else
else if (button == LEFT_BUTTON) {
/*
* Find the bearing of the click point from the current
* square's centre.
*/
int cx, cy;
double angle;
cx = from->squares[from->current].x * GRID_SCALE + ds->ox;
cy = from->squares[from->current].y * GRID_SCALE + ds->oy;
if (x == cx && y == cy)
return NULL; /* clicked in exact centre! */
angle = atan2(y - cy, x - cx);
/*
* There are three possibilities.
*
* - This square is a square, so we choose between UP,
* DOWN, LEFT and RIGHT by dividing the available angle
* at the 45-degree points.
*
* - This square is an up-pointing triangle, so we choose
* between DOWN, LEFT and RIGHT by dividing into
* 120-degree arcs.
*
* - This square is a down-pointing triangle, so we choose
* between UP, LEFT and RIGHT in the inverse manner.
*
* Don't forget that since our y-coordinates increase
* downwards, `angle' is measured _clockwise_ from the
* x-axis, not anticlockwise as most mathematicians would
* instinctively assume.
*/
if (from->squares[from->current].npoints == 4) {
/* Square. */
if (fabs(angle) > 3*PI/4)
direction = LEFT;
else if (fabs(angle) < PI/4)
direction = RIGHT;
else if (angle > 0)
direction = DOWN;
else
direction = UP;
} else if (from->squares[from->current].directions[UP] == 0) {
/* Up-pointing triangle. */
if (angle < -PI/2 || angle > 5*PI/6)
direction = LEFT;
else if (angle > PI/6)
direction = DOWN;
else
direction = RIGHT;
} else {
/* Down-pointing triangle. */
assert(from->squares[from->current].directions[DOWN] == 0);
if (angle > PI/2 || angle < -5*PI/6)
direction = LEFT;
else if (angle < -PI/6)
direction = UP;
else
direction = RIGHT;
}
} else
return NULL;
/*
@ -1288,10 +1358,6 @@ struct bbox {
float l, r, u, d;
};
struct game_drawstate {
int ox, oy; /* pixel position of float origin */
};
static void find_bbox_callback(void *ctx, struct grid_square *sq)
{
struct bbox *bb = (struct bbox *)ctx;

View File

@ -450,9 +450,8 @@ static void free_ui(game_ui *ui)
{
}
static game_state *make_move(game_state *from, game_ui *ui,
int x, int y, int button)
{
static game_state *make_move(game_state *from, game_ui *ui, game_drawstate *ds,
int x, int y, int button) {
int gx, gy, dx, dy, ux, uy, up, p;
game_state *ret;

View File

@ -325,7 +325,7 @@ static int midend_really_process_key(midend_data *me, int x, int y, int button)
} else {
game_state *s =
me->ourgame->make_move(me->states[me->statepos-1].state,
me->ui, x, y, button);
me->ui, me->drawstate, x, y, button);
if (s == me->states[me->statepos-1].state) {
/*

View File

@ -2229,8 +2229,8 @@ static void free_ui(game_ui *ui)
sfree(ui);
}
static game_state *make_move(game_state *from, game_ui *ui, int x, int y,
int button)
static game_state *make_move(game_state *from, game_ui *ui, game_drawstate *ds,
int x, int y, int button)
{
game_state *ret;
int cx, cy;

3
net.c
View File

@ -1798,8 +1798,7 @@ static void free_ui(game_ui *ui)
* Process a move.
*/
static game_state *make_move(game_state *state, game_ui *ui,
int x, int y, int button)
{
game_drawstate *ds, int x, int y, int button) {
game_state *ret, *nullret;
int tx, ty, orig;
int shift = button & MOD_SHFT, ctrl = button & MOD_CTRL;

View File

@ -1051,7 +1051,7 @@ static void slide_col(game_state *state, int dir, int col)
}
static game_state *make_move(game_state *state, game_ui *ui,
int x, int y, int button)
game_drawstate *ds, int x, int y, int button)
{
int cx, cy;
int n, dx, dy;

View File

@ -142,8 +142,8 @@ static void free_ui(game_ui *ui)
{
}
static game_state *make_move(game_state *from, game_ui *ui, int x, int y,
int button)
static game_state *make_move(game_state *from, game_ui *ui, game_drawstate *ds,
int x, int y, int button)
{
return NULL;
}

View File

@ -764,9 +764,8 @@ static void free_ui(game_ui *ui)
sfree(ui);
}
static game_state *make_move(game_state *from, game_ui *ui,
int x, int y, int button)
{
static game_state *make_move(game_state *from, game_ui *ui, game_drawstate *ds,
int x, int y, int button) {
game_state *ret;
button &= ~MOD_MASK;

View File

@ -227,8 +227,8 @@ struct game {
char *(*text_format)(game_state *state);
game_ui *(*new_ui)(game_state *state);
void (*free_ui)(game_ui *ui);
game_state *(*make_move)(game_state *from, game_ui *ui, int x, int y,
int button);
game_state *(*make_move)(game_state *from, game_ui *ui, game_drawstate *ds,
int x, int y, int button);
void (*size)(game_params *params, int *x, int *y);
float *(*colours)(frontend *fe, game_state *state, int *ncolours);
game_drawstate *(*new_drawstate)(game_state *state);

5
rect.c
View File

@ -2178,9 +2178,8 @@ static void ui_draw_rect(game_state *state, game_ui *ui,
}
}
static game_state *make_move(game_state *from, game_ui *ui,
int x, int y, int button)
{
static game_state *make_move(game_state *from, game_ui *ui, game_drawstate *ds,
int x, int y, int button) {
int xc, yc;
int startdrag = FALSE, enddrag = FALSE, active = FALSE;
game_state *ret;

View File

@ -577,9 +577,8 @@ static void free_ui(game_ui *ui)
{
}
static game_state *make_move(game_state *from, game_ui *ui,
int x, int y, int button)
{
static game_state *make_move(game_state *from, game_ui *ui, game_drawstate *ds,
int x, int y, int button) {
int cx, cy;
int dx, dy, tx, ty, n;
game_state *ret;

4
solo.c
View File

@ -1821,8 +1821,8 @@ static void free_ui(game_ui *ui)
sfree(ui);
}
static game_state *make_move(game_state *from, game_ui *ui, int x, int y,
int button)
static game_state *make_move(game_state *from, game_ui *ui, game_drawstate *ds,
int x, int y, int button)
{
int c = from->c, r = from->r, cr = c*r;
int tx, ty;

View File

@ -618,8 +618,8 @@ static void free_ui(game_ui *ui)
{
}
static game_state *make_move(game_state *from, game_ui *ui, int x, int y,
int button)
static game_state *make_move(game_state *from, game_ui *ui, game_drawstate *ds,
int x, int y, int button)
{
int w = from->w, h = from->h, n = from->n, wh = w*h;
game_state *ret;