implemented new input system
This commit is contained in:
		
							parent
							
								
									43527cd675
								
							
						
					
					
						commit
						86ba2b8c29
					
				| 
						 | 
					@ -19,4 +19,8 @@ static inline Drop T##_as_Drop(T* x) {\
 | 
				
			||||||
    return (Drop){.tc = &tc, .data = 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
 | 
					#endif // !_fencer_drop_h
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										11
									
								
								src/fencer.c
									
									
									
									
									
								
							
							
						
						
									
										11
									
								
								src/fencer.c
									
									
									
									
									
								
							| 
						 | 
					@ -2,6 +2,7 @@
 | 
				
			||||||
#include "camera.h"
 | 
					#include "camera.h"
 | 
				
			||||||
#include "debug.h"
 | 
					#include "debug.h"
 | 
				
			||||||
#include "input.h"
 | 
					#include "input.h"
 | 
				
			||||||
 | 
					#include "input_axis.h"
 | 
				
			||||||
#include "physics_entity.h"
 | 
					#include "physics_entity.h"
 | 
				
			||||||
#include "physics_world.h"
 | 
					#include "physics_world.h"
 | 
				
			||||||
#include "program.h"
 | 
					#include "program.h"
 | 
				
			||||||
| 
						 | 
					@ -16,16 +17,8 @@
 | 
				
			||||||
static Player* player = NULL;
 | 
					static Player* player = NULL;
 | 
				
			||||||
static Level* level = 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
 | 
					static
 | 
				
			||||||
void play() {
 | 
					void play() {
 | 
				
			||||||
    input_add_key_action(NULL, InputDelegate(toggle_info_key), SDL_SCANCODE_F1);
 | 
					 | 
				
			||||||
    g_camera.fov = 40;
 | 
					    g_camera.fov = 40;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    player = player_new();
 | 
					    player = player_new();
 | 
				
			||||||
| 
						 | 
					@ -47,7 +40,7 @@ void draw() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int main(int argc, char* argv[]) {
 | 
					int main(int argc, char* argv[]) {
 | 
				
			||||||
    struct ProgramSettings config = {
 | 
					    struct ProgramSettings config = {
 | 
				
			||||||
        .target_fps = 120,
 | 
					        .target_fps = 240,
 | 
				
			||||||
        .title = "fencer",
 | 
					        .title = "fencer",
 | 
				
			||||||
        .view_resolution = {1920, 1080},
 | 
					        .view_resolution = {1920, 1080},
 | 
				
			||||||
        .on_play = &play,
 | 
					        .on_play = &play,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -22,7 +22,7 @@ size_t _internal_find_index_for_entity(void* data, const List* list) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static inline
 | 
					static inline
 | 
				
			||||||
void _internal_clear_removed() {
 | 
					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);
 | 
					        BehaviourEntity* entity = list_at_as(BehaviourEntity, &_game_entities, *index);
 | 
				
			||||||
        entity->drop->drop(entity->data);
 | 
					        entity->drop->drop(entity->data);
 | 
				
			||||||
        list_erase(&_game_entities, *index);
 | 
					        list_erase(&_game_entities, *index);
 | 
				
			||||||
| 
						 | 
					@ -32,7 +32,7 @@ void _internal_clear_removed() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static inline
 | 
					static inline
 | 
				
			||||||
void _internal_process_new() {
 | 
					void _internal_process_new() {
 | 
				
			||||||
    list_foreach(BehaviourEntity, entity, &_add_queue) {
 | 
					    list_foreach(BehaviourEntity*, entity, &_add_queue) {
 | 
				
			||||||
        list_add(&_game_entities, entity);
 | 
					        list_add(&_game_entities, entity);
 | 
				
			||||||
        entity->tc->start(entity->data);
 | 
					        entity->tc->start(entity->data);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -48,7 +48,7 @@ void game_world_init() {
 | 
				
			||||||
void game_world_close() {
 | 
					void game_world_close() {
 | 
				
			||||||
    _internal_clear_removed();
 | 
					    _internal_clear_removed();
 | 
				
			||||||
    _internal_process_new();
 | 
					    _internal_process_new();
 | 
				
			||||||
    list_foreach(BehaviourEntity, entity, &_game_entities) {
 | 
					    list_foreach(BehaviourEntity*, entity, &_game_entities) {
 | 
				
			||||||
        entity->drop->drop(entity->data);
 | 
					        entity->drop->drop(entity->data);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    list_empty(&_game_entities);
 | 
					    list_empty(&_game_entities);
 | 
				
			||||||
| 
						 | 
					@ -67,14 +67,14 @@ void game_world_remove_entity(void* entity) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void game_world_update() {
 | 
					void game_world_update() {
 | 
				
			||||||
    _internal_process_new();
 | 
					    _internal_process_new();
 | 
				
			||||||
    list_foreach(BehaviourEntity, entity, &_game_entities) {
 | 
					    list_foreach(BehaviourEntity*, entity, &_game_entities) {
 | 
				
			||||||
        entity->tc->update(entity->data, delta_time());
 | 
					        entity->tc->update(entity->data, delta_time());
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    _internal_clear_removed();
 | 
					    _internal_clear_removed();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void game_word_draw() {
 | 
					void game_word_draw() {
 | 
				
			||||||
    list_foreach(BehaviourEntity, entity, &_game_entities) {
 | 
					    list_foreach(BehaviourEntity*, entity, &_game_entities) {
 | 
				
			||||||
        entity->tc->draw(entity->data);
 | 
					        entity->tc->draw(entity->data);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										95
									
								
								src/input.c
									
									
									
									
									
								
							
							
						
						
									
										95
									
								
								src/input.c
									
									
									
									
									
								
							| 
						 | 
					@ -1,10 +1,103 @@
 | 
				
			||||||
#include "input.h"
 | 
					#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() {
 | 
					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() {
 | 
					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;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										35
									
								
								src/input.h
									
									
									
									
									
								
							
							
						
						
									
										35
									
								
								src/input.h
									
									
									
									
									
								
							| 
						 | 
					@ -3,15 +3,48 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "vmath.h"
 | 
					#include "vmath.h"
 | 
				
			||||||
#include "list.h"
 | 
					#include "list.h"
 | 
				
			||||||
 | 
					#include "input_axis.h"
 | 
				
			||||||
#include <SDL2/SDL_events.h>
 | 
					#include <SDL2/SDL_events.h>
 | 
				
			||||||
#include <SDL2/SDL_scancode.h>
 | 
					#include <SDL2/SDL_scancode.h>
 | 
				
			||||||
#include <SDL2/SDL_keyboard.h>
 | 
					#include <SDL2/SDL_keyboard.h>
 | 
				
			||||||
#include <SDL2/SDL_joystick.h>
 | 
					#include <SDL2/SDL_gamecontroller.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					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_init();
 | 
				
			||||||
extern void input_clean();
 | 
					extern void input_clean();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// handle an input event
 | 
					// handle an input event
 | 
				
			||||||
extern void input_handle_event(SDL_Event 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
 | 
					#endif // !_fencer_input_h
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										187
									
								
								src/input_axis.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										187
									
								
								src/input_axis.c
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -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);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										129
									
								
								src/input_axis.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										129
									
								
								src/input_axis.h
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -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 <SDL2/SDL_events.h>
 | 
				
			||||||
 | 
					#include <SDL2/SDL_keyboard.h>
 | 
				
			||||||
 | 
					#include <SDL2/SDL_gamecontroller.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					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
 | 
				
			||||||
| 
						 | 
					@ -27,7 +27,7 @@ extern void* list_iterator_begin(List* self);
 | 
				
			||||||
extern void* list_iterator_end(List* self);
 | 
					extern void* list_iterator_end(List* self);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define list_from_type(T) list_init(sizeof(T))
 | 
					#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_at_as(T, __list, __i) ((T*)(list_at(__list, __i)))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define list_iterator_begin_as(T, __list) ((T*)(list_iterator_begin(__list)))
 | 
					#define list_iterator_begin_as(T, __list) ((T*)(list_iterator_begin(__list)))
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -56,7 +56,7 @@ int _internal_default_contact_solver(RigidBody* body, Contact* contact, Transfor
 | 
				
			||||||
void physics_entity_apply_collision_forces(PhysicsEntity self, List* contacts) {
 | 
					void physics_entity_apply_collision_forces(PhysicsEntity self, List* contacts) {
 | 
				
			||||||
    RigidBody* body = self.tc->get_rigidbody(self.data);
 | 
					    RigidBody* body = self.tc->get_rigidbody(self.data);
 | 
				
			||||||
    // apply collision impulse
 | 
					    // apply collision impulse
 | 
				
			||||||
    list_foreach(Contact, contact, contacts)
 | 
					    list_foreach(Contact*, contact, contacts)
 | 
				
			||||||
        rigidbody_add_impulse(body, _internal_calculate_contact_force(body, contact), 1);
 | 
					        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;
 | 
					    int done;
 | 
				
			||||||
    for(size_t iteration = 100; iteration != 0; --iteration) {
 | 
					    for(size_t iteration = 100; iteration != 0; --iteration) {
 | 
				
			||||||
        done = 1;
 | 
					        done = 1;
 | 
				
			||||||
        list_foreach(Contact, contact, contacts) {
 | 
					        list_foreach(Contact*, contact, contacts) {
 | 
				
			||||||
            if(!_internal_default_contact_solver(body, contact, pre_solve))
 | 
					            if(!_internal_default_contact_solver(body, contact, pre_solve))
 | 
				
			||||||
                done = 0;
 | 
					                done = 0;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
| 
						 | 
					@ -93,7 +93,7 @@ void physics_entity_update(PhysicsEntity self) {
 | 
				
			||||||
    List* contacts = rigidbody_get_contacts(body);
 | 
					    List* contacts = rigidbody_get_contacts(body);
 | 
				
			||||||
    if(contacts->len > 0) {
 | 
					    if(contacts->len > 0) {
 | 
				
			||||||
        self.tc->collision_solver(self.data, contacts);
 | 
					        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);
 | 
					            self.tc->on_collision(self.data, contact->hit);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    rigidbody_collect_contacts(body);
 | 
					    rigidbody_collect_contacts(body);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										64
									
								
								src/player.c
									
									
									
									
									
								
							
							
						
						
									
										64
									
								
								src/player.c
									
									
									
									
									
								
							| 
						 | 
					@ -1,24 +1,65 @@
 | 
				
			||||||
#include "player.h"
 | 
					#include "player.h"
 | 
				
			||||||
#include "assets.h"
 | 
					#include "assets.h"
 | 
				
			||||||
#include "debug.h"
 | 
					#include "debug.h"
 | 
				
			||||||
 | 
					#include "input_axis.h"
 | 
				
			||||||
#include "physics_entity.h"
 | 
					#include "physics_entity.h"
 | 
				
			||||||
#include "program.h"
 | 
					#include "program.h"
 | 
				
			||||||
#include "rigidbody.h"
 | 
					#include "rigidbody.h"
 | 
				
			||||||
#include "input.h"
 | 
					#include "input.h"
 | 
				
			||||||
#include "physics_world.h"
 | 
					#include "physics_world.h"
 | 
				
			||||||
#include "game_world.h"
 | 
					#include "game_world.h"
 | 
				
			||||||
 | 
					#include <SDL2/SDL_gamecontroller.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static
 | 
					static
 | 
				
			||||||
void player_input_h(Player* self, int val) {
 | 
					void player_input_h(Player* self, InputEvent val) {
 | 
				
			||||||
    self->directional.x = val * 10.f;
 | 
					    self->directional.x = val.as_float * 5.f;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static
 | 
					static
 | 
				
			||||||
void player_input_v(Player* self, int val) {
 | 
					void player_input_jump(Player* self, InputEvent down) {
 | 
				
			||||||
    self->directional.y = -val * 10.f;
 | 
					    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() {
 | 
					Player* player_new() {
 | 
				
			||||||
 | 
					 | 
				
			||||||
    Spritesheet* spr_player_standing = spritesheet_load("assets/sprites/player.png", (IVector){128, 128});
 | 
					    Spritesheet* spr_player_standing = spritesheet_load("assets/sprites/player.png", (IVector){128, 128});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    float ex_w = 0.1f;
 | 
					    float ex_w = 0.1f;
 | 
				
			||||||
| 
						 | 
					@ -36,12 +77,14 @@ Player* player_new() {
 | 
				
			||||||
            {ex_w-r, -h}, {ex_w, rr-h},
 | 
					            {ex_w-r, -h}, {ex_w, rr-h},
 | 
				
			||||||
        }, 8)
 | 
					        }, 8)
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    self->rigidbody = rigidbody_make(Player_as_Transformable(self));
 | 
					    self->rigidbody = rigidbody_make(Player_as_Transformable(self));
 | 
				
			||||||
    rigidbody_set_mass(self->rigidbody, 10.f);
 | 
					    rigidbody_set_mass(self->rigidbody, 10.f);
 | 
				
			||||||
    physics_world_add_entity(Player_as_PhysicsEntity(self));
 | 
					    physics_world_add_entity(Player_as_PhysicsEntity(self));
 | 
				
			||||||
    sprite_set_origin(self->sprite, (Vector){0.25f, 1.f});
 | 
					    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;
 | 
					    return self;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -59,11 +102,6 @@ void player_start(Player* self) {}
 | 
				
			||||||
void player_update(Player* self, float dt) {
 | 
					void player_update(Player* self, float dt) {
 | 
				
			||||||
    Vector velocity = rigidbody_get_velocity(self->rigidbody);
 | 
					    Vector velocity = rigidbody_get_velocity(self->rigidbody);
 | 
				
			||||||
    Vector velocity_target = {self->is_grounded ? self->directional.x : velocity.x, velocity.y};
 | 
					    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, vmulff(vsubf(velocity_target, velocity), 50.f), 0);
 | 
				
			||||||
    rigidbody_accelerate(self->rigidbody, (Vector){0.0f, 100.f}, 0);
 | 
					    rigidbody_accelerate(self->rigidbody, (Vector){0.0f, 100.f}, 0);
 | 
				
			||||||
    self->is_grounded = 0;
 | 
					    self->is_grounded = 0;
 | 
				
			||||||
| 
						 | 
					@ -77,7 +115,7 @@ void player_free(Player* self) {
 | 
				
			||||||
    rigidbody_destroy(self->rigidbody);
 | 
					    rigidbody_destroy(self->rigidbody);
 | 
				
			||||||
    shape_destroy(self->shape);
 | 
					    shape_destroy(self->shape);
 | 
				
			||||||
    sprite_destroy(self->sprite);
 | 
					    sprite_destroy(self->sprite);
 | 
				
			||||||
    input_remove_actions(self);
 | 
					    playerinput_drop(self->player_input);
 | 
				
			||||||
    free(self);
 | 
					    free(self);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -8,6 +8,7 @@
 | 
				
			||||||
#include "collision.h"
 | 
					#include "collision.h"
 | 
				
			||||||
#include "sprite.h"
 | 
					#include "sprite.h"
 | 
				
			||||||
#include "sprite_entity.h"
 | 
					#include "sprite_entity.h"
 | 
				
			||||||
 | 
					#include "player_input.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef struct Player {
 | 
					typedef struct Player {
 | 
				
			||||||
    Transform transform;
 | 
					    Transform transform;
 | 
				
			||||||
| 
						 | 
					@ -18,6 +19,7 @@ typedef struct Player {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    Sprite* sprite;
 | 
					    Sprite* sprite;
 | 
				
			||||||
    int is_grounded;
 | 
					    int is_grounded;
 | 
				
			||||||
 | 
					    PlayerInput* player_input;
 | 
				
			||||||
} Player;
 | 
					} Player;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern Player* player_new();
 | 
					extern Player* player_new();
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										37
									
								
								src/player_input.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								src/player_input.c
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -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);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										23
									
								
								src/player_input.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								src/player_input.h
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -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
 | 
				
			||||||
| 
						 | 
					@ -18,7 +18,7 @@ static double _frame_start;
 | 
				
			||||||
static double _game_start_time;
 | 
					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
 | 
					static inline
 | 
				
			||||||
double tstos(struct timespec ts) {
 | 
					double tstos(struct timespec ts) {
 | 
				
			||||||
| 
						 | 
					@ -44,7 +44,9 @@ int program_run(const struct ProgramSettings* settings) {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    _game_start_time = get_time_s();
 | 
					    _game_start_time = get_time_s();
 | 
				
			||||||
    _frame_start = _game_start_time;
 | 
					    _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(
 | 
					    g_window = SDL_CreateWindow(
 | 
				
			||||||
        settings->title,
 | 
					        settings->title,
 | 
				
			||||||
| 
						 | 
					@ -54,11 +56,11 @@ int program_run(const struct ProgramSettings* settings) {
 | 
				
			||||||
        settings->view_resolution.y,
 | 
					        settings->view_resolution.y,
 | 
				
			||||||
        SDL_WINDOW_FULLSCREEN_DESKTOP | SDL_WINDOW_RESIZABLE);
 | 
					        SDL_WINDOW_FULLSCREEN_DESKTOP | SDL_WINDOW_RESIZABLE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    render_init(g_window, settings);
 | 
					 | 
				
			||||||
    assets_init();
 | 
					 | 
				
			||||||
    camera_init();
 | 
					 | 
				
			||||||
    input_init();
 | 
					 | 
				
			||||||
    physics_world_init();
 | 
					    physics_world_init();
 | 
				
			||||||
 | 
					    render_init(g_window, settings);
 | 
				
			||||||
 | 
					    camera_init();
 | 
				
			||||||
 | 
					    assets_init();
 | 
				
			||||||
 | 
					    input_init();
 | 
				
			||||||
    game_world_init();
 | 
					    game_world_init();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    LOG_INFO("settings->on_play");
 | 
					    LOG_INFO("settings->on_play");
 | 
				
			||||||
| 
						 | 
					@ -88,11 +90,11 @@ int program_run(const struct ProgramSettings* settings) {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void program_quit() {
 | 
					void program_quit() {
 | 
				
			||||||
 | 
					    game_world_close();
 | 
				
			||||||
 | 
					    input_clean();
 | 
				
			||||||
    assets_clean();
 | 
					    assets_clean();
 | 
				
			||||||
    render_clean();
 | 
					    render_clean();
 | 
				
			||||||
    input_clean();
 | 
					 | 
				
			||||||
    physics_world_clean();
 | 
					    physics_world_clean();
 | 
				
			||||||
    game_world_close();
 | 
					 | 
				
			||||||
    SDL_DestroyWindow(g_window);
 | 
					    SDL_DestroyWindow(g_window);
 | 
				
			||||||
    SDL_Quit();
 | 
					    SDL_Quit();
 | 
				
			||||||
    exit(0);
 | 
					    exit(0);
 | 
				
			||||||
| 
						 | 
					@ -105,6 +107,9 @@ void program_handle_events() {
 | 
				
			||||||
            default: break;
 | 
					            default: break;
 | 
				
			||||||
            case SDL_KEYUP:
 | 
					            case SDL_KEYUP:
 | 
				
			||||||
            case SDL_KEYDOWN:
 | 
					            case SDL_KEYDOWN:
 | 
				
			||||||
 | 
					            case SDL_CONTROLLERBUTTONUP:
 | 
				
			||||||
 | 
					            case SDL_CONTROLLERBUTTONDOWN:
 | 
				
			||||||
 | 
					            case SDL_CONTROLLERAXISMOTION:
 | 
				
			||||||
                input_handle_event(event);
 | 
					                input_handle_event(event);
 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
            case SDL_WINDOWEVENT:
 | 
					            case SDL_WINDOWEVENT:
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -140,7 +140,7 @@ Vector rigidbody_get_force(RigidBody* self) {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void rigidbody_debug_draw_contacts(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);
 | 
					        _internal_debug_draw_collision_edge(self, contact);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -21,7 +21,7 @@ Vector* _shape_get_furthest_in_direction(Shape* self, Vector direction) {
 | 
				
			||||||
    Vector* furthest = list_at(&self->points, 0);
 | 
					    Vector* furthest = list_at(&self->points, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    float dot;
 | 
					    float dot;
 | 
				
			||||||
    list_foreach(Vector, point, &self->points) {
 | 
					    list_foreach(Vector*, point, &self->points) {
 | 
				
			||||||
        dot = vdotf(direction, vsubf(*point, self->mean));
 | 
					        dot = vdotf(direction, vsubf(*point, self->mean));
 | 
				
			||||||
        if(dot > furthest_dot) {
 | 
					        if(dot > furthest_dot) {
 | 
				
			||||||
            furthest = point;
 | 
					            furthest = point;
 | 
				
			||||||
| 
						 | 
					@ -39,7 +39,7 @@ static
 | 
				
			||||||
int _shape_calculate_is_convex(Shape* self) {
 | 
					int _shape_calculate_is_convex(Shape* self) {
 | 
				
			||||||
    // point relative to mean
 | 
					    // point relative to mean
 | 
				
			||||||
    Vector relative;
 | 
					    Vector relative;
 | 
				
			||||||
    list_foreach(Vector, point, &self->points) {
 | 
					    list_foreach(Vector*, point, &self->points) {
 | 
				
			||||||
        relative = vsubf(*point, self->mean);
 | 
					        relative = vsubf(*point, self->mean);
 | 
				
			||||||
        if(point != _shape_get_furthest_in_direction(self, relative)) {
 | 
					        if(point != _shape_get_furthest_in_direction(self, relative)) {
 | 
				
			||||||
            return 0;
 | 
					            return 0;
 | 
				
			||||||
| 
						 | 
					@ -53,7 +53,7 @@ static
 | 
				
			||||||
Vector _shape_calculate_mean(Shape* self) {
 | 
					Vector _shape_calculate_mean(Shape* self) {
 | 
				
			||||||
    Vector avg = ZeroVector;
 | 
					    Vector avg = ZeroVector;
 | 
				
			||||||
    size_t count = 0;
 | 
					    size_t count = 0;
 | 
				
			||||||
    list_foreach(Vector, point, &self->points) {
 | 
					    list_foreach(Vector*, point, &self->points) {
 | 
				
			||||||
        ++count;
 | 
					        ++count;
 | 
				
			||||||
        avg = vaddf(avg, vmulff(*point, 1.0/count));
 | 
					        avg = vaddf(avg, vmulff(*point, 1.0/count));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue