Compare commits

...

5 Commits

@ -1,6 +1,8 @@
#include <chipmunk.h>
#include "types.h"
#include "ipsettings.h" // debug/developer settings
#include <stdio.h> // assert logging
#include <string.h> // memset
@ -229,6 +231,12 @@ void grid_create(GameState* gs, Entity* e)
create_body(gs, e);
}
void entity_set_rotation(Entity* e, float rot)
{
assert(e->body != NULL);
cpBodySetAngle(e->body, rot);
}
void entity_set_pos(Entity* e, V2 pos)
{
assert(e->is_grid);
@ -295,12 +303,8 @@ void box_create(GameState* gs, Entity* new_box, Entity* grid, V2 pos)
// removes boxes from grid, then ensures that the rule that grids must not have
// holes in them is applied.
static void grid_remove_box(GameState* gs, struct Entity* grid, struct Entity* box)
static void grid_correct_for_holes(GameState* gs, struct Entity* grid)
{
assert(grid->is_grid);
assert(box->is_box);
entity_destroy(gs, box);
int num_boxes = grid_num_boxes(gs, grid);
if (num_boxes == 0)
{
@ -447,6 +451,14 @@ static void grid_remove_box(GameState* gs, struct Entity* grid, struct Entity* b
}
}
static void grid_remove_box(GameState* gs, struct Entity* grid, struct Entity* box)
{
assert(grid->is_grid);
assert(box->is_box);
entity_destroy(gs, box);
grid_correct_for_holes(gs, grid);
}
static cpBool on_damage(cpArbiter* arb, cpSpace* space, cpDataPointer userData)
{
cpShape* a, * b;
@ -653,7 +665,7 @@ void ser_var(SerState* ser, char* var_pointer, size_t var_size, const char* name
}
}
#define SER_VAR_NAME(var_pointer, name) ser_var(ser, (char*)var_pointer, sizeof(var_pointer), name, __FILE__, __LINE__)
#define SER_VAR_NAME(var_pointer, name) ser_var(ser, (char*)var_pointer, sizeof(*var_pointer), name, __FILE__, __LINE__)
#define SER_VAR(var_pointer) SER_VAR_NAME(var_pointer, #var_pointer)
void ser_V2(SerState* ser, V2* var)
@ -676,7 +688,7 @@ void ser_entityid(SerState* ser, EntityID* id)
SER_VAR(&id->index);
}
void ser_inputframe(SerState* ser, struct InputFrame* i)
void ser_inputframe(SerState* ser, InputFrame* i)
{
SER_VAR(&i->tick);
SER_VAR(&i->movement);
@ -684,11 +696,11 @@ void ser_inputframe(SerState* ser, struct InputFrame* i)
SER_VAR(&i->seat_action);
ser_entityid(ser, &i->seat_to_inhabit);
SER_VAR(&i->hand_pos);
ser_entityid(ser, &i->grid_hand_pos_local_to);
SER_VAR(&i->dobuild);
SER_VAR(&i->build_type);
SER_VAR(&i->build_rotation);
ser_entityid(ser, &i->grid_to_build_on);
}
void ser_player(SerState* ser, Player* p)
@ -941,9 +953,9 @@ Entity* closest_to_point_in_radius(GameState* gs, V2 point, float radius)
return NULL;
}
V2 thruster_direction(Entity* box)
V2 box_facing_vector(Entity* box)
{
assert(box->is_box && box->box_type == BoxThruster);
assert(box->is_box);
V2 to_return = (V2){ .x = 1.0f, .y = 0.0f };
to_return = V2rotate(to_return, rotangle(box->compass_rotation));
@ -954,7 +966,7 @@ V2 thruster_direction(Entity* box)
V2 thruster_force(Entity* box)
{
return V2scale(thruster_direction(box), -box->thrust * THRUSTER_FORCE);
return V2scale(box_facing_vector(box), -box->thrust * THRUSTER_FORCE);
}
uint64_t tick(GameState* gs)
@ -962,6 +974,18 @@ uint64_t tick(GameState* gs)
return (uint64_t)floor(gs->time / ((double)TIMESTEP));
}
V2 get_world_hand_pos(GameState* gs, InputFrame* input, Entity* player)
{
Entity* potential_grid = get_entity(gs, input->grid_hand_pos_local_to);
if (potential_grid != NULL)
{
return grid_local_to_world(potential_grid, input->hand_pos);
}
else {
return input->hand_pos;
}
}
void process(GameState* gs, float dt)
{
assert(gs->space != NULL);
@ -984,6 +1008,10 @@ void process(GameState* gs, float dt)
}
assert(p->is_player);
if (INFINITE_RESOURCES)
{
p->spice_taken_away = 0.0f;
}
// update gold win condition
if (V2length(V2sub(cp_to_v2(cpBodyGetPosition(p->body)), gs->goldpos)) < GOLD_COLLECT_RADIUS)
{
@ -993,6 +1021,7 @@ void process(GameState* gs, float dt)
}
#if 1
V2 world_hand_pos = get_world_hand_pos(gs, &player->input, p);
if (player->input.seat_action)
{
player->input.seat_action = false; // "handle" the input
@ -1000,7 +1029,7 @@ void process(GameState* gs, float dt)
if (the_seat == NULL) // not piloting any seat
{
cpPointQueryInfo query_info = { 0 };
cpShape* result = cpSpacePointQueryNearest(gs->space, v2_to_cp(player->input.hand_pos), 0.1f, cpShapeFilterNew(CP_NO_GROUP, CP_ALL_CATEGORIES, BOXES), &query_info);
cpShape* result = cpSpacePointQueryNearest(gs->space, v2_to_cp(world_hand_pos), 0.1f, cpShapeFilterNew(CP_NO_GROUP, CP_ALL_CATEGORIES, BOXES), &query_info);
if (result != NULL)
{
Entity* potential_seat = cp_shape_entity(result);
@ -1013,12 +1042,13 @@ void process(GameState* gs, float dt)
}
else
{
Log("No ship above player at point %f %f\n", player->input.hand_pos.x, player->input.hand_pos.y);
Log("No ship above player at point %f %f\n", world_hand_pos.x, world_hand_pos.y);
}
}
else
{
V2 pilot_seat_exit_spot = V2add(box_pos(the_seat), V2rotate((V2) { .x = BOX_SIZE }, rotangle(the_seat->compass_rotation)));
V2 pilot_seat_exit_spot = V2add(box_pos(the_seat), V2scale(box_facing_vector(the_seat), BOX_SIZE));
cpBodySetPosition(p->body, v2_to_cp(pilot_seat_exit_spot));
cpBodySetVelocity(p->body, v2_to_cp(player_vel(gs, p)));
the_seat->piloted_by = (EntityID){ 0 };
@ -1061,7 +1091,7 @@ void process(GameState* gs, float dt)
{
if (cur->box_type != BoxThruster)
continue;
float wanted_thrust = -V2dot(target_direction, thruster_direction(cur));
float wanted_thrust = -V2dot(target_direction, box_facing_vector(cur));
wanted_thrust = clamp01(wanted_thrust);
cur->wanted_thrust = wanted_thrust;
}
@ -1075,10 +1105,10 @@ void process(GameState* gs, float dt)
player->input.dobuild = false; // handle the input. if didn't do this, after destruction of hovered box, would try to build on its grid with grid_index...
cpPointQueryInfo info = { 0 };
V2 world_build = player->input.hand_pos;
V2 world_build = world_hand_pos;
// @Robust sanitize this input so player can't build on any grid in the world
Entity* target_grid = get_entity(gs, player->input.grid_to_build_on);
Entity* target_grid = get_entity(gs, player->input.grid_hand_pos_local_to);
cpShape* nearest = cpSpacePointQueryNearest(gs->space, v2_to_cp(world_build), 0.01f, cpShapeFilterNew(CP_NO_GROUP, CP_ALL_CATEGORIES, BOXES), &info);
if (nearest != NULL)
{
@ -1104,6 +1134,7 @@ void process(GameState* gs, float dt)
{
Entity* new_box = new_entity(gs);
box_create(gs, new_box, target_grid, grid_world_to_local(target_grid, world_build));
grid_correct_for_holes(gs, target_grid); // no holey ship for you!
new_box->box_type = player->input.build_type;
new_box->compass_rotation = player->input.build_rotation;
p->spice_taken_away += 0.1f;
@ -1134,8 +1165,6 @@ void process(GameState* gs, float dt)
}
if (e->is_grid)
{
float thruster_energy_consumption_per_second = 0.0f;
BOXES_ITER(gs, cur, e)
{
if (cur->box_type == BoxThruster)
@ -1149,6 +1178,7 @@ void process(GameState* gs, float dt)
possible_battery->energy_used += energy_to_consume;
cur->thrust = cur->wanted_thrust;
cpBodyApplyForceAtWorldPoint(e->body, v2_to_cp(thruster_force(cur)), v2_to_cp(box_pos(cur)));
break;
}
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.3 KiB

After

Width:  |  Height:  |  Size: 385 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 727 B

After

Width:  |  Height:  |  Size: 264 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 840 B

After

Width:  |  Height:  |  Size: 404 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.6 KiB

After

Width:  |  Height:  |  Size: 291 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 734 B

After

Width:  |  Height:  |  Size: 537 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.4 KiB

After

Width:  |  Height:  |  Size: 272 B

@ -420,7 +420,7 @@ frame(void)
V2 grid_pos;
float grid_rotation;
} build_preview = { 0 };
V2 hand_pos = { 0 };
V2 hand_pos = { 0 }; // in local space of grid when hovering over a grid
bool hand_at_arms_length = false;
{
// interpolate zoom
@ -439,6 +439,7 @@ frame(void)
// calculate build preview stuff
EntityID grid_to_build_on = (EntityID){ 0 };
V2 possibly_local_hand_pos = (V2){ 0 };
if (myentity() != NULL) {
hand_pos = V2sub(world_mouse_pos, entity_pos(myentity()));
float hand_len = V2length(hand_pos);
@ -452,6 +453,7 @@ frame(void)
hand_pos = V2scale(V2normalize(hand_pos), hand_len);
hand_pos = V2add(hand_pos, entity_pos(myentity()));
possibly_local_hand_pos = hand_pos;
Entity* placing_grid = closest_to_point_in_radius(&gs, hand_pos, BUILD_BOX_SNAP_DIST_TO_SHIP);
if (placing_grid == NULL) {
build_preview = (struct BuildPreviewInfo){
@ -462,6 +464,7 @@ frame(void)
else {
grid_to_build_on = get_id(&gs, placing_grid);
hand_pos = grid_snapped_box_pos(placing_grid, hand_pos);
possibly_local_hand_pos = grid_world_to_local(placing_grid, hand_pos);
build_preview = (struct BuildPreviewInfo){ .grid_pos = entity_pos(placing_grid),
.grid_rotation = entity_rotation(placing_grid),
};
@ -474,7 +477,7 @@ frame(void)
// every frame
static size_t last_frame_id = 0;
struct InputFrame cur_input_frame = { 0 };
InputFrame cur_input_frame = { 0 };
cur_input_frame.id = last_frame_id;
V2 input = (V2){
.x = (float)keydown[SAPP_KEYCODE_D] - (float)keydown[SAPP_KEYCODE_A],
@ -484,15 +487,16 @@ frame(void)
input = V2normalize(input);
cur_input_frame.movement = input;
cur_input_frame.seat_action = keypressed[SAPP_KEYCODE_G].pressed;
cur_input_frame.hand_pos = hand_pos;
cur_input_frame.grid_hand_pos_local_to = grid_to_build_on;
cur_input_frame.hand_pos = possibly_local_hand_pos;
if (mouse_pressed && cur_editing_boxtype != -1) {
cur_input_frame.dobuild = mouse_pressed;
cur_input_frame.build_type = cur_editing_boxtype;
cur_input_frame.build_rotation = cur_editing_rotation;
cur_input_frame.grid_to_build_on = grid_to_build_on;
}
struct InputFrame latest = client_to_server.inputs[0];
InputFrame latest = client_to_server.inputs[0];
// @Robust split this into separate lines and be very careful about testing for inequality
bool input_differs = false;
@ -505,12 +509,12 @@ frame(void)
input_differs = input_differs || cur_input_frame.dobuild != latest.dobuild;
input_differs = input_differs || cur_input_frame.build_type != latest.build_type;
input_differs = input_differs || cur_input_frame.build_rotation != latest.build_rotation;
input_differs = input_differs || !entityids_same(cur_input_frame.grid_to_build_on, latest.grid_to_build_on);
input_differs = input_differs || !entityids_same(cur_input_frame.grid_hand_pos_local_to, latest.grid_hand_pos_local_to);
if (input_differs) {
struct InputFrame last_frame = client_to_server.inputs[0];
InputFrame last_frame = client_to_server.inputs[0];
for (int i = 0; i < INPUT_BUFFER - 1; i++) {
struct InputFrame last_last_frame = last_frame;
InputFrame last_last_frame = last_frame;
last_frame = client_to_server.inputs[i + 1];
client_to_server.inputs[i + 1] = last_last_frame;
}
@ -518,7 +522,6 @@ frame(void)
client_to_server.inputs[0] = cur_input_frame;
last_frame_id += 1;
}
dbg_rect(client_to_server.inputs[0].hand_pos);
static double last_input_sent_time = 0.0;
if (fabs(last_input_sent_time - time) > TIME_BETWEEN_INPUT_PACKETS) {
@ -545,7 +548,8 @@ frame(void)
sgp_set_blend_mode(SGP_BLENDMODE_BLEND);
// Draw background color
sgp_set_color(0.1f, 0.1f, 0.1f, 1.0f);
set_color(colhexcode(0x020509));
// sgp_set_color(0.1f, 0.1f, 0.1f, 1.0f);
sgp_clear();
// sokol drawing library draw in world space

@ -1,3 +1,4 @@
#include <chipmunk.h> // initializing bodies
#include "types.h"
#include "sokol_time.h"
#include <enet/enet.h>
@ -5,6 +6,7 @@
#include <inttypes.h> // int64 printing
#include <stdlib.h>
// started in a thread from host
void server(void* data)
{
@ -26,7 +28,24 @@ void server(void* data)
entity_set_pos(grid, (V2) { -BOX_SIZE * 2, 0.0f });
Entity* box = new_entity(&gs);
box_create(&gs, box, grid, (V2) { 0 });
}
// rotation test
if (false)
{
Entity* grid = new_entity(&gs);
grid_create(&gs, grid);
entity_set_pos(grid, (V2) { -BOX_SIZE * 2, 0.0f });
entity_set_rotation(grid, PI / 1.7f);
cpBodySetVelocity(grid->body, cpv(-0.1, 0.0));
cpBodySetAngularVelocity(grid->body, 1.0f);
#define BOX_AT(pos) { Entity* box = new_entity(&gs); box_create(&gs, box, grid, pos); }
BOX_AT(((V2) { 0 }));
BOX_AT(((V2) { BOX_SIZE, 0 }));
BOX_AT(((V2) { 2.0*BOX_SIZE, 0 }));
BOX_AT(((V2) { 2.0*BOX_SIZE, BOX_SIZE }));
BOX_AT(((V2) { 0.0*BOX_SIZE, -BOX_SIZE }));
}
if (enet_initialize() != 0)
@ -133,7 +152,7 @@ void server(void* data)
continue;
if (received.inputs[i].id <= latest_id)
continue; // don't reprocess inputs already processed
struct InputFrame cur_input = received.inputs[i];
InputFrame cur_input = received.inputs[i];
gs.players[player_slot].input.movement = cur_input.movement;
gs.players[player_slot].input.hand_pos = cur_input.hand_pos;
@ -143,10 +162,11 @@ void server(void* data)
if (cur_input.seat_action)
{
gs.players[player_slot].input.seat_action = cur_input.seat_action;
gs.players[player_slot].input.grid_hand_pos_local_to = cur_input.grid_hand_pos_local_to;
}
if (cur_input.dobuild)
{
gs.players[player_slot].input.grid_to_build_on = cur_input.grid_to_build_on;
gs.players[player_slot].input.grid_hand_pos_local_to = cur_input.grid_hand_pos_local_to;
gs.players[player_slot].input.dobuild = cur_input.dobuild;
gs.players[player_slot].input.build_type = cur_input.build_type;
gs.players[player_slot].input.build_rotation = cur_input.build_rotation;

@ -98,7 +98,7 @@ static bool entityids_same(EntityID a, EntityID b)
// when updated, must update serialization, AND comparison
// function in main.c
struct InputFrame
typedef struct
{
uint64_t tick;
size_t id; // each input has unique, incrementing, I.D, so server doesn't double process inputs. Inputs to server should be ordered from 0-max like biggest id-smallest. This is done so if packet loss server still processes input
@ -106,13 +106,13 @@ struct InputFrame
bool seat_action;
EntityID seat_to_inhabit;
V2 hand_pos; // world coords, world star!
V2 hand_pos;
EntityID grid_hand_pos_local_to; // when not null, hand_pos is local to this grid. this prevents bug where
bool dobuild;
enum BoxType build_type;
enum CompassRotation build_rotation;
EntityID grid_to_build_on;
};
} InputFrame;
typedef struct Entity
{
@ -158,7 +158,7 @@ typedef struct Player
{
bool connected;
EntityID entity;
struct InputFrame input;
InputFrame input;
} Player;
// gotta update the serialization functions when this changes
typedef struct GameState
@ -215,7 +215,7 @@ typedef struct ServerToClient
struct ClientToServer
{
struct InputFrame inputs[INPUT_BUFFER];
InputFrame inputs[INPUT_BUFFER];
};
// server
@ -235,6 +235,7 @@ Entity* get_entity(struct GameState* gs, EntityID id);
Entity* new_entity(struct GameState* gs);
EntityID get_id(struct GameState* gs, Entity* e);
V2 entity_pos(Entity* e);
void entity_set_rotation(Entity* e, float rot);
void entity_set_pos(Entity* e, V2 pos);
float entity_rotation(Entity* e);
#define BOX_CHAIN_ITER(gs, cur, starting_box) for (Entity *cur = get_entity(gs, starting_box); cur != NULL; cur = get_entity(gs, cur->next_box))
@ -258,7 +259,7 @@ V2 box_pos(Entity* box); // returns in world coords
float box_rotation(Entity* box);
// thruster
V2 thruster_direction(Entity* box);
V2 box_facing_vector(Entity* box);
V2 thruster_force(Entity* box);
// debug draw
@ -409,6 +410,15 @@ static Color colhex(int r, int g, int b)
};
}
static Color colhexcode(int hexcode)
{
// 0x020509;
int r = (hexcode >> 16) & 0xFF;
int g = (hexcode >> 8) & 0xFF;
int b = (hexcode >> 0) & 0xFF;
return colhex(r, g, b);
}
static Color Collerp(Color a, Color b, float factor)
{
Color to_return = { 0 };

Loading…
Cancel
Save