Implement touch controls

This commit is contained in:
Xavier Del Campo Romero 2022-03-30 08:36:16 +02:00
parent 82c61e3d1d
commit 45337576df
9 changed files with 177 additions and 18 deletions

View File

@ -1,3 +1,3 @@
add_library(camera "src/camera.c" "src/pad.c" "src/mouse.c")
add_library(camera "src/camera.c" "src/pad.c" "src/mouse.c" "src/touch.c")
target_include_directories(camera PUBLIC "inc" PRIVATE "privinc")
target_link_libraries(camera PUBLIC container mouse pad terrain util PRIVATE gfx)

View File

@ -35,6 +35,7 @@ extern struct sprite cursor_sprite;
void camera_update_pad(struct camera *cam, const struct pad *p);
void camera_update_mouse(struct camera *cam, const struct mouse *m);
bool camera_update_touch(struct camera *cam, const struct mouse *m);
bool camera_translate(const struct camera *cam, const struct util_rect *dim, short *x, short *y);
void cursor_init(struct cursor *c);
bool cursor_collision(const struct camera *cam, const struct util_rect *d);

57
src/camera/src/touch.c Normal file
View File

@ -0,0 +1,57 @@
#include <camera.h>
#include <mouse.h>
#include <camera_private.h>
#include <gfx.h>
static void cursor_update(struct cursor *const c, const struct mouse *const m)
{
if (c->screen.last_w != screen_w
|| c->screen.last_h != screen_h)
cursor_init(c);
c->x = m->x;
c->y = m->y;
}
static bool update_speed(struct camera *const cam, const struct mouse *const m)
{
bool ret = false;
int *const sx = &cam->x_speed, *const sy = &cam->y_speed;
if (mouse_pressed(m, MOUSE_BUTTON_LEFT))
{
*sx = m->dx;
*sy = m->dy;
ret = *sx || *sy;
}
else if (*sx || *sy)
{
const int qx = *sx / 4;
if (qx)
*sx -= qx;
else
*sx = 0;
const int qy = *sy / 4;
if (qy)
*sy -= qy;
else
*sy = 0;
}
return ret;
}
bool camera_update_touch(struct camera *const cam, const struct mouse *const m)
{
bool ret;
cursor_update(&cam->cursor, m);
ret = update_speed(cam, m);
camera_update_pos(cam);
return ret;
}

View File

