0
\$\begingroup\$

I'm trying to make a voxel game while learning about OpenGL. The world is made up of many chunks of voxels. Therefore there is a Chunk class, containing an array of elements (which for now just are ints indicating if a voxel is solid (1) or empty(0) ).

There is a single World object that stores an std::vector<chunk> chunks member list. world is responsible for creating and initializing all of the chunks within. However, an important step in rendering the actual voxels is for the chunks to create a mesh based on which voxels are empty and which are full. To do this, each chunk iterates over its element array. If a voxel is solid, then it checks the orthogonally adjacent voxels and creates a quad (a class that encapsulates two triangles formatted for OpenGL) face on each exposed side.

An issue arises when the examined voxel is on the edge of its chunk. To check adjacent voxels past the edge, it needs to know data from a neighboring chunk about them. I have already tried storing a list Chunk* neighbors[6] of neighboring chunks in each chunk, and assigning them via the world before generating the mesh. However this still leaves holes where quads should have been generated along some borders, and interior walls of quads along others where none should have been generated.

View of the world; Terrain generated by noise, colors provided generously by the sin() function. Note the regular pattern of internal walls inside the structure and the gaps along borders near the top. This is what I'm trying to solve.

To generalize the process and make it more accessible to access information about any voxel in the world (which could obviously be useful later on for gameplay reasons), I then decided to implement a PositionInWorldIsSolid(x, y, z) function in the World class. The idea is that each chunk only needs to store a pointer to the world that owns all of them, and it can then call this function to access any chunk in the world if it needs information (in this early case, just about solidity). However, here I run into a problem.

The World class definition in World.h already includes the Chunk class #include "Chunk.h" so it can store the list of chunks, since generally the world should be acting on them and not the other way around. When I try to go backward and let the chunks access information about the other chunks through the world, they need to store a World* world referring to the single world object that owns them. To allow the chunks to use the type World I need to #include "World.h" in the Chunk.h file. This is obviously a problem; now I'm defining two classes by each other. Is there anyway I can get around this and allow each chunk to access the function in world or the list?

For context, this is probably the largest project I have ever attempted and I'm definitely not used to working with this many moving parts, but the whole point is to gain experience. That said, the project was an extension of a learnOpenGL tutorial project in visual studio; for whatever reason the tutorial uses header files for all class definitions, and only uses a .cpp file for the file containing main(). I've been following suite since I haven't generally had to use both ever before, but apparently there is a way to do this by forward declaring the classes each in their .h files and including each in their .cpp files (or perhaps vice-versa). I haven't tried this in case it's a lot of work to create .cpp's for every header involved, but if this is the recommended solution I would like to know.

[edit] now I have tried this with no success, really not sure what to do now.

\$\endgroup\$
8
  • \$\begingroup\$ "To allow the chunks to use the type World I need to #include "World.h" in the Chunk.h file." Not in every cases. What you need seems to be "forward declaration". Instead of including the header of the world in the header of the chunk, simply make the class aware it exists with class World;, but you include it (World.h) in the .cpp (Chunk.cpp) file. \$\endgroup\$ Commented Sep 22, 2022 at 2:58
  • 1
    \$\begingroup\$ There is an section about it in this answer: Break cyclic references where two definitions both use each other. \$\endgroup\$ Commented Sep 22, 2022 at 3:01
  • 2
    \$\begingroup\$ If you have tried this, then please give more details about what you tried exactly and what were the issues you've encountered; "with no success" does not give us any clues about how we could help you further. \$\endgroup\$ Commented Sep 22, 2022 at 3:05
  • \$\begingroup\$ Good point. I tried creating a Chunk.cpp file and including both headers there, defining the mesh generation function in it, and forward declaring the World class in chunk.h just as suggested. Near as I can tell the issue is because the chunk class depends on a separate Noise class that depends on an OpenSimplex implementation. Since chunk.cpp must include both chunk.h and world.h for forward declaration, and world.h already contains chunk.h, I think the files are creating multiple Noise classes and it consistently throws four Multiple Symbol errors in the linker for Noise class constants. \$\endgroup\$ Commented Sep 22, 2022 at 13:50
  • \$\begingroup\$ Do you have include guards in your header files (e.g. #pragma once or #ifndef BLABLA #define BLABLABLA #endif)? \$\endgroup\$ Commented Sep 22, 2022 at 13:53

0

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.