feat: implemented input module
This commit is contained in:
parent
4151c3429a
commit
38ceeec36f
|
@ -1,6 +1,7 @@
|
||||||
#include "engine_loop.h"
|
#include "engine_loop.h"
|
||||||
#include "engine_global.h"
|
#include "engine_global.h"
|
||||||
#include "render.h"
|
#include "render.h"
|
||||||
|
#include "input.h"
|
||||||
#include "resources.h"
|
#include "resources.h"
|
||||||
#include "utils/debug.h"
|
#include "utils/debug.h"
|
||||||
#include "stdlib.h"
|
#include "stdlib.h"
|
||||||
|
@ -25,6 +26,7 @@ void RunGame(Scene *initial_scene) {
|
||||||
while (!WindowShouldClose()) {
|
while (!WindowShouldClose()) {
|
||||||
SceneTick(GetMainScene(), GetFrameTime());
|
SceneTick(GetMainScene(), GetFrameTime());
|
||||||
RenderNextFrame();
|
RenderNextFrame();
|
||||||
|
Internal_UpdateInput();
|
||||||
}
|
}
|
||||||
ShutDown();
|
ShutDown();
|
||||||
UNREACHABLE("RunGame: Reached beyond ShutDown call");
|
UNREACHABLE("RunGame: Reached beyond ShutDown call");
|
||||||
|
@ -36,6 +38,7 @@ void InitializeEngine() {
|
||||||
// initialize engine subsystems
|
// initialize engine subsystems
|
||||||
InitializeResourceSubsystem();
|
InitializeResourceSubsystem();
|
||||||
InitializeRenderingSubsystem();
|
InitializeRenderingSubsystem();
|
||||||
|
InitializeInputSubsystem();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShutDown() {
|
void ShutDown() {
|
||||||
|
@ -43,6 +46,7 @@ void ShutDown() {
|
||||||
if(GetMainScene() != NULL)
|
if(GetMainScene() != NULL)
|
||||||
DestroyScene(GetMainScene());
|
DestroyScene(GetMainScene());
|
||||||
// clean up subsystem resources
|
// clean up subsystem resources
|
||||||
|
CleanInputSubsystem();
|
||||||
CleanResourceSubsystem();
|
CleanResourceSubsystem();
|
||||||
CleanupRenderingSubsystem();
|
CleanupRenderingSubsystem();
|
||||||
CloseWindow();
|
CloseWindow();
|
||||||
|
|
187
src/core/input.c
Normal file
187
src/core/input.c
Normal file
|
@ -0,0 +1,187 @@
|
||||||
|
#include "input.h"
|
||||||
|
#include "string.h"
|
||||||
|
#include "utils/debug.h"
|
||||||
|
#include "utils/hash_map.h"
|
||||||
|
#include "utils/list.h"
|
||||||
|
#include "utils/strutil.h"
|
||||||
|
#include <raylib.h>
|
||||||
|
|
||||||
|
typedef struct InputObserver {
|
||||||
|
List listeners;
|
||||||
|
unsigned char listener_type;
|
||||||
|
} InputObserver;
|
||||||
|
|
||||||
|
typedef struct MappedInput {
|
||||||
|
InputObserver *observer;
|
||||||
|
int device_idx; //!< For gamepad inputs, the gamepad index
|
||||||
|
int input_idx; //!< key/button/axis to check
|
||||||
|
InputType type; //!< type of input to check
|
||||||
|
union {
|
||||||
|
int last_int_value; //!< last value for buttons
|
||||||
|
float last_float_value; //!< Last value for analog axes
|
||||||
|
};
|
||||||
|
} MappedInput;
|
||||||
|
|
||||||
|
static HashMap g_input_map;
|
||||||
|
static List g_mapped_actions;
|
||||||
|
|
||||||
|
static
|
||||||
|
uintptr_t HashStrPtrPtr(char **ptr) {
|
||||||
|
return strhash(*ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void InitializeInputSubsystem() {
|
||||||
|
g_input_map = hash_map_from_types(char*, InputObserver*, HashStrPtrPtr);
|
||||||
|
g_mapped_actions = list_from_type(MappedInput);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CleanInputSubsystem() {
|
||||||
|
// free both input map keys and values manually, as neither is managed elsewhere
|
||||||
|
List input_values = hash_map_values(&g_input_map);
|
||||||
|
for(size_t i = 0; i < input_values.len; ++i) {
|
||||||
|
InputObserver *observer = **list_at_as(InputObserver**, &input_values, i);
|
||||||
|
list_empty(&observer->listeners); // free the listener array
|
||||||
|
free(observer);
|
||||||
|
}
|
||||||
|
list_empty(&input_values);
|
||||||
|
List input_keys = hash_map_keys(&g_input_map);
|
||||||
|
for(size_t i = 0; i < input_keys.len; ++i) {
|
||||||
|
free(**list_at_as(char**, &input_keys, i));
|
||||||
|
}
|
||||||
|
list_empty(&input_keys);
|
||||||
|
// clear the collection containers
|
||||||
|
hash_map_empty(&g_input_map);
|
||||||
|
list_empty(&g_mapped_actions);
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void Internal_UpdateGamepadButtonInput(MappedInput *self) {
|
||||||
|
if(!IsGamepadAvailable(self->device_idx)) return;
|
||||||
|
int const value = IsGamepadButtonDown(self->device_idx, self->input_idx);
|
||||||
|
if(value != self->last_int_value)
|
||||||
|
list_foreach(InputListener *,listener, &self->observer->listeners)
|
||||||
|
listener->button_listener(listener->object, value != 0);
|
||||||
|
self->last_int_value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void Internal_UpdateGamepadAxisInput(MappedInput *self) {
|
||||||
|
if(!IsGamepadAvailable(self->device_idx)) return;
|
||||||
|
float const value = GetGamepadAxisMovement(self->device_idx, self->input_idx);
|
||||||
|
if(value != self->last_float_value)
|
||||||
|
list_foreach(InputListener *,listener, &self->observer->listeners)
|
||||||
|
listener->axis_listener(listener->object, value);
|
||||||
|
self->last_float_value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void Internal_UpdateKeyboardInput(MappedInput *self) {
|
||||||
|
int const value = IsKeyDown(self->input_idx);
|
||||||
|
if(value != self->last_int_value)
|
||||||
|
list_foreach(InputListener *,listener, &self->observer->listeners)
|
||||||
|
listener->button_listener(listener->object, value);
|
||||||
|
self->last_int_value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void Internal_UpdateMouseInput(MappedInput *self) {
|
||||||
|
float value = 0.f;
|
||||||
|
if(self->input_idx == 1)
|
||||||
|
value = GetMouseDelta().y;
|
||||||
|
else value = GetMouseDelta().x;
|
||||||
|
if(value != self->last_float_value)
|
||||||
|
list_foreach(InputListener *,listener, &self->observer->listeners)
|
||||||
|
listener->axis_listener(listener->object, self->last_float_value);
|
||||||
|
self->last_float_value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Internal_UpdateInput() {
|
||||||
|
list_foreach(MappedInput *,input, &g_mapped_actions) {
|
||||||
|
switch(input->type) {
|
||||||
|
case INPUT_LISTENER_GAMEPAD_BUTTON:
|
||||||
|
Internal_UpdateGamepadButtonInput(input);
|
||||||
|
break;
|
||||||
|
case INPUT_LISTENER_GAMEPAD_AXIS:
|
||||||
|
Internal_UpdateGamepadAxisInput(input);
|
||||||
|
break;
|
||||||
|
case INPUT_LISTENER_KEY:
|
||||||
|
Internal_UpdateKeyboardInput(input);
|
||||||
|
break;
|
||||||
|
case INPUT_LISTENER_MOUSE:
|
||||||
|
Internal_UpdateMouseInput(input);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
InputObserver *Internal_CreateNewAction(char const *action_name, unsigned char listener_type) {
|
||||||
|
char *key = malloc(strlen(action_name) + 1);
|
||||||
|
strcpy(key, action_name);
|
||||||
|
InputObserver *value = new(InputObserver);
|
||||||
|
*value = (InputObserver) {
|
||||||
|
.listeners = list_from_type(InputListener),
|
||||||
|
.listener_type = listener_type
|
||||||
|
};
|
||||||
|
hash_map_insert(&g_input_map, &key, &value);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Either returns existing observer or adds new observer.
|
||||||
|
static
|
||||||
|
InputObserver *Internal_GetInputObserver(char const *action_name, unsigned char listener_type) {
|
||||||
|
InputObserver** observer = hash_map_get_as(InputObserver*, &g_input_map, &action_name);
|
||||||
|
ASSERT_RETURN(observer == NULL || listener_type != 0 || (*observer)->listener_type != listener_type, NULL,
|
||||||
|
"Internal_GetInputObserver: Device type is not supported by found action");
|
||||||
|
return observer != NULL ? *observer : Internal_CreateNewAction(action_name, listener_type);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AddAction(char const *action_name, InputType dev_type, int device, int input) {
|
||||||
|
// assert that there is a valid name to map to an observer
|
||||||
|
ASSERT_RETURN(action_name != NULL,, "AddAction: action_name has to be passed with a valid string");
|
||||||
|
InputObserver *observer = Internal_GetInputObserver(action_name, dev_type & 0xF);
|
||||||
|
// assert that there is an observer to work with
|
||||||
|
ASSERT_RETURN(observer != NULL,, "AddAction: Could not find or create %s", action_name);
|
||||||
|
MappedInput mapped = { .observer = observer, .input_idx = input, .device_idx = device, .type = dev_type };
|
||||||
|
if((0xF & dev_type) == 0x01) // initialize last_ _value based on device type
|
||||||
|
mapped.last_int_value = 0;
|
||||||
|
else mapped.last_float_value = 0.f;
|
||||||
|
list_add(&g_mapped_actions, &mapped);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AddListener(char const *action_name, InputListener listener) {
|
||||||
|
InputObserver *observer = Internal_GetInputObserver(action_name, ((listener.axis_listener != 0) << 1) | (listener.button_listener != NULL));
|
||||||
|
// assert that there is actually an observer to work with
|
||||||
|
ASSERT_RETURN(observer != NULL,, "AddListener: Could not find or create action called %s", action_name);
|
||||||
|
// assert that either the observer and listener are both for button events, or both for axis events.
|
||||||
|
ASSERT_RETURN(observer->listener_type != 0x2 || listener.button_listener == NULL && listener.axis_listener != NULL,,
|
||||||
|
"AddListener: Axis listener is not supported by button action.");
|
||||||
|
ASSERT_RETURN(observer->listener_type != 0x1 || listener.axis_listener == NULL && listener.button_listener != NULL,,
|
||||||
|
"AddListener: Button listenertype is not supported by axis action.");
|
||||||
|
list_add(&observer->listeners, &listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RemoveListener(char const *action_name, void *object) {
|
||||||
|
InputObserver *observer = Internal_GetInputObserver(action_name, 0);
|
||||||
|
ASSERT_RETURN(observer != NULL,, "RemoveListener: Could not find or create action called %s", action_name);
|
||||||
|
// linear search for input, as the list is unsorted & not indexed
|
||||||
|
for(size_t i = 0; i < observer->listeners.len; ++i) {
|
||||||
|
if(list_at_as(InputListener, &observer->listeners, i)->object == object) {
|
||||||
|
list_erase(&observer->listeners, i);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void RemoveAllListeners(void *object) {
|
||||||
|
List observers = hash_map_values(&g_input_map);
|
||||||
|
// linear search through observers for listeners that match the passed object
|
||||||
|
for(size_t observer_idx = 0; observer_idx < observers.len; ++observer_idx) {
|
||||||
|
List *listeners = &(**list_at_as(InputObserver**, &observers, observer_idx))->listeners;
|
||||||
|
for(size_t listener_idx = 0; listener_idx < listeners->len;) {
|
||||||
|
if(list_at_as(InputListener, listeners, listener_idx)->object == object) {
|
||||||
|
list_erase(listeners, listener_idx);
|
||||||
|
} else ++listener_idx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,30 +3,37 @@
|
||||||
|
|
||||||
#include "stdbool.h"
|
#include "stdbool.h"
|
||||||
|
|
||||||
typedef enum InputListenerType {
|
//! Input type, second nibble is an index.
|
||||||
INPUT_LISTENER_INT,
|
//! First nibble is a bitmask of what type of listener will work.
|
||||||
INPUT_LISTENER_BOOL,
|
//! Where 0b0001 is float and 0b0010 is bool listeners.
|
||||||
INPUT_LISTENER_FLOAT,
|
typedef enum InputType {
|
||||||
} InputListenerType;
|
INPUT_LISTENER_KEY = 0x11,
|
||||||
|
INPUT_LISTENER_GAMEPAD_BUTTON = 0x21,
|
||||||
|
INPUT_LISTENER_GAMEPAD_AXIS = 0x32,
|
||||||
|
INPUT_LISTENER_MOUSE = 0x42,
|
||||||
|
} InputType;
|
||||||
|
|
||||||
typedef void(*IntListener)(int);
|
typedef void(*BoolListener)(void*,bool);
|
||||||
typedef void(*BoolListener)(bool);
|
typedef void(*FloatListener)(void*,float);
|
||||||
typedef void(*FloatListener)(float);
|
|
||||||
|
|
||||||
typedef struct InputListener {
|
typedef struct InputListener {
|
||||||
void *object;
|
void *object;
|
||||||
InputListenerType type;
|
BoolListener button_listener;
|
||||||
union {
|
FloatListener axis_listener;
|
||||||
IntListener int_listener;
|
|
||||||
BoolListener bool_listener;
|
|
||||||
FloatListener float_listener;
|
|
||||||
};
|
|
||||||
} InputListener;
|
} InputListener;
|
||||||
|
|
||||||
void InitInputSubmodule();
|
#define ButtonInputListener(object_, function_) ((InputListener){.object = object_, .button_listener = (void(*)(void*, bool))function_, .axis_listener = NULL})
|
||||||
void CleanInputSubmodule();
|
#define AxisInputListener(object_, function_) ((InputListener){.object = object_, .button_listener = NULL, .axis_listener = (void(*)(void*, float))function_})
|
||||||
|
|
||||||
void AddListener();
|
extern void InitializeInputSubsystem();
|
||||||
void RemoveListener();
|
extern void CleanInputSubsystem();
|
||||||
|
|
||||||
|
extern void Internal_UpdateInput();
|
||||||
|
|
||||||
|
extern void AddAction(char const *action_name, InputType dev_type, int device, int input);
|
||||||
|
|
||||||
|
extern void AddListener(char const *action, InputListener listener);
|
||||||
|
extern void RemoveListener(char const *action, void *object);
|
||||||
|
extern void RemoveAllListeners(void *object);
|
||||||
|
|
||||||
#endif // !INPUT_H
|
#endif // !INPUT_H
|
||||||
|
|
|
@ -119,9 +119,9 @@ void InitializeResourceSubsystem() {
|
||||||
|
|
||||||
void CleanResourceSubsystem() {
|
void CleanResourceSubsystem() {
|
||||||
List resources = hash_map_values(&g_resource_map);
|
List resources = hash_map_values(&g_resource_map);
|
||||||
list_foreach(ResourceContainer *,resource, &resources)
|
list_foreach(ResourceContainer **,resource, &resources)
|
||||||
if(resource->is_loaded)
|
if((*resource)->is_loaded)
|
||||||
g_unload_functions[resource->type](resource);
|
g_unload_functions[(*resource)->type](*resource);
|
||||||
hash_map_empty(&g_resource_map);
|
hash_map_empty(&g_resource_map);
|
||||||
UnloadDirectoryFiles(g_resource_files);
|
UnloadDirectoryFiles(g_resource_files);
|
||||||
}
|
}
|
||||||
|
|
12
src/main.c
12
src/main.c
|
@ -1,5 +1,6 @@
|
||||||
#include "raylib.h"
|
#include "raylib.h"
|
||||||
#include "test_object.h"
|
#include "test_object.h"
|
||||||
|
#include "core/input.h"
|
||||||
#include "core/camera_node.h"
|
#include "core/camera_node.h"
|
||||||
#include "core/engine_global.h"
|
#include "core/engine_global.h"
|
||||||
#include "core/engine_loop.h"
|
#include "core/engine_loop.h"
|
||||||
|
@ -15,7 +16,7 @@ SceneNode *CreateCameraScene() {
|
||||||
// set camera parent offset
|
// set camera parent offset
|
||||||
Transformable transformable = TC_CAST(camera_parent->entity, Transformable);
|
Transformable transformable = TC_CAST(camera_parent->entity, Transformable);
|
||||||
Transform transform = transformable.tc->get_transform(transformable.data);
|
Transform transform = transformable.tc->get_transform(transformable.data);
|
||||||
transform.translation = (Vector3){3.f, 4.f, -10.f};
|
transform.translation = (Vector3){0.f, 4.f, -10.f};
|
||||||
transform.rotation = QuaternionFromEuler(7.5f * DEG2RAD, 0.f, 0.f);
|
transform.rotation = QuaternionFromEuler(7.5f * DEG2RAD, 0.f, 0.f);
|
||||||
transformable.tc->set_transform(transformable.data, transform);
|
transformable.tc->set_transform(transformable.data, transform);
|
||||||
return camera_parent;
|
return camera_parent;
|
||||||
|
@ -30,7 +31,6 @@ SceneNode *CreateModelScene() {
|
||||||
// move the renderer's parent transform
|
// move the renderer's parent transform
|
||||||
Transformable transformable = TC_CAST(model_parent->entity, Transformable);
|
Transformable transformable = TC_CAST(model_parent->entity, Transformable);
|
||||||
Transform transform = transformable.tc->get_global_transform(transformable.data);
|
Transform transform = transformable.tc->get_global_transform(transformable.data);
|
||||||
transform.translation.y += 10;
|
|
||||||
transformable.tc->set_global_transform(transformable.data, transform);
|
transformable.tc->set_global_transform(transformable.data, transform);
|
||||||
return model_parent;
|
return model_parent;
|
||||||
}
|
}
|
||||||
|
@ -43,8 +43,16 @@ Scene *CreateInitialScene() {
|
||||||
return CreateScene(root);
|
return CreateScene(root);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ConfigureInput() {
|
||||||
|
AddAction("pitch_up", INPUT_LISTENER_KEY, 0, KEY_S);
|
||||||
|
AddAction("pitch_down", INPUT_LISTENER_KEY, 0, KEY_W);
|
||||||
|
AddAction("roll_left", INPUT_LISTENER_KEY, 0, KEY_A);
|
||||||
|
AddAction("roll_right", INPUT_LISTENER_KEY, 0, KEY_D);
|
||||||
|
}
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
InitializeEngine();
|
InitializeEngine();
|
||||||
|
ConfigureInput();
|
||||||
RunGame(CreateInitialScene());
|
RunGame(CreateInitialScene());
|
||||||
UNREACHABLE("main: End of main function reached. This is an error, call ShutDown() when exiting instead.");
|
UNREACHABLE("main: End of main function reached. This is an error, call ShutDown() when exiting instead.");
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
#include "test_object.h"
|
#include "test_object.h"
|
||||||
#include "core/render.h"
|
#include "core/render.h"
|
||||||
|
#include "utils/debug.h"
|
||||||
|
#include "core/input.h"
|
||||||
#include "raylib.h"
|
#include "raylib.h"
|
||||||
|
|
||||||
START_REFLECT(TestObject);
|
START_REFLECT(TestObject);
|
||||||
|
@ -34,6 +36,10 @@ void DestroyTestObject(TestObject *self) {
|
||||||
void TestObjectEnterTree(TestObject *self) {
|
void TestObjectEnterTree(TestObject *self) {
|
||||||
self->transform = TC_CAST(self->node->parent->entity, Transformable);
|
self->transform = TC_CAST(self->node->parent->entity, Transformable);
|
||||||
AddRenderable(TestObject_as_Renderable(self));
|
AddRenderable(TestObject_as_Renderable(self));
|
||||||
|
AddListener("pitch_up", ButtonInputListener(self, TestObjectUpInput));
|
||||||
|
AddListener("pitch_down", ButtonInputListener(self, TestObjectDownInput));
|
||||||
|
AddListener("roll_left", ButtonInputListener(self, TestObjectLeftInput));
|
||||||
|
AddListener("roll_right", ButtonInputListener(self, TestObjectRightInput));
|
||||||
}
|
}
|
||||||
|
|
||||||
void TestObjectExitTree(TestObject *self) {
|
void TestObjectExitTree(TestObject *self) {
|
||||||
|
@ -46,8 +52,27 @@ void TestObjectDraw(TestObject *self) {
|
||||||
void TestObjectTick(TestObject *self, double delta) {
|
void TestObjectTick(TestObject *self, double delta) {
|
||||||
Transform global_transform = self->transform.tc->get_global_transform(self->transform.data);
|
Transform global_transform = self->transform.tc->get_global_transform(self->transform.data);
|
||||||
Matrix global_matrix = TransformGetMatrix(global_transform);
|
Matrix global_matrix = TransformGetMatrix(global_transform);
|
||||||
global_transform.rotation = QuaternionMultiply(global_transform.rotation, QuaternionFromAxisAngle(MATRIX_RIGHT(global_matrix), -3.f * delta));
|
|
||||||
global_matrix = TransformGetMatrix(global_transform);
|
|
||||||
global_transform.translation = Vector3Add(global_transform.translation, Vector3Scale(MATRIX_FORWARD(global_matrix), 2.f * delta));
|
global_transform.translation = Vector3Add(global_transform.translation, Vector3Scale(MATRIX_FORWARD(global_matrix), 2.f * delta));
|
||||||
|
global_transform.rotation = QuaternionMultiply(QuaternionFromAxisAngle(MATRIX_FORWARD(global_matrix), self->fly_input.x * 3.f * delta), global_transform.rotation);
|
||||||
|
global_transform.rotation = QuaternionMultiply(QuaternionFromAxisAngle(MATRIX_RIGHT(global_matrix), self->fly_input.y * 3.f * delta), global_transform.rotation);
|
||||||
self->transform.tc->set_global_transform(self->transform.data, global_transform);
|
self->transform.tc->set_global_transform(self->transform.data, global_transform);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void TestObjectLeftInput(TestObject *self, bool value) {
|
||||||
|
self->fly_input.x += value ? -1 : +1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestObjectRightInput(TestObject *self, bool value) {
|
||||||
|
self->fly_input.x += value ? +1 : -1;
|
||||||
|
LOG_INFO("Input Right");
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestObjectUpInput(TestObject *self, bool value) {
|
||||||
|
self->fly_input.y += value ? -1 : +1;
|
||||||
|
LOG_INFO("Input Up");
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestObjectDownInput(TestObject *self, bool value) {
|
||||||
|
self->fly_input.y += value ? +1 : -1;
|
||||||
|
}
|
||||||
|
|
|
@ -12,15 +12,21 @@
|
||||||
typedef struct TestObject {
|
typedef struct TestObject {
|
||||||
SceneNode *node;
|
SceneNode *node;
|
||||||
Transformable transform;
|
Transformable transform;
|
||||||
|
Vector2 fly_input;
|
||||||
} TestObject;
|
} TestObject;
|
||||||
|
|
||||||
SceneNode *CreateTestObject();
|
SceneNode *CreateTestObject();
|
||||||
void DestroyTestObject(TestObject *self);
|
void DestroyTestObject(TestObject *self);
|
||||||
|
|
||||||
void TestObjectEnterTree(TestObject *self);
|
extern void TestObjectEnterTree(TestObject *self);
|
||||||
void TestObjectExitTree(TestObject *self);
|
extern void TestObjectExitTree(TestObject *self);
|
||||||
void TestObjectDraw(TestObject *self);
|
extern void TestObjectDraw(TestObject *self);
|
||||||
void TestObjectTick(TestObject *self, double delta);
|
extern void TestObjectTick(TestObject *self, double delta);
|
||||||
|
|
||||||
|
extern void TestObjectLeftInput(TestObject *self, bool value);
|
||||||
|
extern void TestObjectRightInput(TestObject *self, bool value);
|
||||||
|
extern void TestObjectUpInput(TestObject *self, bool value);
|
||||||
|
extern void TestObjectDownInput(TestObject *self, bool value);
|
||||||
|
|
||||||
DECL_REFLECT(TestObject);
|
DECL_REFLECT(TestObject);
|
||||||
decl_typeclass_impl(SceneNodeEntity, TestObject);
|
decl_typeclass_impl(SceneNodeEntity, TestObject);
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit af50174b71853f3ca887fc0e064e88258c412f2c
|
Subproject commit 2021092a17b810d08d655f48cadca945d26258f5
|
Loading…
Reference in a new issue