Refactor entity input system

This commit is contained in:
2023-12-07 18:31:31 +01:00
parent 56a73fe28c
commit 85511812b5
3 changed files with 271 additions and 2 deletions

104
engine/tests/pan_test.c Normal file
View File

@@ -0,0 +1,104 @@
/*******************************************************************************************
*
* raylib [2D] example - world space panning
*
* Welcome to raylib!
*
* To test examples, just press F6 and execute raylib_compile_execute script
* Note that compiled executable is placed in the same folder as .c file
*
* You can find all basic examples on C:\raylib\raylib\examples folder or
* raylib official webpage: www.raylib.com
*
* Enjoy using raylib. :)
*
* This example has been created using raylib 3.5 (www.raylib.com)
* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details)
*
* Copyright (c) 2013-2016 Ramon Santamaria (@raysan5)
*
********************************************************************************************/
#include "raylib.h"
#include "raymath.h"
int main(void)
{
// Initialization
//--------------------------------------------------------------------------------------
const int screenWidth = 800;
const int screenHeight = 450;
InitWindow(screenWidth, screenHeight, "raylib [2d] example - world space panning");
Camera2D cam = { 0 };
cam.zoom = 1;
cam.offset.x = GetScreenWidth() / 2.0f;
cam.offset.y = GetScreenHeight() / 2.0f;
Vector2 prevMousePos = GetMousePosition();
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
//--------------------------------------------------------------------------------------
// Main game loop
while (!WindowShouldClose()) // Detect window close button or ESC key
{
float mouseDelta = GetMouseWheelMove();
float newZoom = cam.zoom + mouseDelta * 0.01f;
if (newZoom <= 0)
newZoom = 0.01f;
cam.zoom = newZoom;
Vector2 thisPos = GetMousePosition();
Vector2 delta = Vector2Subtract(prevMousePos, thisPos);
prevMousePos = thisPos;
if (IsMouseButtonDown(0))
cam.target = GetScreenToWorld2D(Vector2Add(cam.offset, delta),cam);
if (IsKeyPressed(KEY_LEFT))
cam.rotation += 10;
else if (IsKeyPressed(KEY_RIGHT))
cam.rotation -= 10;
BeginDrawing();
ClearBackground(RAYWHITE);
BeginMode2D(cam);
float size = 5000;
for (float i = -size; i <= size; i += 10)
{
DrawLine(i, -size, i, size, GRAY);
DrawLine(-size, i, size, i, GRAY);
}
DrawLine(-size, 0, size, 0, RED);
DrawLine(0, -size, 0, size, RED);
Vector2 mapGrid = GetScreenToWorld2D(GetMousePosition(), cam);
mapGrid.x = floorf(mapGrid.x / 10) * 10.0f;
mapGrid.y = floorf(mapGrid.y / 10) * 10.0f;
DrawRectangle(mapGrid.x, mapGrid.y, 10, 10, BLUE);
EndMode2D();
DrawText(TextFormat("%4.0f %4.0f", mapGrid.x, mapGrid.y),10, 10, 20, BLACK);
EndDrawing();
//----------------------------------------------------------------------------------
}
// De-Initialization
//--------------------------------------------------------------------------------------
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
return 0;
}

125
game/input.h Normal file
View File

