Skip to content

Instantly share code, notes, and snippets.

@jcelerier
Forked from jackmott/FasterGame.cpp
Last active September 14, 2016 21:58
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save jcelerier/f6b666041162eb221bfca441eccb0ee7 to your computer and use it in GitHub Desktop.
Save jcelerier/f6b666041162eb221bfca441eccb0ee7 to your computer and use it in GitHub Desktop.
Faster Game CPP
#include <cstdio>
#include <cstdlib>
#include <chrono>
#include <random>
#include <thread>
#include <cmath>
#include <string>
#include <vector>
#include <array>
#include <boost/lockfree/queue.hpp>
using namespace std;
using namespace std::chrono;
class Vector
{
public:
float x{}, y{}, z{};
Vector() = default;
Vector(float x_, float y_, float z_): x{x_}, y{y_}, z{z_} { }
static Vector add(Vector a,Vector b)
{
return Vector(a.x+b.x,a.y+b.y,a.z+b.z);
}
static Vector mul(Vector a,Vector b)
{
return Vector(a.x*b.x,a.y*b.y,a.z*b.z);
}
static Vector sub(Vector a,Vector b)
{
return Vector(a.x-b.x,a.y-b.y,a.z-b.z);
}
static float getDistance(Vector a, Vector b)
{
Vector s = Vector::sub(a,b);
float result = std::sqrt(s.x*s.x + s.y*s.y + s.z*s.z);
return result;
}
};
class Block
{
public:
std::string name;
Vector location;
int durability;
int textureid;
int type;
unsigned char id;
bool breakable;
bool visible;
Block() = default;
Block(
std::string n,
Vector location,
unsigned char id,
int durability,
int textureid,
int type,
bool breakable,
bool visible):
name{std::move(n)},
location{location},
durability{durability},
textureid{textureid},
type{type},
id{id},
breakable{breakable},
visible{visible}
{
}
};
class Entity
{
public:
std::string name;
Vector location;
Vector speed;
int health;
enum class Type { Zombie,Chicken,Exploder,TallCreepyThing };
Entity(Vector ,Type);
Entity() = default;
~Entity() = default;
void updatePosition();
};
Entity::Entity (Vector location,Type type)
{
this->location = location;
switch(type)
{
case Type::Zombie:
name = "Zombie";
health = 50;
speed = Vector(0.5,0.0,0.5);
break;
case Type::Chicken:
name = "Checking";
health = 25;
speed = Vector(0.75,0.25,0.75);
break;
case Type::Exploder:
name = "Exploder";
health = 75;
speed = Vector(0.75,0.0,0.75);
break;
case Type::TallCreepyThing:
name ="Tall Creepy Thing";
health = 500;
speed = Vector(1.0,1.0,1.0);
break;
}
}
void Entity::updatePosition()
{
location = Vector(location.x+1.0f*speed.x,location.y+1.0f*speed.y,location.z+1.0f*speed.z);
}
class Chunk
{
static constexpr const int NUM_BLOCKS = 65536;
static constexpr const int NUM_ENTITIES = 1000;
public:
std::array<unsigned char, NUM_BLOCKS> blocks;
std::vector<Entity> entities;
Vector location;
Chunk(Vector);
Chunk() = default;
~Chunk() = default;
void processEntities();
};
Chunk::Chunk(Vector location)
{
this->location = location;
for (int i = 0; i < NUM_BLOCKS;i++)
{
blocks[i] = i%256;
}
entities.resize(NUM_ENTITIES);
#pragma omp parallel for
for (int i = 0; i < NUM_ENTITIES;i=i+4)
{
entities[i] = Entity(Vector(i,i,i),Entity::Type::Chicken);
entities[i+1] = Entity(Vector(i+1,i,i),Entity::Type::Zombie);
entities[i+2] = Entity(Vector(i+2,i,i),Entity::Type::Exploder);
entities[i+3] = Entity(Vector(i+3,i,i),Entity::Type::TallCreepyThing);
}
}
void Chunk::processEntities()
{
for(auto& entity : entities)
{
entity.updatePosition();
}
}
class Game
{
public:
static constexpr const int CHUNK_COUNT = 100;
std::array<Block, 256> blocks;
std::array<Chunk, CHUNK_COUNT> chunks;
Vector playerLocation;
int chunkCounter;
Game();
void loadWorld();
void updateChunks();
};
Game::Game()
{
for (int i = 0; i < 256; i++)
{
blocks[i] = Block("Block" + std::to_string(i),
Vector(i,i,i), i, 100, 1, 1, true, true);
}
chunkCounter = 0;
playerLocation = Vector(0,0,0);
}
void Game::loadWorld() {
for (int i = 0; i < CHUNK_COUNT;i++)
{
chunks[i] = Chunk(Vector(chunkCounter,0.0,0.0));
chunkCounter++;
}
}
void Game::updateChunks()
{
boost::lockfree::queue<std::size_t, boost::lockfree::fixed_sized<true>, boost::lockfree::capacity<CHUNK_COUNT>> toRemove;
#pragma omp parallel for
for (int i = 0; i < CHUNK_COUNT;i++)
{
auto& chunk = chunks[i];
chunk.processEntities();
float chunkDistance = Vector::getDistance(chunk.location,playerLocation);
if (chunkDistance > CHUNK_COUNT)
{
toRemove.push(i);
}
}
std::size_t res;
while(toRemove.pop(res))
{
chunks[res] = Chunk(Vector(chunkCounter,0.0,0.0));
chunkCounter++;
}
}
int main()
{
auto game = new Game;
printf("%i\n", sizeof(Game));
high_resolution_clock::time_point start;
high_resolution_clock::time_point end;
printf("loading world...\n");
start = high_resolution_clock::now();
game->loadWorld();
end = high_resolution_clock::now();
auto duration = duration_cast<milliseconds>(end-start).count();
printf("load time:%lu\n",duration);
//spin
while(1)
{
start = high_resolution_clock::now();
Vector playerMovement = Vector(0.1,0.0,0.0);
game->playerLocation = Vector::add(playerMovement,game->playerLocation);
game->updateChunks();
end = high_resolution_clock::now();
auto duration = (double) (duration_cast<nanoseconds>(end-start).count() / 1000000.0);
printf("%f\n",duration);
if (duration < 16) {
this_thread::sleep_for(milliseconds((long)(16.0-duration)));
}
}
}
@jackmott
Copy link

jackmott commented Sep 9, 2016

Had to add #include array to get it to build.
Crashes when I run it, stack overflow.

@jcelerier
Copy link
Author

Heh.
Which platform are you ? I guess stack size is plenty under linux... The first line, Game game = Game(); (which could be shortened and made faster by just typing Game game;) allocates roughly 6 megabytes of memory on the stack.

Could you try with the updated version ? it is allocated on the heap instead on the stack from the beginning, which frees it and does not change the performance.

@jackmott
Copy link

Works great now! Mind if I add it to the blog? I can credit you and link your name to whatever you like.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment