float terrain_height(terrain* ter, vec2 position) { vec2 amount = vec2_fmod(position, 1.0); vec2 top_left = vec2_new(floor(position.x), floor(position.y)); vec2 top_right = vec2_new(ceil(position.x), floor(position.y)); vec2 bot_left = vec2_new(floor(position.x), ceil(position.y)); vec2 bot_right = vec2_new(ceil(position.x), ceil(position.y)); top_left.x = clamp(top_left.x, 0, ter->width-1); top_left.y = clamp(top_left.y, 0, ter->height-1); top_right.x = clamp(top_right.x, 0, ter->width-1); top_right.y = clamp(top_right.y, 0, ter->height-1); bot_left.x = clamp(bot_left.x, 0, ter->width-1); bot_left.y = clamp(bot_left.y, 0, ter->height-1); bot_right.x = clamp(bot_right.x, 0, ter->width-1); bot_right.y = clamp(bot_right.y, 0, ter->height-1); float s0 = ter->heightmap[(int)top_left.x + (int)top_left.y * ter->width]; float s1 = ter->heightmap[(int)top_right.x + (int)top_right.y * ter->width]; float s2 = ter->heightmap[(int)bot_left.x + (int)bot_left.y * ter->width]; float s3 = ter->heightmap[(int)bot_right.x + (int)bot_right.y * ter->width]; return bilinear_interp(s1, s0, s3, s2, amount.x, amount.y); }
static float perlin_noise2D(vec2 v) { vec2 amount = vec2_fmod(v,1.0); vec2 p1 = vec2_floor(v); vec2 p2 = vec2_add(p1, vec2_new(1,0) ); vec2 p3 = vec2_add(p1, vec2_new(0,1) ); vec2 p4 = vec2_add(p1, vec2_new(1,1) ); int h1 = vec2_mix_hash(p1); int h2 = vec2_mix_hash(p2); int h3 = vec2_mix_hash(p3); int h4 = vec2_mix_hash(p4); double result = bismootherstep_interp(h2, h1, h4, h3, amount.x, amount.y); return result / INT_MAX; }
static void collision_detection() { /* Collision is fairly simplistic and looks something like this. @-----@ We check for collision in those points here which @ @ are @ signs. If any are colliding with a solid tile | | then we shift the player so that they are no longer @ @ colliding with it. Also invert the velocity. @-----@ */ character* main_char = entity_get("main_char"); const float buffer = 4; const float bounce = 0.5; vec2 diff; /* Bottom Collision */ diff = vec2_fmod(main_char->position, TILE_SIZE); vec2 bottom1 = vec2_add(main_char->position, vec2_new(buffer, TILE_SIZE)); vec2 bottom2 = vec2_add(main_char->position, vec2_new(TILE_SIZE - buffer, TILE_SIZE)); bool bottom1_col = tile_has_collision(level_tile_at(current_level, bottom1)); bool bottom2_col = tile_has_collision(level_tile_at(current_level, bottom2)); if (bottom1_col || bottom2_col) { main_char->position = vec2_add(main_char->position, vec2_new(0,-diff.y)); main_char->velocity.y *= -bounce; } /* Top Collision */ diff = vec2_fmod(main_char->position, TILE_SIZE); vec2 top1 = vec2_add(main_char->position, vec2_new(buffer, 0)); vec2 top2 = vec2_add(main_char->position, vec2_new(TILE_SIZE - buffer, 0)); bool top1_col = tile_has_collision(level_tile_at(current_level, top1)); bool top2_col = tile_has_collision(level_tile_at(current_level, top2)); if (top1_col || top2_col) { main_char->position = vec2_add(main_char->position, vec2_new(0, TILE_SIZE - diff.y)); main_char->velocity.y *= -bounce; } /* Left Collision */ diff = vec2_fmod(main_char->position, TILE_SIZE); vec2 left1 = vec2_add(main_char->position, vec2_new(0, buffer)); vec2 left2 = vec2_add(main_char->position, vec2_new(0, TILE_SIZE - buffer)); bool left1_col = tile_has_collision(level_tile_at(current_level, left1)); bool left2_col = tile_has_collision(level_tile_at(current_level, left2)); if (left1_col || left2_col) { main_char->position = vec2_add(main_char->position, vec2_new(TILE_SIZE - diff.x,0)); main_char->velocity.x *= -bounce; } /* Right Collision */ diff = vec2_fmod(main_char->position, TILE_SIZE); vec2 right1 = vec2_add(main_char->position, vec2_new(TILE_SIZE, buffer)); vec2 right2 = vec2_add(main_char->position, vec2_new(TILE_SIZE, TILE_SIZE - buffer)); bool right1_col = tile_has_collision(level_tile_at(current_level, right1)); bool right2_col = tile_has_collision(level_tile_at(current_level, right2)); if (right1_col || right2_col) { main_char->position = vec2_add(main_char->position, vec2_new(-diff.x,0)); main_char->velocity.x *= -bounce; } }