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)
|
||||
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: {
|
||||
|
||||
Reference in New Issue
Block a user