Refactor entity input system
This commit is contained in:
104
engine/tests/pan_test.c
Normal file
104
engine/tests/pan_test.c
Normal 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
125
game/input.h
Normal 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
|
||||||
@@ -55,7 +55,43 @@ void inputPrimaryAction(Game *game, InputState *input) {
|
|||||||
if (selectedCount == 0)
|
if (selectedCount == 0)
|
||||||
input->state = INPUT_NONE;
|
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: {
|
case INPUT_SELECTED_UNITS: {
|
||||||
inputPrimaryAction(game, input);
|
inputPrimaryAction(game, input);
|
||||||
if (input->state != INPUT_SELECTED_UNITS) break;
|
if (input->state != INPUT_SELECTED_UNITS) break;
|
||||||
|
inputUnitAction(game, input);
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
i32 selectedCount = ecs_query_entity_count(input->queries.selected);
|
i32 selectedCount = ecs_query_entity_count(input->queries.selected);
|
||||||
if (selectedCount > 1 && isInputBtnJustDragged(input, secondaryBtn)) {
|
if (selectedCount > 1 && isInputBtnJustDragged(input, secondaryBtn)) {
|
||||||
// TODO: For click it should just move them
|
// TODO: For click it should just move them
|
||||||
@@ -127,7 +167,6 @@ void updatePlayerInput() {
|
|||||||
i32 unitPosIdx = 0;
|
i32 unitPosIdx = 0;
|
||||||
|
|
||||||
ecs_defer_begin(ECS);
|
ecs_defer_begin(ECS);
|
||||||
iterateSelectedUnits(input->queries.selected, iterRemovePaths);
|
|
||||||
ecs_defer_end(ECS);
|
ecs_defer_end(ECS);
|
||||||
|
|
||||||
ecs_iter_t it = ecs_query_iter(ECS, input->queries.selected);
|
ecs_iter_t it = ecs_query_iter(ECS, input->queries.selected);
|
||||||
@@ -185,6 +224,7 @@ void updatePlayerInput() {
|
|||||||
}
|
}
|
||||||
ecs_defer_end(ECS);
|
ecs_defer_end(ECS);
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case INPUT_SELECTED_OBJECT: {
|
case INPUT_SELECTED_OBJECT: {
|
||||||
|
|||||||
Reference in New Issue
Block a user