@ -26,7 +26,7 @@ int game(void)
{
const struct human_player_cfg cfg =
{
.sel_periph = HUMAN_PLAYER_PERIPH_KEYBOARD_MOUSE,
.sel_periph = HUMAN_PLAYER_PERIPH_TOUCH,
.padn = i,
.pl =
{
@ -86,8 +86,7 @@ int game(void)
terrain_update(&map);
if (terrain_render(&map, &h->cam)
|| human_player_render(h, &o)
|| cursor_render(&h->cam.cursor))
|| human_player_render(h, &o))
goto end;
/* TODO: render AI players. */

View File

@ -16,12 +16,13 @@ enum mouse_button
struct mouse
{
short x, y;
short x, y, dx, dy;
int mask, oldmask;
};
void mouse_init(struct mouse *m);
void mouse_update(struct mouse *m);
bool mouse_pressed(const struct mouse *m, enum mouse_button b);
bool mouse_justpressed(const struct mouse *m, enum mouse_button b);
bool mouse_justreleased(const struct mouse *m, enum mouse_button b);

View File

@ -39,6 +39,7 @@ static void mouse_event(const SDL_MouseMotionEvent *const ev,
void mouse_update(struct mouse *const m)
{
const short x = m->x, y = m->y;
SDL_Event ev;
int n;
@ -71,6 +72,9 @@ void mouse_update(struct mouse *const m)
}
}
m->dx = m->x - x;
m->dy = m->y - y;
end:
if (n < 0)

View File

@ -1,6 +1,11 @@
#include <mouse.h>
#include <stdbool.h>
bool mouse_pressed(const struct mouse *const m, const enum mouse_button b)
{
return m->mask & (1 << b);
}
bool mouse_justpressed(const struct mouse *const m,
const enum mouse_button b)
{

View File

@ -22,6 +22,7 @@ struct human_player_cfg
enum human_player_periph
{
HUMAN_PLAYER_PERIPH_PAD,
HUMAN_PLAYER_PERIPH_TOUCH,
HUMAN_PLAYER_PERIPH_KEYBOARD_MOUSE
} sel_periph;
@ -39,10 +40,12 @@ struct human_player
{
struct pad pad;
struct
struct human_player_kbm
{
struct mouse mouse;
struct keyboard keyboard;
bool long_press, pan;
unsigned int lp_t;
} kbm;
} periph;

View File

@ -207,15 +207,33 @@ static bool select_resources(struct human_player *const h, const short x,
}
static bool select_instances(struct human_player *const h,
const struct player_others *const o, const bool excl)
const struct player_others *const o, const bool excl,
const bool same_type)
{
unsigned long x, y;
cursor_pos(&h->cam, &x, &y);
return select_buildings(h, x, y, excl)
|| select_units(h, x, y, excl)
|| select_resources(h, x, y, o, excl);
if (!same_type || !h->n_sel)
return select_buildings(h, x, y, excl)
|| select_units(h, x, y, excl)
|| select_resources(h, x, y, o, excl);
else
{
switch (h->sel->type)
{
case INSTANCE_TYPE_UNIT:
return select_units(h, x, y, excl);
case INSTANCE_TYPE_BUILDING:
return select_buildings(h, x, y, excl);
case INSTANCE_TYPE_RESOURCE:
select_resources(h, x, y, o, excl);
}
}
return false;
}
static bool instance_collision(const struct camera *const cam,
@ -518,7 +536,7 @@ static bool update_from_pad(struct human_player *const h,
|| pad_justpressed(p, PAD_KEY_EXIT))
ret = true;
else if (pad_justpressed(p, PAD_KEY_A))
select_instances(h, o, false);
select_instances(h, o, false, false);
else if (pad_justpressed(p, PAD_KEY_B))
move_units(h, o);
else if (pad_justpressed(p, PAD_KEY_C))
@ -529,10 +547,59 @@ static bool update_from_pad(struct human_player *const h,
return ret;
}
static bool update_keyboard_mouse_common(const struct mouse *const m,
const struct keyboard *const k)
{
bool ret = false;
if (keyboard_justreleased(k, &KEYBOARD_COMBO(KEYBOARD_KEY_EXIT)))
ret = true;
else if (keyboard_justreleased(k, &KEYBOARD_COMBO(KEYBOARD_KEY_F11)))
gfx_toggle_fullscreen();
return ret;
}
static bool update_from_touch(struct human_player *const h,
struct player_others *const o)
{
struct mouse *const m = &h->periph.kbm.mouse;
struct keyboard *const k = &h->periph.kbm.keyboard;
mouse_update(m);
keyboard_update(k);
enum {DEAD_ZONE = 5};
struct human_player_kbm *const kbm = &h->periph.kbm;
if (mouse_pressed(m, MOUSE_BUTTON_LEFT) && !kbm->pan)
{
enum {LONG_PRESS_THRESHOLD = 30};
if (kbm->lp_t < LONG_PRESS_THRESHOLD)
kbm->lp_t++;
else if (!kbm->long_press)
{
kbm->long_press = true;
deselect_instances(h);
}
}
else if (mouse_justreleased(m, MOUSE_BUTTON_LEFT))
{
if (!kbm->pan && !select_instances(h, o, false, true))
move_units(h, o);
kbm->pan = false;
kbm->long_press = false;
kbm->lp_t = 0;
}
return update_keyboard_mouse_common(m, k);
}
static bool update_from_keyboard_mouse(struct human_player *const h,
struct player_others *const o)
{
bool ret = false;
struct mouse *const m = &h->periph.kbm.mouse;
struct keyboard *const k = &h->periph.kbm.keyboard;
@ -545,17 +612,13 @@ static bool update_from_keyboard_mouse(struct human_player *const h,
keyboard_pressed(k, &KEYBOARD_COMBO(KEYBOARD_KEY_LSHIFT))
|| keyboard_pressed(k, &KEYBOARD_COMBO(KEYBOARD_KEY_RSHIFT));
if (!select_instances(h, o, !shift_pressed))
if (!select_instances(h, o, !shift_pressed, false))
deselect_instances(h);
}
else if (mouse_justreleased(m, MOUSE_BUTTON_RIGHT))
move_units(h, o);
else if (keyboard_justreleased(k, &KEYBOARD_COMBO(KEYBOARD_KEY_EXIT)))
ret = true;
else if (keyboard_justreleased(k, &KEYBOARD_COMBO(KEYBOARD_KEY_F11)))
gfx_toggle_fullscreen();
return ret;
return update_keyboard_mouse_common(m, k);
}
bool human_player_update(struct human_player *const h,
@ -577,6 +640,15 @@ bool human_player_update(struct human_player *const h,
camera_update_pad(&h->cam, &h->periph.pad);
break;
case HUMAN_PLAYER_PERIPH_TOUCH:
{
struct human_player_kbm *const kbm = &h->periph.kbm;
ret = update_from_touch(h, o);
kbm->pan |= camera_update_touch(&h->cam, &kbm->mouse);
}
break;
case HUMAN_PLAYER_PERIPH_KEYBOARD_MOUSE:
ret = update_from_keyboard_mouse(h, o);
camera_update_mouse(&h->cam, &h->periph.kbm.mouse);
@ -659,6 +731,21 @@ int human_player_render(const struct human_player *const h,
|| gui_render(h))
return -1;
switch (h->sel_periph)
{
case HUMAN_PLAYER_PERIPH_PAD:
/* Fall through. */
case HUMAN_PLAYER_PERIPH_KEYBOARD_MOUSE:
cursor_render(&h->cam.cursor);
break;
case HUMAN_PLAYER_PERIPH_TOUCH:
break;
default:
return -1;
}
return 0;
}
@ -672,6 +759,8 @@ int human_player_init(const struct human_player_cfg *const cfg,
switch (h->sel_periph = cfg->sel_periph)
{
case HUMAN_PLAYER_PERIPH_TOUCH:
/* Fall through. */
case HUMAN_PLAYER_PERIPH_KEYBOARD_MOUSE:
mouse_init(&h->periph.kbm.mouse);
keyboard_init(&h->periph.kbm.keyboard);