Add cursor support
This commit is contained in:
14
game/input.h
14
game/input.h
@@ -17,7 +17,7 @@ typedef enum InputType {
|
|||||||
|
|
||||||
#define MOUSE_BUTTON_COUNT (MOUSE_BUTTON_BACK + 1)
|
#define MOUSE_BUTTON_COUNT (MOUSE_BUTTON_BACK + 1)
|
||||||
|
|
||||||
#define CLICK_LIMIT 0.2f
|
#define CLICK_LIMIT 0.12f
|
||||||
#define BUTTON_COUNT (MOUSE_BUTTON_BACK + 1)
|
#define BUTTON_COUNT (MOUSE_BUTTON_BACK + 1)
|
||||||
|
|
||||||
typedef struct InputMapping {
|
typedef struct InputMapping {
|
||||||
@@ -41,6 +41,11 @@ typedef struct InputState {
|
|||||||
Vector2 mouse;
|
Vector2 mouse;
|
||||||
Vector2 mouseWorld;
|
Vector2 mouseWorld;
|
||||||
f32 mouseDownElapsed[BUTTON_COUNT];
|
f32 mouseDownElapsed[BUTTON_COUNT];
|
||||||
|
enum {
|
||||||
|
CURSOR_NONE,
|
||||||
|
CURSOR_COLLECT_WOOD,
|
||||||
|
} cursor;
|
||||||
|
|
||||||
// INPUT_BUILDING
|
// INPUT_BUILDING
|
||||||
int building;
|
int building;
|
||||||
bool buildingCanPlace;
|
bool buildingCanPlace;
|
||||||
@@ -49,6 +54,11 @@ typedef struct InputState {
|
|||||||
// SELECTED_UNITS
|
// SELECTED_UNITS
|
||||||
Rectangle pickArea;
|
Rectangle pickArea;
|
||||||
|
|
||||||
|
|
||||||
|
// SELECTED_OBJECT
|
||||||
|
// SELECTED_BUILDING
|
||||||
|
|
||||||
|
// Other
|
||||||
struct {
|
struct {
|
||||||
/* Selected units
|
/* Selected units
|
||||||
* 1: Position
|
* 1: Position
|
||||||
@@ -58,8 +68,6 @@ typedef struct InputState {
|
|||||||
ecs_query_t *selected;
|
ecs_query_t *selected;
|
||||||
//ecs_query_t *selectedBuilding;
|
//ecs_query_t *selectedBuilding;
|
||||||
} queries;
|
} queries;
|
||||||
// SELECTED_OBJECT
|
|
||||||
// SELECTED_BUILDING
|
|
||||||
} InputState;
|
} InputState;
|
||||||
|
|
||||||
static InputMapping inputDefaultMapping() {
|
static InputMapping inputDefaultMapping() {
|
||||||
|
|||||||
@@ -224,7 +224,7 @@ void render(float dt, void *userData) {
|
|||||||
|
|
||||||
bzTileMapDraw(&game->map);
|
bzTileMapDraw(&game->map);
|
||||||
|
|
||||||
drawPlayerInputUI();
|
drawPlayerInputUIGround();
|
||||||
|
|
||||||
ecs_progress(ECS, dt);
|
ecs_progress(ECS, dt);
|
||||||
ecs_enable(ECS, renderDebugPathSystem, game->debugDraw.path);
|
ecs_enable(ECS, renderDebugPathSystem, game->debugDraw.path);
|
||||||
@@ -234,6 +234,8 @@ void render(float dt, void *userData) {
|
|||||||
if (game->debugDraw.spatialGrid)
|
if (game->debugDraw.spatialGrid)
|
||||||
bzSpatialGridDrawDebugGrid(game->entityGrid);
|
bzSpatialGridDrawDebugGrid(game->entityGrid);
|
||||||
|
|
||||||
|
drawPlayerInputUI();
|
||||||
|
|
||||||
EndMode2D();
|
EndMode2D();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -114,7 +114,14 @@ void renderDebugPath(ecs_iter_t *it);
|
|||||||
void updatePlayerInput();
|
void updatePlayerInput();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Task:
|
* Task (rendering above ground):
|
||||||
|
* 0: Game (singleton)
|
||||||
|
* 0: InputState (singleton)
|
||||||
|
*/
|
||||||
|
void drawPlayerInputUIGround();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Task (rendering on top):
|
||||||
* 0: Game (singleton)
|
* 0: Game (singleton)
|
||||||
* 0: InputState (singleton)
|
* 0: InputState (singleton)
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -20,6 +20,12 @@ static void iterRemovePaths(ecs_entity_t entity, Position *pos, Size *size);
|
|||||||
|
|
||||||
void placeUnits(i32 numUnits, f32 unitSpacing, Vector2 start, Vector2 end, BzTileMap *map, Vector2 **outPlaces);
|
void placeUnits(i32 numUnits, f32 unitSpacing, Vector2 start, Vector2 end, BzTileMap *map, Vector2 **outPlaces);
|
||||||
|
|
||||||
|
void resetInputState(InputState *input) {
|
||||||
|
input->cursor = CURSOR_NONE;
|
||||||
|
input->state = INPUT_NONE;
|
||||||
|
input->building = 0;
|
||||||
|
}
|
||||||
|
|
||||||
void inputPrimaryAction(Game *game, InputState *input) {
|
void inputPrimaryAction(Game *game, InputState *input) {
|
||||||
const MouseButton primaryBtn = input->mapping.primaryBtn;
|
const MouseButton primaryBtn = input->mapping.primaryBtn;
|
||||||
if (isInputBtnDragged(input, primaryBtn)) {
|
if (isInputBtnDragged(input, primaryBtn)) {
|
||||||
@@ -40,22 +46,26 @@ void inputPrimaryAction(Game *game, InputState *input) {
|
|||||||
}
|
}
|
||||||
i32 selectedCount = ecs_query_entity_count(input->queries.selected);
|
i32 selectedCount = ecs_query_entity_count(input->queries.selected);
|
||||||
if (isInputBtnJustDragged(input, primaryBtn) && selectedCount > 0) {
|
if (isInputBtnJustDragged(input, primaryBtn) && selectedCount > 0) {
|
||||||
|
resetInputState(input);
|
||||||
input->state = INPUT_SELECTED_UNITS;
|
input->state = INPUT_SELECTED_UNITS;
|
||||||
} else if (isInputBtnJustUp(input, primaryBtn)) {
|
} else if (isInputBtnJustUp(input, primaryBtn)) {
|
||||||
if (pickEntity(game->entityGrid, input->mouseDownWorld, Unit)) {
|
if (pickEntity(game->entityGrid, input->mouseDownWorld, Unit)) {
|
||||||
|
resetInputState(input);
|
||||||
input->state = INPUT_SELECTED_UNITS;
|
input->state = INPUT_SELECTED_UNITS;
|
||||||
} else if (pickEntity(game->entityGrid, input->mouseDownWorld, Harvestable)) {
|
} else if (pickEntity(game->entityGrid, input->mouseDownWorld, Harvestable)) {
|
||||||
|
resetInputState(input);
|
||||||
input->state = INPUT_SELECTED_OBJECT;
|
input->state = INPUT_SELECTED_OBJECT;
|
||||||
} else if (pickEntity(game->entityGrid, input->mouseDownWorld, Buildable)) {
|
} else if (pickEntity(game->entityGrid, input->mouseDownWorld, Buildable)) {
|
||||||
|
resetInputState(input);
|
||||||
input->state = INPUT_SELECTED_BUILDING;
|
input->state = INPUT_SELECTED_BUILDING;
|
||||||
}
|
}
|
||||||
selectedCount = ecs_query_entity_count(input->queries.selected);
|
selectedCount = ecs_query_entity_count(input->queries.selected);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (selectedCount == 0)
|
if (selectedCount == 0)
|
||||||
input->state = INPUT_NONE;
|
resetInputState(input);
|
||||||
}
|
}
|
||||||
void inputUnitAction(Game *game, const InputState *input) {
|
void inputUnitAction(Game *game, InputState *input) {
|
||||||
ecs_query_t *query = input->queries.selected;
|
ecs_query_t *query = input->queries.selected;
|
||||||
BzTileMap *map = &game->map;
|
BzTileMap *map = &game->map;
|
||||||
const i32 numUnits = ecs_query_entity_count(query);
|
const i32 numUnits = ecs_query_entity_count(query);
|
||||||
@@ -63,6 +73,14 @@ void inputUnitAction(Game *game, const InputState *input) {
|
|||||||
|
|
||||||
const MouseButton actionBtn = input->mapping.secondaryBtn;
|
const MouseButton actionBtn = input->mapping.secondaryBtn;
|
||||||
|
|
||||||
|
input->cursor = CURSOR_NONE;
|
||||||
|
if (queryEntity(game->entityGrid, input->mouseWorld, Harvestable)) {
|
||||||
|
input->cursor = CURSOR_COLLECT_WOOD;
|
||||||
|
if (isInputBtnJustUp(input, actionBtn)) {
|
||||||
|
bzLogInfo("Chop wood!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (isInputBtnJustDown(input, actionBtn)) {
|
if (isInputBtnJustDown(input, actionBtn)) {
|
||||||
// Note: We mustn't use ecs ecs_remove_all since this will also
|
// Note: We mustn't use ecs ecs_remove_all since this will also
|
||||||
// remove ongoing paths that are not part of this query.
|
// remove ongoing paths that are not part of this query.
|
||||||
@@ -120,8 +138,7 @@ void updatePlayerInput() {
|
|||||||
|
|
||||||
if (IsKeyPressed(input->mapping.backBtn)) {
|
if (IsKeyPressed(input->mapping.backBtn)) {
|
||||||
ecs_remove_all(ECS, Selected);
|
ecs_remove_all(ECS, Selected);
|
||||||
input->state = INPUT_NONE;
|
resetInputState(input);
|
||||||
input->building = 0;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -241,29 +258,21 @@ void updatePlayerInput() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void drawPlayerInputUI() {
|
void drawPlayerInputUIGround() {
|
||||||
Game *game = ecs_singleton_get_mut(ECS, Game);
|
const Game *game = ecs_singleton_get_mut(ECS, Game);
|
||||||
InputState *input = ecs_singleton_get_mut(ECS, InputState);
|
const InputState *input = ecs_singleton_get_mut(ECS, InputState);
|
||||||
BzTileMap *map = &game->map;
|
|
||||||
|
|
||||||
const MouseButton primaryBtn = input->mapping.primaryBtn;
|
const MouseButton primaryBtn = input->mapping.primaryBtn;
|
||||||
const MouseButton secondaryBtn = input->mapping.secondaryBtn;
|
|
||||||
|
|
||||||
i32 selectedUnitCount = ecs_count_id(ECS, Selected);
|
const i32 selectedUnitCount = ecs_count_id(ECS, Selected);
|
||||||
switch (input->state) {
|
switch (input->state) {
|
||||||
case INPUT_NONE:
|
|
||||||
if (isInputBtnDragged(input, primaryBtn)) {
|
|
||||||
Rectangle area = input->pickArea;
|
|
||||||
DrawRectangleLines(area.x, area.y, area.width, area.height, RED);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case INPUT_BUILDING: {
|
case INPUT_BUILDING: {
|
||||||
Color placeColor = input->buildingCanPlace ?
|
const Color placeColor = input->buildingCanPlace ?
|
||||||
(Color) {0, 255, 0, 200} :
|
(Color) {0, 255, 0, 200} :
|
||||||
(Color) {255, 0, 0, 200};
|
(Color) {255, 0, 0, 200};
|
||||||
|
|
||||||
BzTile width = game->map.tileWidth;
|
const BzTile width = game->map.tileWidth;
|
||||||
BzTile height = game->map.tileHeight;
|
const BzTile height = game->map.tileHeight;
|
||||||
DrawRectangleLines(input->buildingPos.x * width,
|
DrawRectangleLines(input->buildingPos.x * width,
|
||||||
input->buildingPos.y * height,
|
input->buildingPos.y * height,
|
||||||
input->buildingSize.sizeX * width,
|
input->buildingSize.sizeX * width,
|
||||||
@@ -287,25 +296,9 @@ void drawPlayerInputUI() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
Rectangle area = {input->mouseWorld.x, input->mouseWorld.y, 1, 1};
|
|
||||||
DrawCircle(area.x, area.y, 4.0f, BLUE);
|
|
||||||
|
|
||||||
BzSpatialGridIter it = bzSpatialGridIter(game->entityGrid, area.x, area.y, area.width, area.height);
|
|
||||||
while (bzSpatialGridQueryNext(&it)) {
|
|
||||||
ecs_entity_t entity = 0;
|
|
||||||
|
|
||||||
BzSpatialGrid *grid = game->entityGrid;
|
|
||||||
Vector2 point = input->mouseWorld;
|
|
||||||
|
|
||||||
|
|
||||||
if ((entity = queryEntity(grid, point, Harvestable))) {
|
|
||||||
DrawText("Collect resources", point.x, point.y, 10.0f, RED);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
default: break;
|
||||||
}
|
}
|
||||||
ecs_iter_t it = ecs_query_iter(ECS, input->queries.selected);
|
ecs_iter_t it = ecs_query_iter(ECS, input->queries.selected);
|
||||||
rlSetLineWidth(2.0f);
|
rlSetLineWidth(2.0f);
|
||||||
@@ -323,6 +316,30 @@ void drawPlayerInputUI() {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void drawPlayerInputUI() {
|
||||||
|
const Game *game = ecs_singleton_get_mut(ECS, Game);
|
||||||
|
const InputState *input = ecs_singleton_get_mut(ECS, InputState);
|
||||||
|
|
||||||
|
const MouseButton primaryBtn = input->mapping.primaryBtn;
|
||||||
|
|
||||||
|
if (isInputBtnDragged(input, primaryBtn)) {
|
||||||
|
const Rectangle area = input->pickArea;
|
||||||
|
DrawRectangleLines(area.x, area.y, area.width, area.height, RED);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (input->cursor) {
|
||||||
|
case CURSOR_COLLECT_WOOD: {
|
||||||
|
const Vector2 point = input->mouseWorld;
|
||||||
|
DrawCircle(point.x, point.y, 2.0f, RED);
|
||||||
|
DrawText("Collect wood", point.x, point.y, 10.0f, RED);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
Rectangle calculateEntityBounds(Position pos, Size size) {
|
Rectangle calculateEntityBounds(Position pos, Size size) {
|
||||||
return (Rectangle) {
|
return (Rectangle) {
|
||||||
pos.x - size.x * 0.5f,
|
pos.x - size.x * 0.5f,
|
||||||
|
|||||||
Reference in New Issue
Block a user