@@ -0,0 +1,125 @@
#ifndef PIXELDEFENSE_GAME_INPUT_H
#define PIXELDEFENSE_GAME_INPUT_H
#include <breeze.h>
#include <flecs.h>
#include "components.h"
typedef enum InputType {
INPUT_NONE,
INPUT_BUILDING,
INPUT_SELECTED_UNITS,
INPUT_SELECTED_OBJECT,
INPUT_SELECTED_BUILDING,
} InputType;
#define MOUSE_BUTTON_COUNT (MOUSE_BUTTON_BACK + 1)
#define CLICK_LIMIT 0.2f
#define BUTTON_COUNT (MOUSE_BUTTON_BACK + 1)
typedef struct InputMapping {
MouseButton primaryBtn;
MouseButton secondaryBtn;
//MouseButton mmb;
MouseButton backBtn;
MouseButton moveLeft;
MouseButton moveRight;
MouseButton moveUp;
MouseButton moveDown;
} InputMapping;
typedef struct InputState {
InputType state;
InputMapping mapping;
// Common
Vector2 mouseDown;
Vector2 mouseDownWorld;
Vector2 mouse;
Vector2 mouseWorld;
f32 mouseDownElapsed[BUTTON_COUNT];
// INPUT_BUILDING
int building;
bool buildingCanPlace;
TilePosition buildingPos;
TileSize buildingSize;
// Units
Rectangle pickArea;
struct {
/* Selected units
* 1: Position
* 2: Size
* 3: UnitSelected
*/
ecs_query_t *selected;
//ecs_query_t *selectedBuilding;
} queries;
Position *unitPositions;
// SELECTED_OBJECT
// SELECTED_BUILDING
} InputState;
static InputMapping inputDefaultMapping() {
return (InputMapping) {
.primaryBtn = MOUSE_BUTTON_LEFT,
.secondaryBtn = MOUSE_BUTTON_RIGHT,
.backBtn = KEY_ESCAPE,
.moveLeft = KEY_W,
.moveRight = KEY_D,
.moveUp = KEY_UP,
.moveDown = KEY_S
};
}
static void updateInputState(InputState *state, const Camera2D camera, const f32 dt) {
for (i32 i = 0; i < BUTTON_COUNT; i++) {
f32 *elapsed = &state->mouseDownElapsed[i];
if (IsMouseButtonDown(i))
*elapsed += dt;
else if (IsMouseButtonUp(i) &&
!IsMouseButtonReleased(i))
*elapsed = 0;
}
const Vector2 mouse = GetMousePosition();
const Vector2 mouseWorld = GetScreenToWorld2D(mouse, camera);
if (IsMouseButtonPressed(state->mapping.primaryBtn) ||
IsMouseButtonPressed(state->mapping.secondaryBtn)) {
state->mouseDown = mouse;
state->mouseDownWorld = mouseWorld;
}
state->mouse = mouse;
state->mouseWorld = mouseWorld;
}
static bool isInputBtnDragged(const InputState *state, const MouseButton btn) {
return IsMouseButtonDown(btn) && state->mouseDownElapsed[btn] > CLICK_LIMIT;
}
static bool isInputBtnJustDragged(const InputState *state, const MouseButton btn) {
return IsMouseButtonReleased(btn) && state->mouseDownElapsed[btn] > CLICK_LIMIT;
}
static bool isInputBtnJustDown(const InputState *state, const MouseButton btn) {
BZ_UNUSED(state);
return IsMouseButtonPressed(btn);
}
static bool isInputBtnJustUp(const InputState *state, const MouseButton btn) {
return IsMouseButtonReleased(btn) && state->mouseDownElapsed[btn] <= CLICK_LIMIT;
}
static bool isInputBtnDown(const InputState *state, const MouseButton btn) {
BZ_UNUSED(state);
return IsMouseButtonDown(btn);
}
static bool isInputBtnUp(const InputState *state, const MouseButton btn) {
BZ_UNUSED(state);
return IsMouseButtonUp(btn);
}
extern ECS_COMPONENT_DECLARE(InputState); // defined in main.c
#endif //PIXELDEFENSE_GAME_INPUT_H

View File

@@ -55,7 +55,43 @@ void inputPrimaryAction(Game *game, InputState *input) {
if (selectedCount == 0)
input->state = INPUT_NONE;
}
void inputUnitAction(Game *game, InputState *input) {
void inputUnitAction(Game *game, const InputState *input) {
ecs_query_t *query = input->queries.selected;
BzTileMap *map = &game->map;
const i32 numUnits = ecs_query_entity_count(query);
BZ_ASSERT(numUnits > 0);
const MouseButton actionBtn = input->mapping.secondaryBtn;
if (isInputBtnJustDown(input, actionBtn)) {
// Note: We mustn't use ecs ecs_remove_all since this will also
// remove ongoing paths that are not part of this query.
iterateSelectedUnits(input->queries.selected, iterRemovePaths);
const Position target = input->mouseWorld;
ecs_iter_t it = ecs_query_iter(ECS, query);
ecs_defer_begin(ECS);
while (ecs_iter_next(&it)) {
Position *pos = ecs_field(&it, Position, 1);
for (i32 i = 0; i < it.count; i++) {
const ecs_entity_t entity = it.entities[i];
Path path = {NULL, 0};
pathfindAStar(&(PathfindingDesc) {
.start = pos[i],
.target = target,
.map = map,
.outPath = &path,
.pool = game->pools.pathData,
.alloc = &game->stackAlloc
});
if (!path.paths) continue;
ecs_set_ptr(ECS, entity, Path, &path);
}
}
ecs_defer_end(ECS);
}
}
@@ -113,6 +149,10 @@ void updatePlayerInput() {
case INPUT_SELECTED_UNITS: {
inputPrimaryAction(game, input);
if (input->state != INPUT_SELECTED_UNITS) break;
inputUnitAction(game, input);
/*
i32 selectedCount = ecs_query_entity_count(input->queries.selected);
if (selectedCount > 1 && isInputBtnJustDragged(input, secondaryBtn)) {
// TODO: For click it should just move them
@@ -127,7 +167,6 @@ void updatePlayerInput() {
i32 unitPosIdx = 0;
ecs_defer_begin(ECS);
iterateSelectedUnits(input->queries.selected, iterRemovePaths);
ecs_defer_end(ECS);
ecs_iter_t it = ecs_query_iter(ECS, input->queries.selected);
@@ -185,6 +224,7 @@ void updatePlayerInput() {
}
ecs_defer_end(ECS);
}
*/
break;
}
case INPUT_SELECTED_OBJECT: {