diff --git a/src/drop.h b/src/drop.h index db7040c..e5aaef4 100644 --- a/src/drop.h +++ b/src/drop.h @@ -19,4 +19,8 @@ static inline Drop T##_as_Drop(T* x) {\ return (Drop){.tc = &tc, .data = x};\ } +#define impl_default_Drop_for(T)\ + static void default_drop_##T(T* v) { free(v); }\ + impl_Drop_for(T, default_drop_##T) + #endif // !_fencer_drop_h diff --git a/src/fencer.c b/src/fencer.c index b796d8a..51037be 100644 --- a/src/fencer.c +++ b/src/fencer.c @@ -2,6 +2,7 @@ #include "camera.h" #include "debug.h" #include "input.h" +#include "input_axis.h" #include "physics_entity.h" #include "physics_world.h" #include "program.h" @@ -16,16 +17,8 @@ static Player* player = NULL; static Level* level = NULL; -static -void toggle_info_key(void* null, int down) { - if(down) { - g_debug_log_lvl = (g_debug_log_lvl + 1) % 4; - } -} - static void play() { - input_add_key_action(NULL, InputDelegate(toggle_info_key), SDL_SCANCODE_F1); g_camera.fov = 40; player = player_new(); @@ -47,7 +40,7 @@ void draw() { int main(int argc, char* argv[]) { struct ProgramSettings config = { - .target_fps = 120, + .target_fps = 240, .title = "fencer", .view_resolution = {1920, 1080}, .on_play = &play, diff --git a/src/game_world.c b/src/game_world.c index a8fed34..8dfa86f 100644 --- a/src/game_world.c +++ b/src/game_world.c @@ -22,7 +22,7 @@ size_t _internal_find_index_for_entity(void* data, const List* list) { static inline void _internal_clear_removed() { - list_foreach(size_t, index, &_remove_queue) { + list_foreach(size_t*, index, &_remove_queue) { BehaviourEntity* entity = list_at_as(BehaviourEntity, &_game_entities, *index); entity->drop->drop(entity->data); list_erase(&_game_entities, *index); @@ -32,7 +32,7 @@ void _internal_clear_removed() { static inline void _internal_process_new() { - list_foreach(BehaviourEntity, entity, &_add_queue) { + list_foreach(BehaviourEntity*, entity, &_add_queue) { list_add(&_game_entities, entity); entity->tc->start(entity->data); } @@ -48,7 +48,7 @@ void game_world_init() { void game_world_close() { _internal_clear_removed(); _internal_process_new(); - list_foreach(BehaviourEntity, entity, &_game_entities) { + list_foreach(BehaviourEntity*, entity, &_game_entities) { entity->drop->drop(entity->data); } list_empty(&_game_entities); @@ -67,14 +67,14 @@ void game_world_remove_entity(void* entity) { void game_world_update() { _internal_process_new(); - list_foreach(BehaviourEntity, entity, &_game_entities) { + list_foreach(BehaviourEntity*, entity, &_game_entities) { entity->tc->update(entity->data, delta_time()); } _internal_clear_removed(); } void game_word_draw() { - list_foreach(BehaviourEntity, entity, &_game_entities) { + list_foreach(BehaviourEntity*, entity, &_game_entities) { entity->tc->draw(entity->data); } } diff --git a/src/input.c b/src/input.c index bc94b86..55f1817 100644 --- a/src/input.c +++ b/src/input.c @@ -1,10 +1,103 @@ #include "input.h" +#include "input_axis.h" +#include "debug.h" +static List _devices; + +static +void _internal_open_keyboard() { + InputDevice* keyboard = malloc(sizeof(InputDevice)); + *keyboard = (InputDevice){ + .listeners = NULL, + .type = InputDevice_KBM, + .id = -1, + .keyboard = { + .state = SDL_GetKeyboardState(NULL) + } + }; + list_add(&_devices, &keyboard); + LOG_INFO("registered keyboard %d", keyboard->id); +} + +static +void _internal_open_controller(size_t id) { + InputDevice* device = malloc(sizeof(InputDevice)); + *device = (InputDevice) { + .listeners = NULL, + .type = InputDevice_Gamepad, + .id = id, + .gamepad = { + .id = id, + .controller = SDL_GameControllerOpen(id) + } + }; + + list_add(&_devices, &device); + LOG_INFO("registered game controller %d", device->id); +} void input_init() { - + _devices = list_from_type(InputDevice*); + // open the keyboard by default + _internal_open_keyboard(); + + // open any controllers already available + const size_t joystick_count = SDL_NumJoysticks(); + for(size_t i = 0; i < joystick_count; ++i) { + _internal_open_controller(i); + } } void input_clean() { - + list_foreach(InputDevice**, _device, &_devices) { + InputDevice* device = *_device; + if(device->type == InputDevice_Gamepad) + SDL_GameControllerClose(device->gamepad.controller); + free(device); + } + list_empty(&_devices); +} + +void input_handle_event(SDL_Event event) { + list_foreach(InputDevice**, _device, &_devices) { + InputDevice* device = *_device; + + if(device->listeners != NULL) { + list_foreach(InputListener*, listener, device->listeners) { + InputAxis axis = listener->axis; + + if(axis.tc->is_changed_by(axis.data, event)) { + InputEvent value = axis.tc->evaluate(axis.data, event); + listener->fn(listener->self, value); + } + } + } + } +} + +void input_device_set_listeners(InputDevice* self, List* listeners) { + if(self->listeners != NULL) { + list_foreach(InputListener*, listener, self->listeners) { + listener->axis.tc->set_device(listener->axis.data, NULL); + } + } + + self->listeners = listeners; + + if(listeners == NULL) + return; + + list_foreach(InputListener*, listener, listeners) + listener->axis.tc->set_device(listener->axis.data, self); + LOG_INFO("Set listeners for device %d to %p", self->id, listeners); +} + +InputDevice* input_get_device_by_id(int id) { + list_foreach(InputDevice**, _device, &_devices) { + InputDevice* device = *_device; + if(device->id == id) { + return device; + } + } + return NULL; } diff --git a/src/input.h b/src/input.h index 35e4c61..58ff502 100644 --- a/src/input.h +++ b/src/input.h @@ -3,15 +3,48 @@ #include "vmath.h" #include "list.h" +#include "input_axis.h" #include #include #include -#include +#include + +struct PlayerInput; + +typedef void (*InputDelegateFn)(void* self, InputEvent event); + +typedef struct InputListener { + void* self; + InputDelegateFn fn; + InputAxis axis; +} InputListener; + +typedef enum InputDeviceType { + InputDevice_Gamepad, + InputDevice_KBM +} InputDeviceType; + +typedef struct InputDevice { + List* listeners; + InputDeviceType type; + int id; + union { + struct { + const uint8_t* state; + } keyboard; + struct { + SDL_JoystickID id; + SDL_GameController* controller; + } gamepad; + }; +} InputDevice; extern void input_init(); extern void input_clean(); // handle an input event extern void input_handle_event(SDL_Event event); +extern void input_device_set_listeners(InputDevice* self, List* listeners); +extern InputDevice* input_get_device_by_id(int id); #endif // !_fencer_input_h diff --git a/src/input_axis.c b/src/input_axis.c new file mode 100644 index 0000000..36ee80f --- /dev/null +++ b/src/input_axis.c @@ -0,0 +1,187 @@ +#include "input_axis.h" +#include "debug.h" +#include "input.h" + +KeyBind* keybind_new(SDL_Scancode key) { + KeyBind* self = malloc(sizeof(KeyBind)); + *self = (KeyBind) { + .device = NULL, + .scancode = key, + .state = 0 + }; + return self; +} + +int keybind_is_changed_by(KeyBind* self, SDL_Event event) { + return self->device->type == InputDevice_KBM + && (event.type == SDL_KEYUP || event.type == SDL_KEYDOWN) + && event.key.keysym.scancode == self->scancode; +} + +InputEvent keybind_evaluate(KeyBind* self, SDL_Event event) { + return (InputEvent) { + .type = InputEvent_Bool, + .as_bool = self->device->keyboard.state[self->scancode] + }; +} + +void keybind_set_device(KeyBind* self, InputDevice* device) { + self->device = device; +} + +ControllerAxis* controlleraxis_new(int axis) { + ControllerAxis* self = malloc(sizeof(ControllerAxis)); + *self = (ControllerAxis){ + .axis = axis, + .device = NULL + }; + return self; +} + +int controlleraxis_is_changed_by(ControllerAxis* self, SDL_Event event) { + int r = self->device->type == InputDevice_Gamepad + && event.type == SDL_CONTROLLERAXISMOTION + && event.caxis.which == self->device->gamepad.id + && event.caxis.axis == self->axis; + return r; +} + +InputEvent controlleraxis_evaluate(ControllerAxis* self, SDL_Event event) { + float result = (float)event.caxis.value / 32767.0; + LOG_INFO("axis %f", result); + return (InputEvent) { + .type = InputEvent_Float, + .as_float = result + }; +} + +void controlleraxis_set_device(ControllerAxis* self, InputDevice* device) { + self->device = device; +} + +ControllerButton* controllerbutton_new(int button) { + ControllerButton* self = malloc(sizeof(ControllerButton)); + *self = (ControllerButton) { + .button = button, + .device = NULL + }; + return self; +} + +int controllerbutton_is_changed_by(ControllerButton* self, SDL_Event event) { + return self->device->type == InputDevice_Gamepad + && event.cbutton.which == self->device->gamepad.id + && (event.type == SDL_CONTROLLERBUTTONUP || event.type == SDL_CONTROLLERBUTTONDOWN) + && event.cbutton.button == self->button; +} + +InputEvent controllerbutton_evaluate(ControllerButton* self, SDL_Event event) { + return (InputEvent) { + .type = InputEvent_Bool, + .as_bool = event.cbutton.state + }; +} + +void controllerbutton_set_device(ControllerButton* self, InputDevice* device) { + self->device = device; +} + +CompositeAxis1D* compositeaxis1d_new(InputAxis left, InputAxis right, InputEventType type) { + CompositeAxis1D* self = malloc(sizeof(CompositeAxis1D)); + *self = (CompositeAxis1D) { + .left = left, + .right = right, + .type = type, + }; + return self; +} + +int compositeaxis1d_is_changed_by(CompositeAxis1D* self, SDL_Event event) { + return self->left.tc->is_changed_by(self->left.data, event) + || self->right.tc->is_changed_by(self->right.data, event); +} + +static inline +InputEvent _internal_event_to_type(InputEventType type, InputEvent event) { + if(type == InputEvent_Vector && event.type == InputEvent_Vector) + return event; + + float as_float = 0; + switch(event.type) { + case InputEvent_Vector: + LOG_ERROR("No (1)"); + break; + case InputEvent_Bool: + as_float = event.as_bool; + break; + case InputEvent_Float: + as_float = event.as_float; + break; + case InputEvent_Int: + as_float = event.as_int; + break; + } + event.type = type; + switch(type) { + case InputEvent_Int: + event.as_int = round(as_float); + return event; + case InputEvent_Float: + event.as_float = as_float; + return event; + case InputEvent_Bool: + event.as_bool = as_float != 0; + return event; + case InputEvent_Vector: + LOG_ERROR("No (2)"); + return event; + } + return event; +} + +InputEvent compositeaxis1d_evaluate(CompositeAxis1D* self, SDL_Event event) { + InputEvent left_result = self->left.tc->evaluate(self->left.data, event); + InputEvent right_result = self->right.tc->evaluate(self->right.data, event); + + ASSERT_RETURN(self->type != InputEvent_Vector + || (left_result.type == InputEvent_Vector && right_result.type == InputEvent_Vector), + ((InputEvent){.type = 0, .as_bool = 0}), "Composite axis can only output vector if both composite elements output vector."); + + InputEvent final = { + .type = self->type + }; + // if both outputs are booleans, they will be combined to an int + if(final.type == InputEvent_Bool) + final.type = InputEvent_Int; + + left_result = _internal_event_to_type(final.type, left_result); + right_result = _internal_event_to_type(final.type, right_result); + + switch(final.type) { + default: + LOG_ERROR("Invalid composite input result"); + final.type = InputEvent_Bool; + final.as_bool = 0; + return final; + case InputEvent_Int: + final.as_int = right_result.as_int - left_result.as_int; + return final; + case InputEvent_Float: + final.as_float = right_result.as_float - left_result.as_float; + return final; + case InputEvent_Vector: + final.as_vector = vsubf(right_result.as_vector, left_result.as_vector); + return final; + } +} + +void compositeaxis1d_set_device(CompositeAxis1D* self, InputDevice* device) { + self->left.tc->set_device(self->left.data, device); + self->right.tc->set_device(self->right.data, device); +} + +void compositeaxis1d_drop(CompositeAxis1D* self) { + self->left.drop->drop(self->left.data); + self->right.drop->drop(self->right.data); + free(self); +} diff --git a/src/input_axis.h b/src/input_axis.h new file mode 100644 index 0000000..57af6c8 --- /dev/null +++ b/src/input_axis.h @@ -0,0 +1,129 @@ +#ifndef _fencer_input_axis_h +#define _fencer_input_axis_h + +#include "typeclass_helpers.h" +#include "vmath.h" +#include "drop.h" +#include +#include +#include + +struct InputDevice; + +typedef enum InputEventType { + InputEvent_Vector = 0, + InputEvent_Float = 1, + InputEvent_Int = 2, + InputEvent_Bool = 3, +} InputEventType; + +typedef struct InputEvent { + InputEventType type; + union { + Vector as_vector; + float as_float; + int as_int; + int as_bool; + }; +} InputEvent; + +typedef struct { + int (*const is_changed_by)(void*, SDL_Event); + struct InputEvent (*const evaluate)(void*, SDL_Event); + void (*const set_device)(void*, struct InputDevice*); +} IInputAxis; + +typedef struct { + void* data; + IInputAxis const* tc; + IDrop const* drop; +} InputAxis; + +#define impl_InputAxis_for(T, is_changed_by_f, evaluate_f, set_device_f)\ +static inline InputAxis T##_as_InputAxis(T* x) {\ + TC_FN_TYPECHECK(int, is_changed_by_f, T*, SDL_Event);\ + TC_FN_TYPECHECK(struct InputEvent, evaluate_f, T*, SDL_Event);\ + TC_FN_TYPECHECK(void, set_device_f, T*, struct InputDevice*);\ + static IInputAxis const tc = {\ + .is_changed_by = (int(*const)(void*,SDL_Event)) is_changed_by_f,\ + .evaluate = (struct InputEvent(*const)(void*,SDL_Event)) evaluate_f,\ + .set_device = (void(*const)(void*,struct InputDevice*)) set_device_f\ + };\ + IDrop const* drop = T##_as_Drop(x).tc;\ + return (InputAxis){.data=x, .tc=&tc, .drop = drop};\ +} + +typedef struct KeyBind { + int state; + SDL_Scancode scancode; + struct InputDevice* device; +} KeyBind; + +extern KeyBind* keybind_new(SDL_Scancode bind); +extern int keybind_is_changed_by(KeyBind* self, SDL_Event event); +extern struct InputEvent keybind_evaluate(KeyBind* self, SDL_Event); +extern void keybind_set_device(KeyBind* self, struct InputDevice* device); + +impl_default_Drop_for(KeyBind) +impl_InputAxis_for(KeyBind, + keybind_is_changed_by, + keybind_evaluate, + keybind_set_device +) + +typedef struct ControllerAxis { + struct InputDevice* device; + int axis; +} ControllerAxis; + +extern ControllerAxis* controlleraxis_new(int axis); +extern int controlleraxis_is_changed_by(ControllerAxis* self, SDL_Event event); +extern struct InputEvent controlleraxis_evaluate(ControllerAxis* self, SDL_Event event); +extern void controlleraxis_set_device(ControllerAxis* self, struct InputDevice* device); + +impl_default_Drop_for(ControllerAxis) +impl_InputAxis_for(ControllerAxis, + controlleraxis_is_changed_by, + controlleraxis_evaluate, + controlleraxis_set_device +) + +typedef struct ControllerButton { + struct InputDevice* device; + int button; +} ControllerButton; + +extern ControllerButton* controllerbutton_new(int button); +extern int controllerbutton_is_changed_by(ControllerButton* self, SDL_Event event); +extern struct InputEvent controllerbutton_evaluate(ControllerButton* self, SDL_Event event); +extern void controllerbutton_set_device(ControllerButton* self, struct InputDevice* device); + +impl_default_Drop_for(ControllerButton) +impl_InputAxis_for(ControllerButton, + controllerbutton_is_changed_by, + controllerbutton_evaluate, + controllerbutton_set_device +) + +typedef struct CompositeAxis1D { + InputAxis left; + InputAxis right; + InputEventType type; +} CompositeAxis1D; + +extern CompositeAxis1D* compositeaxis1d_new(InputAxis left, InputAxis right, InputEventType type); +extern int compositeaxis1d_is_changed_by(CompositeAxis1D* self, SDL_Event event); +extern struct InputEvent compositeaxis1d_evaluate(CompositeAxis1D* self, SDL_Event event); +extern void compositeaxis1d_set_device(CompositeAxis1D* self, struct InputDevice* device); +extern void compositeaxis1d_drop(CompositeAxis1D* self); + +impl_Drop_for(CompositeAxis1D, + compositeaxis1d_drop +) +impl_InputAxis_for(CompositeAxis1D, + compositeaxis1d_is_changed_by, + compositeaxis1d_evaluate, + compositeaxis1d_set_device +) + +#endif // !_fencer_input_axis_h diff --git a/src/list.h b/src/list.h index 2a74735..6f8789f 100644 --- a/src/list.h +++ b/src/list.h @@ -27,7 +27,7 @@ extern void* list_iterator_begin(List* self); extern void* list_iterator_end(List* self); #define list_from_type(T) list_init(sizeof(T)) -#define list_foreach(T, iter, list) for(T* iter = list_iterator_begin(list); iter != (T*)list_iterator_end(list); ++iter) +#define list_foreach(T, iter, list) for(T iter = list_iterator_begin(list); iter != (T)list_iterator_end(list); ++iter) #define list_at_as(T, __list, __i) ((T*)(list_at(__list, __i))) #define list_iterator_begin_as(T, __list) ((T*)(list_iterator_begin(__list))) diff --git a/src/physics_entity.c b/src/physics_entity.c index 4e86d2a..e331d8d 100644 --- a/src/physics_entity.c +++ b/src/physics_entity.c @@ -56,7 +56,7 @@ int _internal_default_contact_solver(RigidBody* body, Contact* contact, Transfor void physics_entity_apply_collision_forces(PhysicsEntity self, List* contacts) { RigidBody* body = self.tc->get_rigidbody(self.data); // apply collision impulse - list_foreach(Contact, contact, contacts) + list_foreach(Contact*, contact, contacts) rigidbody_add_impulse(body, _internal_calculate_contact_force(body, contact), 1); } @@ -68,7 +68,7 @@ void physics_entity_solve_contacts(PhysicsEntity self, List* contacts) { int done; for(size_t iteration = 100; iteration != 0; --iteration) { done = 1; - list_foreach(Contact, contact, contacts) { + list_foreach(Contact*, contact, contacts) { if(!_internal_default_contact_solver(body, contact, pre_solve)) done = 0; } @@ -93,7 +93,7 @@ void physics_entity_update(PhysicsEntity self) { List* contacts = rigidbody_get_contacts(body); if(contacts->len > 0) { self.tc->collision_solver(self.data, contacts); - list_foreach(Contact, contact, contacts) + list_foreach(Contact*, contact, contacts) self.tc->on_collision(self.data, contact->hit); } rigidbody_collect_contacts(body); diff --git a/src/player.c b/src/player.c index 4f96d06..d3520c0 100644 --- a/src/player.c +++ b/src/player.c @@ -1,24 +1,65 @@ #include "player.h" #include "assets.h" #include "debug.h" +#include "input_axis.h" #include "physics_entity.h" #include "program.h" #include "rigidbody.h" #include "input.h" #include "physics_world.h" #include "game_world.h" +#include static -void player_input_h(Player* self, int val) { - self->directional.x = val * 10.f; +void player_input_h(Player* self, InputEvent val) { + self->directional.x = val.as_float * 5.f; } + static -void player_input_v(Player* self, int val) { - self->directional.y = -val * 10.f; +void player_input_jump(Player* self, InputEvent down) { + if(down.as_bool && self->is_grounded) { + Vector velocity = rigidbody_get_velocity(self->rigidbody); + self->directional.y = 0; + velocity.y = -20.f; + rigidbody_set_velocity(self->rigidbody, velocity); + } +} + +static inline +void _internal_player_init_input(Player* self) { + // default to keyboard if no controllers are available + if(input_get_device_by_id(0) != NULL) + self->player_input = playerinput_new(self, 0); + else + self->player_input = playerinput_new(self, -1); + + // KEYBOARD ------------------------------------------------ + // WALK + playerinput_add(self->player_input, CompositeAxis1D_as_InputAxis(compositeaxis1d_new( + KeyBind_as_InputAxis(keybind_new(SDL_SCANCODE_A)), + KeyBind_as_InputAxis(keybind_new(SDL_SCANCODE_D)), + InputEvent_Float + )), (InputDelegateFn)player_input_h); + // JUMP + playerinput_add(self->player_input, + KeyBind_as_InputAxis(keybind_new(SDL_SCANCODE_W)), + (InputDelegateFn)player_input_jump + ); + + // CONTROLLER ------------------------------------------------ + // WALK + playerinput_add(self->player_input, + ControllerAxis_as_InputAxis(controlleraxis_new(0)), + (InputDelegateFn)player_input_h + ); + // JUMP + playerinput_add(self->player_input, + ControllerButton_as_InputAxis(controllerbutton_new(SDL_CONTROLLER_BUTTON_A)), + (InputDelegateFn)player_input_jump + ); } Player* player_new() { - Spritesheet* spr_player_standing = spritesheet_load("assets/sprites/player.png", (IVector){128, 128}); float ex_w = 0.1f; @@ -36,12 +77,14 @@ Player* player_new() { {ex_w-r, -h}, {ex_w, rr-h}, }, 8) }; + self->rigidbody = rigidbody_make(Player_as_Transformable(self)); rigidbody_set_mass(self->rigidbody, 10.f); physics_world_add_entity(Player_as_PhysicsEntity(self)); sprite_set_origin(self->sprite, (Vector){0.25f, 1.f}); - input_add_axis_action(self, InputDelegate(player_input_h), SDL_SCANCODE_A, SDL_SCANCODE_D); - input_add_axis_action(self, InputDelegate(player_input_v), SDL_SCANCODE_S, SDL_SCANCODE_W); + + _internal_player_init_input(self); + return self; } @@ -59,11 +102,6 @@ void player_start(Player* self) {} void player_update(Player* self, float dt) { Vector velocity = rigidbody_get_velocity(self->rigidbody); Vector velocity_target = {self->is_grounded ? self->directional.x : velocity.x, velocity.y}; - if(self->directional.y < 0 && self->is_grounded) { - self->directional.y = 0; - velocity.y = -30.f; - rigidbody_set_velocity(self->rigidbody, velocity); - } rigidbody_accelerate(self->rigidbody, vmulff(vsubf(velocity_target, velocity), 50.f), 0); rigidbody_accelerate(self->rigidbody, (Vector){0.0f, 100.f}, 0); self->is_grounded = 0; @@ -77,7 +115,7 @@ void player_free(Player* self) { rigidbody_destroy(self->rigidbody); shape_destroy(self->shape); sprite_destroy(self->sprite); - input_remove_actions(self); + playerinput_drop(self->player_input); free(self); } diff --git a/src/player.h b/src/player.h index c45cabe..a583198 100644 --- a/src/player.h +++ b/src/player.h @@ -8,6 +8,7 @@ #include "collision.h" #include "sprite.h" #include "sprite_entity.h" +#include "player_input.h" typedef struct Player { Transform transform; @@ -18,6 +19,7 @@ typedef struct Player { Sprite* sprite; int is_grounded; + PlayerInput* player_input; } Player; extern Player* player_new(); diff --git a/src/player_input.c b/src/player_input.c new file mode 100644 index 0000000..d8220f8 --- /dev/null +++ b/src/player_input.c @@ -0,0 +1,37 @@ +#include "player_input.h" + +PlayerInput* playerinput_new(void* target, int device) { + PlayerInput* self = malloc(sizeof(PlayerInput)); + self->listeners = list_from_type(InputListener); + self->device = input_get_device_by_id(device); + self->target = target; + input_device_set_listeners(self->device, &self->listeners); + return self; +} + +void playerinput_add(PlayerInput* self, InputAxis axis, InputDelegateFn delegate) { + InputListener listener = { + .axis = axis, + .fn = delegate, + .self = self->target, + }; + listener.axis.tc->set_device(listener.axis.data, self->device); + list_add(&self->listeners, &listener); +} + +void playerinput_set_device(PlayerInput* self, int device) { + if(self->device != NULL) + input_device_set_listeners(self->device, NULL); + self->device = input_get_device_by_id(device); + input_device_set_listeners(self->device, &self->listeners); +} + +void playerinput_drop(PlayerInput* self) { + input_device_set_listeners(self->device, NULL); + + list_foreach(InputListener*, listener, &self->listeners) { + listener->axis.drop->drop(listener->axis.data); + } + list_empty(&self->listeners); + free(self); +} diff --git a/src/player_input.h b/src/player_input.h new file mode 100644 index 0000000..acadf79 --- /dev/null +++ b/src/player_input.h @@ -0,0 +1,23 @@ +#ifndef _fencer_player_input_h +#define _fencer_player_input_h + +#include "list.h" +#include "input.h" +#include "input_axis.h" + +typedef struct PlayerInput { + InputDevice* device; + List listeners; + void* target; +} PlayerInput; + +extern PlayerInput* playerinput_new(void* target, int device); +extern void playerinput_add(PlayerInput* self, InputAxis axis, InputDelegateFn delegate); +extern void playerinput_set_device(PlayerInput* self, int device); +extern void playerinput_drop(PlayerInput* self); + +impl_Drop_for(PlayerInput, + playerinput_drop +) + +#endif // !_fencer_player_input_h diff --git a/src/program.c b/src/program.c index 6a2ae57..29760b2 100644 --- a/src/program.c +++ b/src/program.c @@ -18,7 +18,7 @@ static double _frame_start; static double _game_start_time; -#define INITFLAGS SDL_INIT_EVENTS | SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_GAMECONTROLLER +#define INITFLAGS SDL_INIT_EVENTS | SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_GAMECONTROLLER | SDL_INIT_JOYSTICK static inline double tstos(struct timespec ts) { @@ -44,7 +44,9 @@ int program_run(const struct ProgramSettings* settings) { } _game_start_time = get_time_s(); _frame_start = _game_start_time; - SDL_Init(INITFLAGS); + if(SDL_Init(INITFLAGS) != 0) { + LOG_ERROR("SDL init error: %s", SDL_GetError()); + } g_window = SDL_CreateWindow( settings->title, @@ -54,11 +56,11 @@ int program_run(const struct ProgramSettings* settings) { settings->view_resolution.y, SDL_WINDOW_FULLSCREEN_DESKTOP | SDL_WINDOW_RESIZABLE); - render_init(g_window, settings); - assets_init(); - camera_init(); - input_init(); physics_world_init(); + render_init(g_window, settings); + camera_init(); + assets_init(); + input_init(); game_world_init(); LOG_INFO("settings->on_play"); @@ -88,11 +90,11 @@ int program_run(const struct ProgramSettings* settings) { } void program_quit() { + game_world_close(); + input_clean(); assets_clean(); render_clean(); - input_clean(); physics_world_clean(); - game_world_close(); SDL_DestroyWindow(g_window); SDL_Quit(); exit(0); @@ -105,6 +107,9 @@ void program_handle_events() { default: break; case SDL_KEYUP: case SDL_KEYDOWN: + case SDL_CONTROLLERBUTTONUP: + case SDL_CONTROLLERBUTTONDOWN: + case SDL_CONTROLLERAXISMOTION: input_handle_event(event); break; case SDL_WINDOWEVENT: diff --git a/src/rigidbody.c b/src/rigidbody.c index 60ef589..037ea3f 100644 --- a/src/rigidbody.c +++ b/src/rigidbody.c @@ -140,7 +140,7 @@ Vector rigidbody_get_force(RigidBody* self) { } void rigidbody_debug_draw_contacts(RigidBody* self) { - list_foreach(Contact, contact, &self->contacts) { + list_foreach(Contact*, contact, &self->contacts) { _internal_debug_draw_collision_edge(self, contact); } } diff --git a/src/shape.c b/src/shape.c index 35aa34c..f566571 100644 --- a/src/shape.c +++ b/src/shape.c @@ -21,7 +21,7 @@ Vector* _shape_get_furthest_in_direction(Shape* self, Vector direction) { Vector* furthest = list_at(&self->points, 0); float dot; - list_foreach(Vector, point, &self->points) { + list_foreach(Vector*, point, &self->points) { dot = vdotf(direction, vsubf(*point, self->mean)); if(dot > furthest_dot) { furthest = point; @@ -39,7 +39,7 @@ static int _shape_calculate_is_convex(Shape* self) { // point relative to mean Vector relative; - list_foreach(Vector, point, &self->points) { + list_foreach(Vector*, point, &self->points) { relative = vsubf(*point, self->mean); if(point != _shape_get_furthest_in_direction(self, relative)) { return 0; @@ -53,7 +53,7 @@ static Vector _shape_calculate_mean(Shape* self) { Vector avg = ZeroVector; size_t count = 0; - list_foreach(Vector, point, &self->points) { + list_foreach(Vector*, point, &self->points) { ++count; avg = vaddf(avg, vmulff(*point, 1.0/count)); } diff --git a/src/spritesheet.c b/src/spritesheet.c index 2c1ae15..7fcadd7 100644 --- a/src/spritesheet.c +++ b/src/spritesheet.c @@ -77,4 +77,4 @@ SDL_Rect spritesheet_get_frame_rect(const Spritesheet* self, size_t index) { IVector spritesheet_get_resolution(const Spritesheet* self) { return self->resolution; -} \ No newline at end of file +}