paint: merge traits
This commit is contained in:
@@ -0,0 +1,53 @@
|
||||
|
||||
#include "global.h"
|
||||
|
||||
typedef void (*trait_init_t)(char *object);
|
||||
typedef void (*trait_run_t)();
|
||||
typedef void (*trait_stop_t)();
|
||||
|
||||
typedef struct trait {
|
||||
char *name;
|
||||
trait_init_t init;
|
||||
trait_run_t run;
|
||||
trait_stop_t stop;
|
||||
} trait_t;
|
||||
|
||||
static trait_t traits[] = {
|
||||
{"third_person_controller", trait_third_person_controller_init, trait_third_person_controller_run, trait_third_person_controller_stop},
|
||||
{"point_and_click_controller", trait_point_and_click_controller_init, trait_point_and_click_controller_run, trait_point_and_click_controller_stop},
|
||||
};
|
||||
|
||||
#define TRAIT_COUNT (i32)(sizeof(traits) / sizeof(traits[0]))
|
||||
|
||||
static bool trait_attached[TRAIT_COUNT];
|
||||
|
||||
void script_add_trait(char *object, char *trait) {
|
||||
for (i32 i = 0; i < TRAIT_COUNT; ++i) {
|
||||
if (!string_equals(traits[i].name, trait)) {
|
||||
continue;
|
||||
}
|
||||
if (trait_attached[i]) {
|
||||
return;
|
||||
}
|
||||
trait_attached[i] = true;
|
||||
traits[i].init(object);
|
||||
return;
|
||||
}
|
||||
// console_error(string("Unknown trait: %s", trait));
|
||||
}
|
||||
|
||||
void trait_update() {
|
||||
for (i32 i = 0; i < TRAIT_COUNT; ++i) {
|
||||
if (trait_attached[i]) {
|
||||
traits[i].run();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void trait_stop() {
|
||||
for (i32 i = 0; i < TRAIT_COUNT; ++i) {
|
||||
if (trait_attached[i] && traits[i].stop != NULL) {
|
||||
traits[i].stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,410 @@
|
||||
|
||||
#include "../global.h"
|
||||
|
||||
#define PAC_SPEED 1.0
|
||||
#define PAC_ARRIVE 0.1
|
||||
#define PAC_CLEARANCE 0.15
|
||||
#define PAC_TERRAIN "Terrain"
|
||||
#define PAC_MAX_RECTS 32
|
||||
#define PAC_MAX_NODES (PAC_MAX_RECTS * 4 + 2)
|
||||
#define PAC_EPS 0.001
|
||||
#define PAC_FAR 1.0e30
|
||||
|
||||
static char *trait_point_and_click_controller_object = NULL;
|
||||
static quat_t trait_point_and_click_controller_rot = {0.0, 0.0, 0.0, 1.0};
|
||||
static bool trait_point_and_click_controller_moving = false;
|
||||
|
||||
typedef struct {
|
||||
f32 min_x;
|
||||
f32 min_y;
|
||||
f32 max_x;
|
||||
f32 max_y;
|
||||
} pac_rect_t;
|
||||
|
||||
static pac_rect_t pac_rects[PAC_MAX_RECTS];
|
||||
static i32 pac_rect_count = 0;
|
||||
static vec4_t pac_nodes[PAC_MAX_NODES];
|
||||
static i32 pac_node_count = 0;
|
||||
static bool pac_visible[PAC_MAX_NODES][PAC_MAX_NODES];
|
||||
static vec4_t pac_path[PAC_MAX_NODES];
|
||||
static i32 pac_path_count = 0;
|
||||
static i32 pac_path_index = 0;
|
||||
|
||||
void trait_point_and_click_controller_init(char *object) {
|
||||
gc_unroot(trait_point_and_click_controller_object);
|
||||
trait_point_and_click_controller_object = string_copy(object);
|
||||
gc_root(trait_point_and_click_controller_object);
|
||||
trait_point_and_click_controller_moving = false;
|
||||
trait_point_and_click_controller_rot = (quat_t){0.0, 0.0, 0.0, 1.0};
|
||||
pac_path_count = 0;
|
||||
pac_path_index = 0;
|
||||
}
|
||||
|
||||
static f32 pac_dist(vec4_t a, vec4_t b) {
|
||||
f32 dx = a.x - b.x;
|
||||
f32 dy = a.y - b.y;
|
||||
return math_sqrt(dx * dx + dy * dy);
|
||||
}
|
||||
|
||||
static bool pac_inside(pac_rect_t *r, vec4_t p) {
|
||||
return p.x > r->min_x && p.x < r->max_x && p.y > r->min_y && p.y < r->max_y;
|
||||
}
|
||||
|
||||
static void pac_gather_rects(asim_body_t *self) {
|
||||
pac_rect_count = 0;
|
||||
f32 grow = math_sqrt(self->dimx * self->dimx + self->dimy * self->dimy) / 2.0 + PAC_CLEARANCE;
|
||||
|
||||
mesh_object_t_array_t *objects = g_project->_->paint_objects;
|
||||
for (i32 i = 0; i < objects->length && pac_rect_count < PAC_MAX_RECTS; ++i) {
|
||||
object_t *o = objects->buffer[i]->base;
|
||||
if (o->_ == NULL || string_equals(o->name, PAC_TERRAIN)) {
|
||||
continue;
|
||||
}
|
||||
asim_body_t *body = o->_->body;
|
||||
if (body == NULL || body == self || body->shape != ASIM_SHAPE_BOX || body->mass > 0.0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
quat_t rot = o->transform->rot;
|
||||
vec4_t center = vec4_add(o->transform->loc, vec4_apply_quat(body->offset, rot));
|
||||
vec4_t half = (vec4_t){body->dimx / 2.0, body->dimy / 2.0, body->dimz / 2.0, 0.0};
|
||||
|
||||
pac_rect_t r = {PAC_FAR, PAC_FAR, -PAC_FAR, -PAC_FAR};
|
||||
for (i32 c = 0; c < 8; ++c) {
|
||||
vec4_t corner = (vec4_t){(c & 1) ? half.x : -half.x, (c & 2) ? half.y : -half.y, (c & 4) ? half.z : -half.z, 0.0};
|
||||
corner = vec4_apply_quat(corner, rot);
|
||||
r.min_x = math_min(r.min_x, center.x + corner.x);
|
||||
r.min_y = math_min(r.min_y, center.y + corner.y);
|
||||
r.max_x = math_max(r.max_x, center.x + corner.x);
|
||||
r.max_y = math_max(r.max_y, center.y + corner.y);
|
||||
}
|
||||
|
||||
r.min_x -= grow;
|
||||
r.min_y -= grow;
|
||||
r.max_x += grow;
|
||||
r.max_y += grow;
|
||||
pac_rects[pac_rect_count++] = r;
|
||||
}
|
||||
}
|
||||
|
||||
static vec4_t pac_push_out(vec4_t p) {
|
||||
for (i32 pass = 0; pass < 4; ++pass) {
|
||||
bool moved = false;
|
||||
for (i32 i = 0; i < pac_rect_count; ++i) {
|
||||
pac_rect_t *r = &pac_rects[i];
|
||||
if (!pac_inside(r, p)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
f32 left = p.x - r->min_x;
|
||||
f32 right = r->max_x - p.x;
|
||||
f32 down = p.y - r->min_y;
|
||||
f32 up = r->max_y - p.y;
|
||||
f32 best = math_min(math_min(left, right), math_min(down, up));
|
||||
if (best == left) {
|
||||
p.x = r->min_x - PAC_EPS;
|
||||
}
|
||||
else if (best == right) {
|
||||
p.x = r->max_x + PAC_EPS;
|
||||
}
|
||||
else if (best == down) {
|
||||
p.y = r->min_y - PAC_EPS;
|
||||
}
|
||||
else {
|
||||
p.y = r->max_y + PAC_EPS;
|
||||
}
|
||||
moved = true;
|
||||
}
|
||||
if (!moved) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
static bool pac_clip_slab(f32 origin, f32 dir, f32 lo, f32 hi, f32 *t0, f32 *t1) {
|
||||
if (math_abs(dir) < 1e-6) {
|
||||
return origin >= lo && origin <= hi;
|
||||
}
|
||||
|
||||
f32 ta = (lo - origin) / dir;
|
||||
f32 tb = (hi - origin) / dir;
|
||||
if (ta > tb) {
|
||||
f32 tmp = ta;
|
||||
ta = tb;
|
||||
tb = tmp;
|
||||
}
|
||||
if (ta > *t0) {
|
||||
*t0 = ta;
|
||||
}
|
||||
if (tb < *t1) {
|
||||
*t1 = tb;
|
||||
}
|
||||
return *t0 <= *t1;
|
||||
}
|
||||
|
||||
static bool pac_crosses(vec4_t a, vec4_t b, pac_rect_t *r) {
|
||||
f32 min_x = r->min_x + PAC_EPS;
|
||||
f32 max_x = r->max_x - PAC_EPS;
|
||||
f32 min_y = r->min_y + PAC_EPS;
|
||||
f32 max_y = r->max_y - PAC_EPS;
|
||||
if (min_x >= max_x || min_y >= max_y) {
|
||||
return false;
|
||||
}
|
||||
|
||||
f32 t0 = 0.0;
|
||||
f32 t1 = 1.0;
|
||||
return pac_clip_slab(a.x, b.x - a.x, min_x, max_x, &t0, &t1) && pac_clip_slab(a.y, b.y - a.y, min_y, max_y, &t0, &t1);
|
||||
}
|
||||
|
||||
static bool pac_clear(vec4_t a, vec4_t b) {
|
||||
for (i32 i = 0; i < pac_rect_count; ++i) {
|
||||
if (pac_crosses(a, b, &pac_rects[i])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static void pac_build_nodes(vec4_t start, vec4_t goal) {
|
||||
pac_nodes[0] = start;
|
||||
pac_nodes[1] = goal;
|
||||
pac_node_count = 2;
|
||||
|
||||
for (i32 i = 0; i < pac_rect_count; ++i) {
|
||||
pac_rect_t *r = &pac_rects[i];
|
||||
vec4_t corners[4] = {{r->min_x, r->min_y, 0.0, 1.0}, {r->max_x, r->min_y, 0.0, 1.0}, {r->max_x, r->max_y, 0.0, 1.0}, {r->min_x, r->max_y, 0.0, 1.0}};
|
||||
|
||||
for (i32 c = 0; c < 4; ++c) {
|
||||
bool standable = true;
|
||||
for (i32 j = 0; j < pac_rect_count && standable; ++j) {
|
||||
standable = !pac_inside(&pac_rects[j], corners[c]);
|
||||
}
|
||||
if (standable) {
|
||||
pac_nodes[pac_node_count++] = corners[c];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void pac_build_visibility() {
|
||||
for (i32 i = 0; i < pac_node_count; ++i) {
|
||||
pac_visible[i][i] = false;
|
||||
for (i32 j = i + 1; j < pac_node_count; ++j) {
|
||||
bool clear = pac_clear(pac_nodes[i], pac_nodes[j]);
|
||||
pac_visible[i][j] = clear;
|
||||
pac_visible[j][i] = clear;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static bool pac_search() {
|
||||
f32 dist[PAC_MAX_NODES];
|
||||
i32 prev[PAC_MAX_NODES];
|
||||
bool done[PAC_MAX_NODES];
|
||||
|
||||
for (i32 i = 0; i < pac_node_count; ++i) {
|
||||
dist[i] = PAC_FAR;
|
||||
prev[i] = -1;
|
||||
done[i] = false;
|
||||
}
|
||||
dist[0] = 0.0;
|
||||
|
||||
for (;;) {
|
||||
i32 u = -1;
|
||||
for (i32 i = 0; i < pac_node_count; ++i) {
|
||||
if (!done[i] && dist[i] < PAC_FAR && (u == -1 || dist[i] < dist[u])) {
|
||||
u = i;
|
||||
}
|
||||
}
|
||||
if (u == -1 || u == 1) {
|
||||
break;
|
||||
}
|
||||
|
||||
done[u] = true;
|
||||
for (i32 v = 0; v < pac_node_count; ++v) {
|
||||
if (done[v] || !pac_visible[u][v]) {
|
||||
continue;
|
||||
}
|
||||
f32 d = dist[u] + pac_dist(pac_nodes[u], pac_nodes[v]);
|
||||
if (d < dist[v]) {
|
||||
dist[v] = d;
|
||||
prev[v] = u;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (dist[1] >= PAC_FAR) {
|
||||
return false;
|
||||
}
|
||||
|
||||
i32 chain[PAC_MAX_NODES];
|
||||
i32 count = 0;
|
||||
for (i32 n = 1; n != -1; n = prev[n]) {
|
||||
chain[count++] = n;
|
||||
}
|
||||
|
||||
pac_path_count = 0;
|
||||
for (i32 i = count - 2; i >= 0; --i) {
|
||||
pac_path[pac_path_count++] = pac_nodes[chain[i]];
|
||||
}
|
||||
pac_path_index = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool pac_plan(asim_body_t *body, vec4_t goal) {
|
||||
vec4_t pos;
|
||||
asim_body_get_pos(body->_body, &pos);
|
||||
|
||||
pac_gather_rects(body);
|
||||
vec4_t start = pac_push_out((vec4_t){pos.x, pos.y, 0.0, 1.0});
|
||||
goal = pac_push_out((vec4_t){goal.x, goal.y, 0.0, 1.0});
|
||||
|
||||
if (pac_clear(start, goal)) {
|
||||
pac_path[0] = goal;
|
||||
pac_path_count = 1;
|
||||
pac_path_index = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
pac_build_nodes(start, goal);
|
||||
pac_build_visibility();
|
||||
return pac_search();
|
||||
}
|
||||
|
||||
static quat_t trait_point_and_click_controller_facing(vec4_t dir) {
|
||||
return quat_from_axis_angle(vec4_z_axis(), math_atan2(-dir.x, dir.y) + math_pi());
|
||||
}
|
||||
|
||||
static object_t *trait_point_and_click_controller_run_object(object_t *o) {
|
||||
return script_get_object(string("%s_run", o->name));
|
||||
}
|
||||
|
||||
static void trait_point_and_click_controller_set_moving(object_t *o, bool moving) {
|
||||
if (moving == trait_point_and_click_controller_moving) {
|
||||
return;
|
||||
}
|
||||
object_t *run = trait_point_and_click_controller_run_object(o);
|
||||
if (run == NULL) {
|
||||
return;
|
||||
}
|
||||
trait_point_and_click_controller_moving = moving;
|
||||
o->visible = !moving;
|
||||
run->visible = moving;
|
||||
}
|
||||
|
||||
static void trait_point_and_click_controller_place(asim_body_t *body) {
|
||||
if (!trait_point_and_click_controller_moving) {
|
||||
return;
|
||||
}
|
||||
object_t *run = trait_point_and_click_controller_run_object(body->obj);
|
||||
if (run == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
vec4_t pos;
|
||||
asim_body_get_pos(body->_body, &pos);
|
||||
quat_t rot = trait_point_and_click_controller_rot;
|
||||
vec4_t off = vec4_apply_quat(body->offset, rot);
|
||||
|
||||
transform_t *t = run->transform;
|
||||
t->loc = (vec4_t){pos.x - off.x, pos.y - off.y, pos.z - off.z, 1.0};
|
||||
t->rot = rot;
|
||||
transform_build_matrix(t);
|
||||
}
|
||||
|
||||
static void trait_point_and_click_controller_terrain() {
|
||||
object_t *o = script_get_object(PAC_TERRAIN);
|
||||
if (o == NULL || o->_ == NULL) {
|
||||
return;
|
||||
}
|
||||
asim_body_t *body = o->_->body;
|
||||
if (body == NULL || body->shape != ASIM_SHAPE_TERRAIN) {
|
||||
script_physics_set_shape(o, ASIM_SHAPE_TERRAIN);
|
||||
}
|
||||
}
|
||||
|
||||
static bool trait_point_and_click_controller_pick(vec4_t *target) {
|
||||
f32 mx = mouse_view_x();
|
||||
f32 my = mouse_view_y();
|
||||
if (mx < 0.0 || my < 0.0 || mx > sys_w() || my > sys_h()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
trait_point_and_click_controller_terrain();
|
||||
ray_t *ray = raycast_get_ray(mx, my, scene_camera);
|
||||
return asim_terrain_raycast(ray->origin, ray->dir, target);
|
||||
}
|
||||
|
||||
static bool trait_point_and_click_controller_move(asim_body_t *body) {
|
||||
vec4_t vel;
|
||||
asim_body_get_velocity(body->_body, &vel);
|
||||
vec4_t pos;
|
||||
asim_body_get_pos(body->_body, &pos);
|
||||
|
||||
while (pac_path_index < pac_path_count && pac_dist(pac_path[pac_path_index], pos) <= PAC_ARRIVE) {
|
||||
pac_path_index++;
|
||||
}
|
||||
if (pac_path_index >= pac_path_count) {
|
||||
asim_body_set_velocity(body->_body, 0.0, 0.0, vel.z);
|
||||
return false;
|
||||
}
|
||||
|
||||
vec4_t target = pac_path[pac_path_index];
|
||||
f32 dist = pac_dist(target, pos);
|
||||
vec4_t dir = (vec4_t){(target.x - pos.x) / dist, (target.y - pos.y) / dist, 0.0, 0.0};
|
||||
|
||||
f32 speed = PAC_SPEED;
|
||||
f32 delta = sys_delta();
|
||||
if (pac_path_index == pac_path_count - 1 && delta > 0.0 && dist / delta < speed) {
|
||||
speed = dist / delta;
|
||||
}
|
||||
asim_body_set_velocity(body->_body, dir.x * speed, dir.y * speed, vel.z);
|
||||
|
||||
trait_point_and_click_controller_rot = trait_point_and_click_controller_facing(dir);
|
||||
asim_body_set_rotation(body, trait_point_and_click_controller_rot);
|
||||
return true;
|
||||
}
|
||||
|
||||
static asim_body_t *trait_point_and_click_controller_body(object_t *o) {
|
||||
asim_body_t *body = o->_->body;
|
||||
if (body != NULL && body->shape == ASIM_SHAPE_BOX && body->mass > 0.0) {
|
||||
return body;
|
||||
}
|
||||
script_physics_set_shape(o, ASIM_SHAPE_BOX);
|
||||
return o->_->body;
|
||||
}
|
||||
|
||||
void trait_point_and_click_controller_run() {
|
||||
object_t *o = script_get_object(trait_point_and_click_controller_object);
|
||||
if (o == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
asim_body_t *body = trait_point_and_click_controller_body(o);
|
||||
if (body == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
vec4_t target;
|
||||
if (mouse_started("left") && trait_point_and_click_controller_pick(&target) && !pac_plan(body, target)) {
|
||||
pac_path_count = 0;
|
||||
pac_path_index = 0;
|
||||
}
|
||||
|
||||
bool moving = trait_point_and_click_controller_move(body);
|
||||
trait_point_and_click_controller_set_moving(o, moving);
|
||||
trait_point_and_click_controller_place(body);
|
||||
if (moving) {
|
||||
g_context->ddirty = 2;
|
||||
}
|
||||
}
|
||||
|
||||
void trait_point_and_click_controller_stop() {
|
||||
pac_path_count = 0;
|
||||
pac_path_index = 0;
|
||||
object_t *o = script_get_object(trait_point_and_click_controller_object);
|
||||
if (o != NULL) {
|
||||
trait_point_and_click_controller_set_moving(o, false);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,185 @@
|
||||
|
||||
#include "../global.h"
|
||||
|
||||
#define TPC_SENSITIVITY 0.0025
|
||||
#define TPC_PITCH_MIN (-1.3)
|
||||
#define TPC_PITCH_MAX 0.6
|
||||
#define TPC_SPEED 2.0
|
||||
#define TPC_CAMERA_DIST 3.5
|
||||
#define TPC_CAMERA_FOCUS 0.45
|
||||
|
||||
static char *trait_third_person_controller_object = NULL;
|
||||
static f32 trait_third_person_controller_yaw = 0.0;
|
||||
static f32 trait_third_person_controller_pitch = 0.0;
|
||||
static bool trait_third_person_controller_moving = false;
|
||||
|
||||
void trait_third_person_controller_init(char *object) {
|
||||
gc_unroot(trait_third_person_controller_object);
|
||||
trait_third_person_controller_object = string_copy(object);
|
||||
gc_root(trait_third_person_controller_object);
|
||||
trait_third_person_controller_moving = false;
|
||||
}
|
||||
|
||||
static quat_t trait_third_person_controller_facing() {
|
||||
return quat_from_axis_angle(vec4_z_axis(), trait_third_person_controller_yaw + math_pi());
|
||||
}
|
||||
|
||||
static vec4_t trait_third_person_controller_look() {
|
||||
f32 cp = math_cos(trait_third_person_controller_pitch);
|
||||
return (vec4_t){-math_sin(trait_third_person_controller_yaw) * cp, math_cos(trait_third_person_controller_yaw) * cp,
|
||||
math_sin(trait_third_person_controller_pitch), 0.0};
|
||||
}
|
||||
|
||||
static void trait_third_person_controller_grab() {
|
||||
vec4_t look = camera_object_look_world(scene_camera);
|
||||
trait_third_person_controller_yaw = math_atan2(-look.x, look.y);
|
||||
trait_third_person_controller_pitch = math_asin(math_max(math_min(look.z, 1.0), -1.0));
|
||||
trait_third_person_controller_pitch = math_max(math_min(trait_third_person_controller_pitch, TPC_PITCH_MAX), TPC_PITCH_MIN);
|
||||
iron_mouse_lock();
|
||||
}
|
||||
|
||||
static void trait_third_person_controller_rotate() {
|
||||
if (mouse_movement_x == 0 && mouse_movement_y == 0) {
|
||||
return;
|
||||
}
|
||||
trait_third_person_controller_yaw -= mouse_movement_x * TPC_SENSITIVITY;
|
||||
trait_third_person_controller_pitch -= mouse_movement_y * TPC_SENSITIVITY;
|
||||
trait_third_person_controller_pitch = math_max(math_min(trait_third_person_controller_pitch, TPC_PITCH_MAX), TPC_PITCH_MIN);
|
||||
}
|
||||
|
||||
static object_t *trait_third_person_controller_run_object(object_t *o) {
|
||||
return script_get_object(string("%s_run", o->name));
|
||||
}
|
||||
|
||||
static void trait_third_person_controller_set_moving(object_t *o, bool moving) {
|
||||
if (moving == trait_third_person_controller_moving) {
|
||||
return;
|
||||
}
|
||||
object_t *run = trait_third_person_controller_run_object(o);
|
||||
if (run == NULL) {
|
||||
return;
|
||||
}
|
||||
trait_third_person_controller_moving = moving;
|
||||
o->visible = !moving;
|
||||
run->visible = moving;
|
||||
}
|
||||
|
||||
static void trait_third_person_controller_place(asim_body_t *body) {
|
||||
if (!trait_third_person_controller_moving) {
|
||||
return;
|
||||
}
|
||||
object_t *run = trait_third_person_controller_run_object(body->obj);
|
||||
if (run == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
vec4_t pos;
|
||||
asim_body_get_pos(body->_body, &pos);
|
||||
quat_t rot = trait_third_person_controller_facing();
|
||||
vec4_t off = vec4_apply_quat(body->offset, rot);
|
||||
|
||||
transform_t *t = run->transform;
|
||||
t->loc = (vec4_t){pos.x - off.x, pos.y - off.y, pos.z - off.z, 1.0};
|
||||
t->rot = rot;
|
||||
transform_build_matrix(t);
|
||||
}
|
||||
|
||||
static bool trait_third_person_controller_move(asim_body_t *body) {
|
||||
f32 s = math_sin(trait_third_person_controller_yaw);
|
||||
f32 c = math_cos(trait_third_person_controller_yaw);
|
||||
vec4_t forward = (vec4_t){-s, c, 0.0, 0.0};
|
||||
vec4_t right = (vec4_t){c, s, 0.0, 0.0};
|
||||
vec4_t dir = (vec4_t){0.0, 0.0, 0.0, 0.0};
|
||||
|
||||
if (keyboard_down("w")) {
|
||||
dir = vec4_add(dir, forward);
|
||||
}
|
||||
if (keyboard_down("s")) {
|
||||
dir = vec4_sub(dir, forward);
|
||||
}
|
||||
if (keyboard_down("d")) {
|
||||
dir = vec4_add(dir, right);
|
||||
}
|
||||
if (keyboard_down("a")) {
|
||||
dir = vec4_sub(dir, right);
|
||||
}
|
||||
|
||||
vec4_t vel;
|
||||
asim_body_get_velocity(body->_body, &vel);
|
||||
bool moving = dir.x != 0.0 || dir.y != 0.0;
|
||||
if (moving) {
|
||||
dir = vec4_norm(dir);
|
||||
asim_body_set_velocity(body->_body, dir.x * TPC_SPEED, dir.y * TPC_SPEED, vel.z);
|
||||
}
|
||||
else {
|
||||
asim_body_set_velocity(body->_body, 0.0, 0.0, vel.z);
|
||||
}
|
||||
|
||||
asim_body_set_rotation(body, trait_third_person_controller_facing());
|
||||
return moving;
|
||||
}
|
||||
|
||||
static void trait_third_person_controller_follow(asim_body_t *body) {
|
||||
vec4_t pos;
|
||||
asim_body_get_pos(body->_body, &pos);
|
||||
|
||||
f32 size = math_sqrt(body->dimx * body->dimx + body->dimy * body->dimy + body->dimz * body->dimz);
|
||||
f32 dist = (size > 0.0 ? size : 1.0) * TPC_CAMERA_DIST;
|
||||
vec4_t look = trait_third_person_controller_look();
|
||||
vec4_t focus = (vec4_t){pos.x, pos.y, pos.z + body->dimz * TPC_CAMERA_FOCUS, 1.0};
|
||||
|
||||
transform_t *ct = scene_camera->base->transform;
|
||||
ct->loc = (vec4_t){focus.x - look.x * dist, focus.y - look.y * dist, focus.z - look.z * dist, 1.0};
|
||||
ct->rot = quat_mult(quat_from_axis_angle(vec4_z_axis(), trait_third_person_controller_yaw),
|
||||
quat_from_axis_angle(vec4_x_axis(), math_pi() / 2.0 + trait_third_person_controller_pitch));
|
||||
camera_object_build_mat(scene_camera);
|
||||
g_context->ddirty = 2;
|
||||
}
|
||||
|
||||
static asim_body_t *trait_third_person_controller_body(object_t *o) {
|
||||
asim_body_t *body = o->_->body;
|
||||
if (body != NULL && body->shape == ASIM_SHAPE_BOX && body->mass > 0.0) {
|
||||
return body;
|
||||
}
|
||||
script_physics_set_shape(o, ASIM_SHAPE_BOX);
|
||||
return o->_->body;
|
||||
}
|
||||
|
||||
void trait_third_person_controller_run() {
|
||||
object_t *o = script_get_object(trait_third_person_controller_object);
|
||||
if (o == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
asim_body_t *body = trait_third_person_controller_body(o);
|
||||
if (body == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
bool control = iron_mouse_is_locked();
|
||||
if (control && keyboard_started("escape")) {
|
||||
iron_mouse_unlock();
|
||||
control = false;
|
||||
}
|
||||
else if (!control && mouse_started("left")) {
|
||||
trait_third_person_controller_grab();
|
||||
control = iron_mouse_is_locked();
|
||||
}
|
||||
|
||||
if (!control) {
|
||||
trait_third_person_controller_set_moving(o, false);
|
||||
return;
|
||||
}
|
||||
|
||||
trait_third_person_controller_rotate();
|
||||
trait_third_person_controller_set_moving(o, trait_third_person_controller_move(body));
|
||||
trait_third_person_controller_place(body);
|
||||
trait_third_person_controller_follow(body);
|
||||
}
|
||||
|
||||
void trait_third_person_controller_stop() {
|
||||
object_t *o = script_get_object(trait_third_person_controller_object);
|
||||
if (o != NULL) {
|
||||
trait_third_person_controller_set_moving(o, false);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user