Compare commits

...
Sign in to create a new pull request.

12 commits
3d ... main

5 changed files with 245 additions and 34 deletions

3
README.md Normal file
View file

@ -0,0 +1,3 @@
This is a prototype for a game engine im doing, its very messy and imperfect, but its a working vulkan renderer (and an small minigame that doesnt work yet) made in c++23 that works in basically any system that supports vulkan (with some changes to the CMakeLists.txt file)
I'm learning while writing this so expect some bad practices and weird stuff!

268
main.cpp
View file

@ -7,8 +7,12 @@
#include <glm/glm.hpp>
#include <atomic>
#include <thread>
#include <random>
bool skip_rendering = false;
bool stop_physics = false;
std::atomic_bool pressed_space = false;
std::atomic_bool pressed_shift = false;
vk::SurfaceFormatKHR format;
vk::Extent2D framebuffer_extension;
@ -26,13 +30,31 @@ struct bounding_box
float y;
float width;
float height;
float velocityX;
float velocityY;
float accX;
float accY;
};
struct uniform
{
glm::mat4 view;
};
struct push
{
glm::mat4 transform;
};
struct quad
{
bounding_box box;
std::vector<vertex> vertices;
push trans;
};
bounding_box player;
float velocityX = 1.0f;
float velocityY = 0.50f;
@ -197,16 +219,53 @@ void simple_physics()
}
}
void simple_physics_step(float t)
bool simple_physics_step(float t, bounding_box &box, std::vector<quad> &boxes, bool &on_ground)
{
bool collision_x = player.x + player.width / 2 >= 1.0f || player.x - player.width / 2 <= -1.0f;
bool collision_y = player.y + player.height / 2 >=1.0f || player.y - player.height / 2 <= -1.0f;
box.y += box.velocityY * t + 0.5 * box.accY * (t * t);
box.velocityY += box.accY * t;
box.x += box.velocityX * t + 0.5 * box.accX * (t * t);
box.velocityX += box.accX * t;
bool end_game = false;
for (auto &b: boxes)
{
b.box.y += b.box.velocityY * t + 0.5 * b.box.accY * (t * t);
b.box.velocityY += b.box.accY * t;
b.box.x += b.box.velocityX * t + 0.5 * b.box.accX * (t * t);
b.box.velocityX += b.box.accX * t;
bool collision_x = b.box.x + b.box.width / 2 >= box.x - box.width /2 && b.box.x - b.box.width / 2 <= box.x + box.width /2;
bool collision_y = b.box.y + b.box.height / 2 >= box.y - box.height /2 && b.box.y - b.box.height / 2 <= box.y + box.height /2;
end_game = collision_x && collision_y;
if (end_game)
{
#ifdef NDEBUG
std::println("Collision between pos x: {} y: {} and pos x: {} and pos y: {} ", box.x, box.y, b.box.x, b.box.y);
std::println("With width: {} and height: {} and width: {} and height: {}", box.width, box.height, b.box.width, b.box.height);
std::println("Rightmost vertex in position {} collided with leftmost vertex in position {}", box.x + box.width/2, b.box.x - b.box.width/2);
#endif
}
}
bool collision_x = box.x + box.width / 2 >= 1.0f || box.x - box.width / 2 <= -1.0f;
bool collision_top_y = box.y - box.height / 2 <= -1.0f;
bool collision_bottom_y = box.y + box.height / 2 >=1.0f;
if (collision_x)
velocityX = -velocityX;
else if (collision_y)
velocityY = -velocityY;
player.x = player.x + (velocityX * t);
player.y = player.y + (velocityY * t);
box.velocityX = 0;
else if (collision_top_y)
{
box.velocityY = 0;
box.y = -1.0f + box.height/2;
}
else if (collision_bottom_y)
{
box.velocityY = 0.0f;
box.y = 1.0f - box.height/2;
on_ground = true;
}
return end_game;
}
std::pair<vk::DeviceMemory, vk::Buffer> create_buffer(const vk::Device &device, vk::PhysicalDevice selected_physical_device, vk::BufferUsageFlagBits usage, size_t size)
@ -238,11 +297,66 @@ std::pair<vk::DeviceMemory, vk::Buffer> create_buffer(const vk::Device &device,
return std::make_pair(vertex_buffer_memory, vertex_buffer);
}
void keyboard_handle(GLFWwindow *window, int key, int scancode, int action, int mods)
{
if (key == GLFW_KEY_SPACE && action == GLFW_PRESS)
{
//std::println("JUMP!");
pressed_space = true;
}
else if (key == GLFW_KEY_LEFT_SHIFT && action == GLFW_PRESS)
{
pressed_shift = true;
}
if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
exit(0);
}
bounding_box spawn_enemy(std::mt19937 rng)
{
std::uniform_real_distribution<float> dist(0.05, 0.4);
std::uniform_real_distribution<float> y_dist(0.6, 0.9);
std::uniform_real_distribution<float> vel_dist(-1.5, -0.5);
bounding_box ret{0};
ret.height = dist(rng);
ret.width = dist(rng);
ret.x = 0.8;
ret.y = y_dist(rng);
ret.velocityX = vel_dist(rng);
return ret;
}
void add_quad_to_vertices(std::vector<vertex> &vertices, std::vector<vertex> new_quad)
{
new_quad = convert_quad_to_triangles(new_quad);
for (auto vert: new_quad)
{
//std::println("Vertex pos x: {}, y: {}, z: {}", vert.position.x, vert.position.y, vert.position.z);
vertices.push_back(vert);
}
}
std::vector<vertex> bounding_box_to_vertices(const bounding_box &box)
{
float half_width = box.width/2;
float half_height = box.height/2;
std::vector<vertex> vertices = {
{{-half_width, -half_height}, {1.0f, 0.0f, 0.0f}},
{{half_width, -half_height}, {1.0f, 0.0f, 0.0f}},
{{half_width, half_height}, {0.0f, 1.0f, 0.0f}},
{{-half_width, half_height}, {0.0f, 0.0f, 1.0f}}
};
return vertices;
}
int main()
{
using clock = std::chrono::system_clock;
using ms = std::chrono::duration<double, std::milli>;
GLFWwindow *window = create_window(1000, 800, "hello");
std::random_device dev;
std::mt19937 rng(dev());
if (!window)
return -1;
@ -268,7 +382,12 @@ int main()
#endif
vk::InstanceCreateInfo createinfo = vk::InstanceCreateInfo(
vk::InstanceCreateFlags(VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR),
#ifdef __APPLE__
vk::InstanceCreateFlags(VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR),
#endif
#ifdef __linux__
vk::InstanceCreateFlags(),
#endif
&appinfo,layers.size(), layers.data(),
extensions.size(), extensions.data());
vk::Instance instance = vk::createInstance(createinfo);
@ -436,13 +555,17 @@ int main()
vk::DescriptorSetLayoutCreateInfo descriptor_layout_info(vk::DescriptorSetLayoutCreateFlags(), 1, &descriptor_binding);
vk::DescriptorSetLayout descriptor_layout = device.createDescriptorSetLayout(descriptor_layout_info);
vk::PushConstantRange push_constant(vk::ShaderStageFlags(vk::ShaderStageFlagBits::eVertex), 0, sizeof(push));
vk::PipelineLayoutCreateInfo layout_info = {};
layout_info.setLayoutCount = 1;
layout_info.pSetLayouts = &descriptor_layout;
layout_info.pushConstantRangeCount = 1;
layout_info.pPushConstantRanges = &push_constant;
vk::PipelineLayout pipeline_layout = device.createPipelineLayout(layout_info);
uniform u{};
u.transform = glm::mat4(1.0f);
u.view = glm::mat4(1.0f);
auto rec = create_buffer(device, selected_physical_device, vk::BufferUsageFlagBits::eUniformBuffer, sizeof(uniform));
vk::DeviceMemory uniform_buffer_data = rec.first;
vk::Buffer uniform_buffer = rec.second;
@ -512,19 +635,20 @@ int main()
framebuffer_extension.height, 1);
framebuffers.push_back(device.createFramebuffer(framebuffer_info));
}
std::vector<vertex> vertices = {
{{-0.1f, -0.1f}, {1.0f, 0.0f, 0.0f}},
{{0.1f, -0.1f}, {1.0f, 0.0f, 0.0f}},
{{0.1f, 0.1f}, {0.0f, 1.0f, 0.0f}},
{{-0.1f, 0.1f}, {0.0f, 0.0f, 1.0f}}
quad play{};
play.box = player;
play.vertices = {
{{-0.05f, -0.1f}, {1.0f, 0.0f, 0.0f}},
{{0.05f, -0.1f}, {1.0f, 0.0f, 0.0f}},
{{0.05f, 0.1f}, {0.0f, 1.0f, 0.0f}},
{{-0.05f, 0.1f}, {0.0f, 0.0f, 1.0f}}
};
vertices = convert_quad_to_triangles(vertices);
auto ret = create_buffer(device, selected_physical_device, vk::BufferUsageFlagBits::eVertexBuffer, sizeof(vertices[0]) * vertices.size());
vk::DeviceMemory vertex_buffer_memory = ret.first;
play.vertices = convert_quad_to_triangles(play.vertices);
auto ret = create_buffer(device, selected_physical_device, vk::BufferUsageFlagBits::eVertexBuffer, sizeof(vertex) * 6 * 100);
vk::DeviceMemory vertex_memory = ret.first;
vk::Buffer vertex_buffer = ret.second;
char *data = (char *)device.mapMemory(vertex_buffer_memory, 0, sizeof(vertices[0]) * vertices.size());
memcpy(data, vertices.data(), sizeof(vertices[0]) * vertices.size());
char *vertex_data = (char *)device.mapMemory(vertex_memory, 0, sizeof(vertex) * 6 * 100); // 100 quads
memcpy(vertex_data, play.vertices.data(), sizeof(play.vertices[0]) * play.vertices.size());
vk::CommandPoolCreateInfo command_pool_info = {};
@ -575,22 +699,34 @@ int main()
player.x = 0.0f;
player.y = 0.0f;
player.height = 0.2f;
player.width = 0.2f;
player.width = 0.1f;
//velocityX = 0.008f;
std::vector<vertex> render_vertices = vertices;
float angle = 0.0f;
float vel2 = 0.005f;
//std::thread phy_thread(simple_physics);
glfwSetKeyCallback(window, keyboard_handle);
auto before = clock::now();
player.accY = 1.3f;
player.x = -0.8;
player.y = -0.5;
play.box = player;
std::vector<quad> enemies;
bool on_ground = true;
int jumps = 0;
int score = 0;
while(!glfwWindowShouldClose(window))
{
glfwPollEvents();
std::vector<vertex> render_vertices = play.vertices;
auto res_wait = device.waitForFences(next_frame_fence, VK_TRUE, UINT64_MAX);
if (res_wait != vk::Result::eSuccess)
throw std::runtime_error("failed waiting!");
device.resetFences(next_frame_fence);
if (skip_rendering)
{
continue;
}
auto image_result = device.acquireNextImageKHR(swapchain, UINT64_MAX, image_semaphore);
if (image_result.result != vk::Result::eSuccess)
{
@ -598,14 +734,70 @@ int main()
}
uint32_t image_index = image_result.value;
vkResetCommandBuffer(command_buffers[0], 0);
if (enemies.empty())
{
quad enemy{};
std::mt19937 rng2(dev());
enemy.box = spawn_enemy(rng2);
enemy.vertices = bounding_box_to_vertices(enemy.box);
enemy.trans.transform = glm::mat4{1.0f};
enemies.push_back(enemy);
}
auto time_elapsed = clock::now() - before;
simple_physics_step(std::chrono::duration_cast<std::chrono::duration<float>>(time_elapsed).count());
if (pressed_space == true)
{
#ifndef NDEBUG
//std::println("JUMP!");
#endif
if (on_ground || jumps <= 1)
{
if (jumps <= 1)
play.box.velocityY = -1.2f;
on_ground = false;
jumps++;
std::println("Jumps {}", jumps);
}
pressed_space = false;
}
if (pressed_shift == true)
{
play.box.velocityY = 3.0f;
pressed_shift = false;
}
bool end_game = false;
if (stop_physics == false)
end_game = simple_physics_step(std::chrono::duration_cast<std::chrono::duration<float>>(time_elapsed).count(), play.box, enemies, on_ground);
if (on_ground)
jumps = 0;
if (end_game == true)
{
std::println("You lost!");
std::println("Your score was {}", score);
stop_physics = true;
#ifndef NDEBUG
std::println("Collision between pos x: {} y: {} and pos x: {} and pos y: {} ", play.box.x, play.box.y, enemies[0].box.x, enemies[0].box.y);
std::println("With width: {} and height: {} and width: {} and height: {}", play.box.width, play.box.height, enemies[0].box.width, enemies[0].box.height);
std::println("Rightmost vertex in position {} collided with leftmost vertex in position {}", play.box.x + play.box.width/2, enemies[0].box.x - enemies[0].box.width/2);
std::println("Jumps {}", jumps);
#endif
}
before = clock::now();
u.transform = move({player.x, player.y}) * rotate(angle);
memcpy(uniform_data, &u, sizeof(uniform));
play.trans.transform = move({play.box.x, play.box.y});
for (auto &e: enemies)
{
if (e.box.x + e.box.width/2 <= -1.0f)
{
score += (int)(abs((e.box.width * 10)) + abs((e.box.height * 10)) + abs((e.box.velocityX * 10)));
enemies.clear();
break;
}
e.trans.transform = move({e.box.x, e.box.y});
add_quad_to_vertices(render_vertices, e.vertices);
}
//memcpy(uniform_data, &u, sizeof(uniform));
angle -= 1.0f;
memcpy(data, render_vertices.data(), sizeof(vertices[0]) * vertices.size());
angle -= 0.01f;
memcpy(vertex_data, render_vertices.data(), sizeof(render_vertices[0]) * render_vertices.size());
vk::CommandBufferBeginInfo begin_info = {};
@ -621,14 +813,23 @@ int main()
//command_buffers[0].setScissor(0, scissor);
command_buffers[0].bindDescriptorSets(vk::PipelineBindPoint::eGraphics, pipeline_layout, 0, descriptor_sets, nullptr);
command_buffers[0].bindVertexBuffers(0, 1, &vertex_buffer, &offset);
command_buffers[0].draw(vertices.size(), 1, 0, 0);
command_buffers[0].pushConstants(pipeline_layout, vk::ShaderStageFlags(vk::ShaderStageFlagBits::eVertex), 0, sizeof(push), &play.trans);
command_buffers[0].draw(6, 1, 0, 0);
uint32_t offset_vertex = 6;
for (auto &e: enemies)
{
command_buffers[0].pushConstants(pipeline_layout, vk::ShaderStageFlags(vk::ShaderStageFlagBits::eVertex), 0, sizeof(push), &e.trans);
command_buffers[0].draw(6, 1, offset_vertex, 0);
offset_vertex += 6;
}
command_buffers[0].endRenderPass();
if (vkEndCommandBuffer(command_buffers[0]) != VK_SUCCESS)
{
throw std::runtime_error("Command buffer creation failed!");
}
vk::PipelineStageFlags flags = vk::PipelineStageFlags(vk::PipelineStageFlagBits::eColorAttachmentOutput);
vk::PipelineStageFlags flags(vk::PipelineStageFlagBits::eColorAttachmentOutput);
vk::SubmitInfo submit_info = vk::SubmitInfo();
submit_info.waitSemaphoreCount = 1;
submit_info.pWaitSemaphores = &image_semaphore;
@ -653,12 +854,15 @@ int main()
}
thread = false;
//phy_thread.join();
device.unmapMemory(vertex_buffer_memory);
device.unmapMemory(uniform_buffer_data);
device.unmapMemory(vertex_memory);
device.waitIdle();
device.destroyDescriptorPool(descriptor_pool);
device.destroyDescriptorSetLayout(descriptor_layout);
device.destroyBuffer(vertex_buffer);
device.freeMemory(vertex_buffer_memory);
device.destroyBuffer(uniform_buffer);
device.freeMemory(vertex_memory);
device.freeMemory(uniform_buffer_data);
for (auto &framebuffer: framebuffers)
{
device.destroyFramebuffer(framebuffer);

Binary file not shown.

Binary file not shown.

View file

@ -3,9 +3,13 @@
// x -> -1 (left) 1(right)
// y -> -1 (top) 1(bottom)
layout(binding = 0) uniform un{
layout( push_constant ) uniform push{
mat4 transform;
} trans;
}trans;
layout(binding = 0) uniform un{
mat4 view;
} view;
layout(location = 0) in vec2 in_position;
layout(location = 1) in vec3 in_color;