static float get_angle(const float a0[2], const float a1[2], const float b0[2], const float b1[2]) { float u[2], v[2], dot, det; vec2_sub(a1, a0, u); vec2_normalize(u, u); vec2_sub(b1, b0, v); vec2_normalize(v, v); dot = vec2_dot(u, v); det = vec2_cross(u, v); return atan2(det, dot); }
t_vec2 vec2_scale(t_vec2 vec2, float scale) { vec2_normalize(&vec2); vec2.x *= scale; vec2.y *= scale; return (vec2); }
static void fire_projectile(struct GameState *game_state, struct Ship *source, struct Ship *target, int32 damage) { ASSERT(source != target); source->fire_cooldown_timer = source->fire_cooldown; struct Projectile *projectile = create_projectile(game_state); projectile->owner = source->id; projectile->team = source->team; projectile->damage = damage; projectile->position = source->position; projectile->size = vec2_new(0.1f, 0.1f); vec2 direction = vec2_normalize(vec2_sub(target->position, projectile->position)); projectile->velocity = vec2_mul(direction, 5.0f); }
int game_update(int mousedx, int mousedy) { const uint8_t* keys = SDL_GetKeyboardState(NULL); double rot = mousedx*PLAYER_ROTSPEED; if (keys[SDL_SCANCODE_LEFT]) rot -= 10*PLAYER_ROTSPEED; if (keys[SDL_SCANCODE_RIGHT]) rot += 10*PLAYER_ROTSPEED; vec2_rotate(&player.dir, rot, &player.dir); vec2_t dir = {0, 0}; double spd = PLAYER_MOVESPEED; if (keys[SDL_SCANCODE_LCTRL]) spd *= .1; if (keys[SDL_SCANCODE_LSHIFT]) spd *= 10.; vec2_t dirCrossed = {player.dir.y, -player.dir.x}; if (keys[SDL_SCANCODE_W] || keys[SDL_SCANCODE_UP]) vec2_add(&dir, &player.dir, &dir); if (keys[SDL_SCANCODE_S] || keys[SDL_SCANCODE_DOWN]) vec2_addScale(&dir, &player.dir, -1, &dir); if (keys[SDL_SCANCODE_A]) vec2_addScale(&dir, &dirCrossed, -1, &dir); if (keys[SDL_SCANCODE_D]) vec2_add(&dir, &dirCrossed, &dir); if (vec2_lengthSq(&dir) > 0.00001) { vec2_normalize(&dir, &dir); camera_t cam = player; cam.dir = dir; raycast_travel(&cam, spd, &m); player.pos = cam.pos; } return keys[SDL_SCANCODE_ESCAPE]; }
void vec2_reflect(vec2_t* i, int side, vec2_t* out) { switch(side) { case SIDE_NORTH: out->x = i->x; out->y = -i->y; break; case SIDE_EAST: out->x = -i->x; out->y = i->y; break; case SIDE_SOUTH: out->x = i->x; out->y = -i->y; break; case SIDE_WEST: out->x = -i->x; out->y = i->y; break; } vec2_normalize(out, out); }
static int brute_hit(struct foe_brute *f, const vector2 *hit) { const vector2 *pos = &f->common.pos; const float radius = foe_data[FOE_BRUTE].radius; if (vec2_distance_squared(hit, pos) < radius*radius) { if (--f->hit_count == 0) { foe_common_gen_explosion(&f->common, 1.3f); kill_foe(&f->common); foe_common_bump_score(&f->common); } else { vector2 s, os; float t; f->last_hit_tic = gc.level_tics; s = f->common.pos; vec2_sub_from(&s, &ship.pos); vec2_normalize(&s); vec2_set(&os, -s.y, s.x); t = 5.f*(frand() - .5f); s.x += t*os.x; s.y += t*os.y; vec2_mul_scalar(&s, .3f/vec2_length(&s)); vec2_add_to(&f->common.dir, &s); f->common.angle_speed *= 2; } return 1; } return 0; }
static void gen_explosion(float x, float y) { int i, n, c; particle *p; n = 150 + irand(150); c = irand(NUM_PALETTES); for (i = 0; i < n; i++) { vector2 offs; p = add_particle(); if (!p) break; p->ttl = 20 + irand(20); p->t = 0; p->width = .3f*(.6f + .1f*frand()); p->height = .3f*(2.8f + .4f*frand()); p->pos.x = x; p->pos.y = y; p->palette = c; vec2_set(&p->dir, frand() - .5f, frand() - .5f); vec2_normalize(&p->dir); offs = p->dir; vec2_mul_scalar(&offs, 1.3f*frand()); vec2_add_to(&p->pos, &offs); p->speed = PARTICLE_SPEED + .05f*frand(); p->friction = .96f; } }
static void evolved_duck_update(struct foe_evolved_duck *f) { vector2 d, od, t; float r; int ship_is_behind; foe_common_update(&f->common); if (foe_bounced) { f->num_trail_segs = 0; } else { if (f->num_trail_segs < MAX_TRAIL_SEGS) f->num_trail_segs++; if (++f->trail_seg_head >= MAX_TRAIL_SEGS) f->trail_seg_head = 0; f->trail_seg[f->trail_seg_head] = f->common.pos; } hit_ship(&f->common.pos, foe_data[f->common.type].radius); od.x = ship.pos.x - f->common.pos.x; od.y = ship.pos.y - f->common.pos.y; vec2_normalize(&od); t.x = -f->common.dir.y; t.y = f->common.dir.x; ship_is_behind = vec2_dot_product(&od, &t) > 0; /* accelerate if behind ship, brake otherwise */ if (ship_is_behind) vec2_mul_scalar(&f->common.dir, .99f); else vec2_mul_scalar(&f->common.dir, 1.2f); /* turn towards ship */ d.x = -(ship.pos.y - f->common.pos.y); d.y = ship.pos.x - f->common.pos.x; vec2_normalize(&d); r = 1.6f*vec2_dot_product(&d, &f->common.dir); if (r < 0) { if (ship_is_behind) r = -f->max_turn_angle; else { if (r < -f->max_turn_angle) r = -f->max_turn_angle; } } else { if (ship_is_behind) { r = f->max_turn_angle; } else { if (r > f->max_turn_angle) r = f->max_turn_angle; } } vec2_rotate(&f->common.dir, r); vec2_clamp_length(&f->common.dir, foe_data[f->common.type].max_speed); }
static void foe_common_gen_explosion(struct foe_common *f, float scale) { int i; particle *p; int ndebris, nballs; ndebris = scale*(40 + irand(30)); /* debris */ for (i = 0; i < ndebris; i++) { p = add_particle(); if (!p) break; p->ttl = 20 + irand(15); p->t = 0; p->width = scale*.4f*(.6f + .15f*frand()); p->height = scale*.3f*(2.8f + .4f*frand()); p->pos = f->pos; p->palette = PAL_YELLOW; p->friction = .9; vec2_set(&p->dir, frand() - .5f, frand() - .5f); vec2_normalize(&p->dir); p->speed = scale*(PARTICLE_SPEED + .05f*frand()); } #define RADIUS .4f /* fireballs */ nballs = scale*(8 + irand(8)); for (i = 0; i < nballs; i++) { vector2 pos; float r, l; l = 1.2*scale; pos.x = f->pos.x + l*frand() - .5f*l; pos.y = f->pos.y + l*frand() - .5f*l; r = scale*(.2f + .15f*frand()); add_explosion(&pos, r, EFF_EXPLOSION, 13 + irand(4)); } /* shockwave */ add_explosion(&f->pos, scale*.3f, EFF_RING, 18); /* p = add_particle(); if (p) { p->t = 0; p->ttl = 20; p->width = p->height = scale*.3f; p->pos = f->pos; p->palette = PAL_RED; p->type = PT_SHOCKWAVE; } */ perturb_water(&f->pos, scale*1200.f); play_fx(FX_EXPLOSION_1); }
static int _llfunc_vec2_normalize(lua_State *L) { vec2 *v = (vec2*)userdata_get_or_die(L, 1); vec2_normalize(v); return 0; }
static bool _vis_query(NavMesh* navmesh, Vector2 p1, Vector2 p2) { int step_x, step_y, bmap_x, bmap_y, bmap_end_x, bmap_end_y; bmap_x = MIN(floorf(p1.x / vis_cell_width), vis_bitmap_width-1); bmap_y = MIN(floorf(p1.y / vis_cell_height), vis_bitmap_height-1); bmap_end_x = MIN(floorf(p2.x / vis_cell_width), vis_bitmap_width-1); bmap_end_y = MIN(floorf(p2.y / vis_cell_height), vis_bitmap_height-1); Vector2 dir = vec2_sub(p2, p1); dir = vec2_normalize(dir); Vector2 side_dist, delta_dist = vec2( sqrtf(1.0f + (dir.y * dir.y) / (dir.x * dir.x)) * vis_cell_width, sqrtf(1.0f + (dir.x * dir.x) / (dir.y * dir.y)) * vis_cell_height ); if(dir.x > 0.0f) { step_x = 1; side_dist.x = (float)(bmap_x+1) * vis_cell_width - p1.x; } else { step_x = -1; side_dist.x = p1.x - (float)bmap_x * vis_cell_width; } side_dist.y *= delta_dist.x / vis_cell_width; if(dir.y > 0.0f) { step_y = 1; side_dist.y = (float)(bmap_y+1) * vis_cell_height - p1.y; } else { step_y = -1; side_dist.y = p1.y - (float)bmap_y * vis_cell_height; } side_dist.y *= delta_dist.y / vis_cell_height; // DDA while(!_query_vis_bitmap(navmesh, bmap_x, bmap_y)) { bool x_cond = (step_x > 0 && bmap_x >= bmap_end_x) || (step_x < 0 && bmap_x <= bmap_end_x); bool y_cond = (step_y > 0 && bmap_y >= bmap_end_y) || (step_y < 0 && bmap_y <= bmap_end_y); if(x_cond && y_cond) return true; if(side_dist.x < side_dist.y) { side_dist.x += delta_dist.x; bmap_x += step_x; } else { side_dist.y += delta_dist.y; bmap_y += step_y; } } return false; }
static void tick_camera(struct Input *input, struct Camera *camera, float dt) { // // move // vec2 camera_up = vec2_direction(camera->rotation); vec2 camera_right = vec2_direction(camera->rotation - PI_OVER_TWO); vec2 move_acceleration = vec2_zero(); if (key_down(GLFW_KEY_W, input)) move_acceleration = vec2_add(move_acceleration, camera_up); if (key_down(GLFW_KEY_A, input)) move_acceleration = vec2_add(move_acceleration, vec2_negate(camera_right)); if (key_down(GLFW_KEY_S, input)) move_acceleration = vec2_add(move_acceleration, vec2_negate(camera_up)); if (key_down(GLFW_KEY_D, input)) move_acceleration = vec2_add(move_acceleration, camera_right); if (vec2_length2(move_acceleration) > FLOAT_EPSILON) { const float acceleration_magnitude = camera->zoom * 10.0f; move_acceleration = vec2_normalize(move_acceleration); move_acceleration = vec2_mul(move_acceleration, acceleration_magnitude); // v = v0 + (a*t) camera->move_velocity = vec2_add(camera->move_velocity, vec2_mul(move_acceleration, dt)); // Clamp move velocity. const float max_move_speed = 5.0f * sqrtf(camera->zoom); if (vec2_length2(camera->move_velocity) > (max_move_speed * max_move_speed)) camera->move_velocity = vec2_mul(vec2_normalize(camera->move_velocity), max_move_speed); } // Number of seconds required for friction to stop movement completely. // (because velocity is sampled each frame, actual stop time longer than this) float stop_time = 0.1f; float inv_stop_time = 1.0f / stop_time; if (move_acceleration.x == 0.0f) camera->move_velocity.x -= camera->move_velocity.x * inv_stop_time * dt; if (move_acceleration.y == 0.0f) camera->move_velocity.y -= camera->move_velocity.y * inv_stop_time * dt; // r = r0 + (v0*t) + (a*t^2)/2 camera->position = vec2_add(vec2_add(camera->position, vec2_mul(camera->move_velocity, dt)), vec2_div(vec2_mul(move_acceleration, dt * dt), 2.0f)); // // zoom // float zoom_acceleration = 0.0f; if (key_down(GLFW_KEY_SPACE, input)) zoom_acceleration += 1.0f; if (key_down(GLFW_KEY_LEFT_CONTROL, input)) zoom_acceleration -= 1.0f; zoom_acceleration *= camera->zoom * 50.0f; if (zoom_acceleration == 0.0f) camera->zoom_velocity -= camera->zoom_velocity * (1.0f / 0.1f) * dt; // v = v0 + (a*t) camera->zoom_velocity += zoom_acceleration * dt; // r = r0 + (v0*t) + (a*t^2)/2 camera->zoom += (camera->zoom_velocity * dt) + (zoom_acceleration * dt * dt) / 2.0f; // Clamp zoom velocity. const float max_zoom_speed = 3.0f * camera->zoom; camera->zoom_velocity = clamp_float(camera->zoom_velocity, -max_zoom_speed, max_zoom_speed); float unclamped_zoom = camera->zoom; camera->zoom = clamp_float(camera->zoom, 1.0f, 1000.0f); if (camera->zoom != unclamped_zoom) camera->zoom_velocity = 0.0f; }