racing_game/world.cpp

604 lines
14 KiB
C++
Raw Permalink Normal View History

2019-05-25 14:24:49 +10:00
#include <GL/glut.h>
#include <fstream>
#include <iostream>
#include <random>
#include <vector>
#include <math.h>
#include "PerlinNoise.hpp"
#include "random.h"
#include "graphics.h"
#include "blocks.h"
#include "player.h"
#include "world.h"
#include "math.h"
//int min_render_distance=50;
int render_distance_width=40;
int render_distance_height=10;
uint64_t sxyz[3];
Block *world;
/*std::vector<double> render_distance_average;
void on_early()
{
// Increase the render distance
render_distance += 1;
}
void on_late()
{
// Reduce the render distance
if(render_distance > min_render_distance) {
render_distance -= 1;
}
}
*/
void coords_to_int(int *id, int x, int y, int z) {
*id = z * sxyz[1] * sxyz[0] + y * sxyz[0] + x;
}
void int_to_coords(int id, int *x, int *y, int *z) {
*x = id % sxyz[0];
*y = (id/sxyz[0]) % sxyz[1];
*z = (id/sxyz[0]/sxyz[1]) % sxyz[2];
}
// Say if the block is in the world
bool block_in_world(int x, int y, int z) {
return (x >= 0) && (x < sxyz[0]) && (y >= 0) && (y < sxyz[1]) && (z >= 0) && (z < sxyz[2]);
}
// Say if the player is in the world
bool player_in_world(double x, double y, double z) {
return (x >= 0) && (x <= sxyz[0]) && (y >= 0) && (y <= sxyz[1]) && (z >= 0) && (z <= sxyz[2]);
}
bool block_is_ramp(double x, double y, double z)
{
// Get the id
int id;
coords_to_int(&id, x, y, z);
// Is the player on a ramp
if(world[id].type == BTYPE_RAMP)
{
// Get the part of the slope the player is on
double slope_part;
// North
if(world[id].direction == DIRECTION_N)
{
slope_part = 1-(z-int(z));
}
// South
if(world[id].direction == DIRECTION_S)
{
slope_part = z-int(z);
}
// East
if(world[id].direction == DIRECTION_E)
{
slope_part = 1-(x-int(x));
}
// West
if(world[id].direction == DIRECTION_W)
{
slope_part = x-int(x);
}
// Is the player above the slope part
return ((y-int(y)) < slope_part+0.25);
}
// The player isnt on a ramp
return false;
}
bool block_isnt_solid(double x, double y, double z)
{
// Setup some varibles
bool in_world_check = false;
double d = 0.25;
// Is the player inside the world
if(player_in_world(x, y, z)) in_world_check = true;
// Is the block in range
if(in_world_check)
{
if(block_is_ramp(x, y, z))
{
return false;
}
// Get the ids
int id[8];
coords_to_int(&id[0], x+d, y+d, z+d);
coords_to_int(&id[1], x-d, y+d, z+d);
coords_to_int(&id[2], x-d, y+d, z-d);
coords_to_int(&id[3], x+d, y+d, z-d);
coords_to_int(&id[4], x+d, y-d, z+d);
coords_to_int(&id[5], x-d, y-d, z+d);
coords_to_int(&id[6], x-d, y-d, z-d);
coords_to_int(&id[7], x+d, y-d, z-d);
// Loop throgh the ids
for(int i=0;i<8;i++)
{
// Convert the id to coordinates
int cx, cy, cz;
int_to_coords(id[i], &cx, &cy, &cz);
// Are the coordinates out of range; then return true
if(cx < 0 || cy < 0 || cz < 0 || cx >= sxyz[0] || cy >= sxyz[1] || cz >= sxyz[2]) {
return true;
}
// Is the block not in the world
if(!block_in_world(cx, cy, cz))
{
// Return true
return true;
}
// Return false if this is not air and is a block
if(
world[id[i]].id != BLOCK_AIR &&
world[id[i]].type == BTYPE_BLOCK
) return false;
}
// Return true
return true;
}
// Return true
return true;
}
bool block_is_fluid(double x, double y, double z)
{
// Get the fluid motion
double fluid_motion = get_fluid_motion(x, z);
// Get the id
int id;
coords_to_int(&id, x, y+1-fluid_motion, z);
// Get the above id
int a_id;
coords_to_int(&a_id, x, y+2-fluid_motion, z);
// Is the player in a fluid
if(world[id].type == BTYPE_FLUID)
{
// Submurged under the water
if(world[a_id].type == BTYPE_FLUID)
{
// Return true
return true;
}
// Is the decimal height greater than the block height and the fluid motion
return y < int(y) + fluid_motion;
}
// Return false
return false;
}
int relative_block(int id, int x, int y, int z)
{
// Get the position of the current block
int cx, cy, cz;
int_to_coords(id, &cx, &cy, &cz);
// Add the relative coordinates
cx += x;
cy += y;
cz += z;
// Is this valid
if(cx < 0) return -1;
if(cy < 0) return -1;
if(cz < 0) return -1;
if(cx >= sxyz[0]) return -1;
if(cy >= sxyz[1]) return -1;
if(cz >= sxyz[2]) return -1;
// Get the id
int cid;
coords_to_int(&cid, cx, cy, cz);
// Return the block id
return cid;
}
bool relative_block_optimise(int id, int x, int y, int z, bool check)
{
// Is the check varible already false
if(!check) return false;
// Get the id of the relative block
int rb = relative_block(id, x, y, z);
// Is the result out of range (-1)
if(rb == -1) return false;
if(!(
// Is not air
world[rb].id != BLOCK_AIR &&
(
// Is the same type as the other block
world[rb].type == world[id].type ||
// Is the other block a block
world[rb].type == BTYPE_BLOCK
)
)) return true;
return (
(!blockGetSettings(world[id].id).transparent) &&
blockGetSettings(world[rb].id).transparent
);
/*// Check the angle of the face and the player
// Get the blocks coordinates
int cx, cy, cz;
int_to_coords(id, &cx, &cy, &cz);
double a;
if(x != 0 || z != 0)
{
a = atan2(cx-player_pos[0], cz-player_pos[2])*180.0/PI
}
// North / South
if(x != 0)
{
// Get the angle
a -= player_angle[0];
a *= x;
}
// East / West
if(z != 0)
{
// Get the angle
a = ;
a -= player_angle[0] - 90;
a *= z;
}
// Up / Down
if(y != 0)
{
// Get the angle
a = atan2(cy-player_pos[1], cz-player_pos[2])*180.0/PI;
a -= player_angle[0];
a *= y;
}
// Fix the angle
while(a < 0) a += 360;
while(a > 360) a -= 360;
return a > 0 && a < 180;*/
}
void world_load(const char *dir)
{
/*// Open the file
std::ifstream file(dir, std::ios::binary);
// Load the map size
file.read((char*)&sxyz[0], sizeof(uint64_t));
file.read((char*)&sxyz[1], sizeof(uint64_t));
file.read((char*)&sxyz[2], sizeof(uint64_t));
// Setup the world varible
world = new World[sxyz[0]*sxyz[1]*sxyz[2]];
// Read the world data
file.read((char*)world, sizeof(World)*sxyz[0]*sxyz[1]*sxyz[2]);
// Close the file
file.close();*/
}
void player_respawn()
{
// Set the player to the middle and at the top of the map
player_pos[0] = sxyz[0]/2;
player_pos[1] = sxyz[1]-2;
player_pos[2] = sxyz[2]/2;
}
void world_init()
{
// Initialse the blocks
blocks_init();
sxyz[0] = 256;
sxyz[1] = 120;
sxyz[2] = 256;
// Set the players spawn point
player_respawn();
// Setup the world varible
world = new Block[sxyz[0]*sxyz[1]*sxyz[2]];
// Zero out the world varible
zero_out_bytes((char*)world, sizeof(Block)*sxyz[0]*sxyz[1]*sxyz[2]);
// Set the seed
const siv::PerlinNoise perlin(random_get_seed());
// Set the frequency
double frequency = 1;
double xf = sxyz[0] / frequency;
double zf = sxyz[2] / frequency;
// Loop over x
for(int x=0;x<sxyz[0];x++)
{
// Loop over z
for(int z=0;z<sxyz[2];z++)
{
// Get some perlin noise
double f = 128;
int noise = perlin.octaveNoise0_1(x / f, z / f, 8)*100;
// Go up the world
for(int y=0;y<sxyz[1];y++)
{
// Get the id
int id;
coords_to_int(&id, x, y, z);
// Edge of the world
if(x == 0 || z == 0 || x == sxyz[0]-1 || z == sxyz[2]-1 || y == 0 || y == sxyz[1]-1)
{
// Set the block to a barrier
world[id] = make_block(BLOCK_BARRIER);
}
else
{
// 2 blocks under the ground
if(y < noise-2)
{
// Make stone
world[id] = make_block(BLOCK_STONE);
}
// Under the ground
else if(y < noise)
{
// Make dirt
world[id] = make_block(BLOCK_DIRT);
}
// At ground level
else if(y == noise && y >= 60)
{
// Make grass
world[id] = make_block(BLOCK_GRASS);
}
else if(y == noise && y < 60)
{
// Make grass
world[id] = make_block(BLOCK_SAND);
}
// Water level
else if(y > noise && y < 60)
{
// Make water
world[id] = make_block(BLOCK_WATER, BTYPE_FLUID);
}
// 1 block above ground
else if(y == noise+1)
{
// Get some perlin noise
double grass_noise = perlin.octaveNoise0_1(x / 10.0, z / 10.0, 10);
// Over a certain threshold
if(grass_noise > 0.6)
{
// Make grass plant
world[id] = make_block(BLOCK_GRASS_PLANT, BTYPE_PLANT);
}
}
}
/*
else if(y < 2)
{
world[id] = make_block(BLOCK_DIRT);
}
else if(y == 2)
{
world[id] = make_block(BLOCK_GRASS);
}
else if(x > 5 && y < z-100)
{
world[id] = make_block(BLOCK_DIRT);
}
else if(x > 5 && y == z-100)
{
world[id] = make_block(BLOCK_GRASS, BTYPE_RAMP, DIRECTION_S);
}
*/
}
}
}
}
void render_coord(int x, int y, int z, int a1, int a2)
{
// Is this in range
if(block_in_world(x, y, z))
{
// Get the id
int id;
coords_to_int(&id, x, y, z);
int b = 60;
// Is this not air
if(world[id].id != BLOCK_AIR)
{
// Setup a Block Face Map
BlockFaceMap fm;
fm.n = relative_block_optimise(id, 0, 0,-1, a1 > 90 -b && a1 < 270+b || (a2 < -40 || a2 > 40));
fm.s = relative_block_optimise(id, 0, 0, 1, a1 > 270-b || a1 < 90 +b || (a2 < -40 || a2 > 40));
fm.e = relative_block_optimise(id, 1, 0, 0, a1 < 0 +b || a1 > 180-b || (a2 < -40 || a2 > 40));
fm.w = relative_block_optimise(id,-1, 0, 0, a1 < 180+b || a1 > 360-b || (a2 < -40 || a2 > 40));
fm.t = relative_block_optimise(id, 0, 1, 0, a2 > 0-b || world[id].type == BTYPE_FLUID);
fm.b = relative_block_optimise(id, 0,-1, 0, a2 < 0+b);
// Render the block
render_block(world[id], x, y, z, fm);
}
}
}
void world_render_block_inside_player()
{
// Bind the texture
bind_block_texture();
// Get the id
int id;
coords_to_int(&id, player_pos[0], player_pos[1], player_pos[2]);
// Render the block face infront of the player
render_block_face_here(world[id]);
}
void world_render()
{
// Set the colour to maximum opacity and colour
glColor4f(1.0f,1.0f,1.0f,1.0f);
// Bind the texture
bind_block_texture();
// Get the cameras angles
int a1 = (int)player_angle[0] % 360;
int a2 = (int)player_angle[1] % 180;
// Set the cutof render angles
int g1 = 80;
int g2 = 40;
// Render everything inwards
for(int x=render_distance_width;x>0;x-=1) {
for(int y=render_distance_height;y>0;y-=1) {
for(int z=render_distance_width;z>0;z-=1)
{
// Render the blocks
if((a1 < 180 +g1 && a1 > 90 -g1) || (a2 < 0 -g2)) render_coord(player_pos[0]+x, player_pos[1]+y, player_pos[2]+z, a1, a2);
if((a1 < 270 +g1 && a1 > 180 -g1) || (a2 < 0 -g2)) render_coord(player_pos[0]-x, player_pos[1]+y, player_pos[2]+z, a1, a2);
if((a1 < 0 +g1 || a1 > 270 -g1) || (a2 < 0 -g2)) render_coord(player_pos[0]-x, player_pos[1]+y, player_pos[2]-z, a1, a2);
if((a1 < 90 +g1 || a1 > 360 -g1) || (a2 < 0 -g2)) render_coord(player_pos[0]+x, player_pos[1]+y, player_pos[2]-z, a1, a2);
if((a1 < 180 +g1 && a1 > 90 -g1) || (a2 > 0 +g2)) render_coord(player_pos[0]+x, player_pos[1]-y, player_pos[2]+z, a1, a2);
if((a1 < 270 +g1 && a1 > 180 -g1) || (a2 > 0 +g2)) render_coord(player_pos[0]-x, player_pos[1]-y, player_pos[2]+z, a1, a2);
if((a1 < 0 +g1 || a1 > 270 -g1) || (a2 > 0 +g2)) render_coord(player_pos[0]-x, player_pos[1]-y, player_pos[2]-z, a1, a2);
if((a1 < 90 +g1 || a1 > 360 -g1) || (a2 > 0 +g2)) render_coord(player_pos[0]+x, player_pos[1]-y, player_pos[2]-z, a1, a2);
}
}
}
for(int x=render_distance_width;x>0;x-=1) {
for(int z=render_distance_width;z>0;z-=1)
{
// Render the coordinates
render_coord(player_pos[0]+x, player_pos[1], player_pos[2]+z, a1, a2);
render_coord(player_pos[0]+x, player_pos[1], player_pos[2]-z, a1, a2);
render_coord(player_pos[0]-x, player_pos[1], player_pos[2]-z, a1, a2);
render_coord(player_pos[0]-x, player_pos[1], player_pos[2]+z, a1, a2);
}
}
for(int x=render_distance_width;x>0;x-=1) {
for(int y=render_distance_height;y>0;y-=1)
{
// Render the coordinates
render_coord(player_pos[0]+x, player_pos[1]+y, player_pos[2], a1, a2);
render_coord(player_pos[0]+x, player_pos[1]-y, player_pos[2], a1, a2);
render_coord(player_pos[0]-x, player_pos[1]-y, player_pos[2], a1, a2);
render_coord(player_pos[0]-x, player_pos[1]+y, player_pos[2], a1, a2);
}
}
for(int z=render_distance_width;z>0;z-=1) {
for(int y=render_distance_height;y>0;y-=1)
{
// Render the coordinates
render_coord(player_pos[0], player_pos[1]+y, player_pos[2]+z, a1, a2);
render_coord(player_pos[0], player_pos[1]+y, player_pos[2]-z, a1, a2);
render_coord(player_pos[0], player_pos[1]-y, player_pos[2]-z, a1, a2);
render_coord(player_pos[0], player_pos[1]-y, player_pos[2]+z, a1, a2);
}
}
for(int x=render_distance_width;x>0;x-=1)
{
// Render the coordinates
render_coord(player_pos[0]+x, player_pos[1], player_pos[2], a1, a2);
render_coord(player_pos[0]-x, player_pos[1], player_pos[2], a1, a2);
}
for(int y=render_distance_height;y>0;y-=1)
{
// Render the coordinates
render_coord(player_pos[0], player_pos[1]+y, player_pos[2], a1, a2);
render_coord(player_pos[0], player_pos[1]-y, player_pos[2], a1, a2);
}
for(int z=render_distance_width;z>0;z-=1)
{
// Render the coordinates
render_coord(player_pos[0], player_pos[1], player_pos[2]+z, a1, a2);
render_coord(player_pos[0], player_pos[1], player_pos[2]-z, a1, a2);
}
// Render a coordinate where the player is standing
render_coord(player_pos[0], player_pos[1], player_pos[2], a1, a2);
// Unbind the texture
unbind_block_texture();
// Enable blending
//glEnable(GL_BLEND);
}
void set_block_at(int x, int y, int z, uint8_t id, uint8_t type, uint8_t direction)
{
// Get the id
int w_id;
coords_to_int(&w_id, x, y, z);
// Get the block
Block b = make_block(id, type, direction);
// Set the block
world[w_id] = b;
}