I’m trying to make a small 2D game using Odin & SDL3 to get to know odin better. I’m stuck at a point where in C I would have used a forward declaration but I can’t find how to do it the odin way.
I’ve a package state_mangager, here is a procedure of this package :
pop :: proc(manager: ^State_Manager, ctx: ^Game_Context) -> bool {
current, ok := pop_safe(&manager.stack)
if !ok do return false
if current.cleanup != nil do current.cleanup(ctx)
if !is_empty(manager) {
below := peek(manager)
if below.resume != nil do below.resume(ctx)
}
return true
}
The state manager pass a Game_Context struct to most of it’s functions, here is the Game_Context struct :
The Game_Context struct exist to be able to draw and retrieve asset from game state functions. But State_Manager doesn’t know about Game_Context and if I put Game_Context and it’s own package i’ll have a circular depency and it wil not work either ?
The easy solution is to put everything in the same package but it doesn’t feel right to me. What would be the correct approch to correctly structure the project without having this problem ?
It may seem strange at first, but it is the Odin way. It took me a while to get use to it, but the benefits become apparent with time. If you are looking to taxonomize the code, create different files per category of code, in the same folder, and use the same package name for all of them. Everything will know about each other. I typically use the high-level name of the project I’m working on as the package name for the whole project (package mysdlprojectname). The main procedure does not need to be in a package named “main”. It can have any package name, and the file may also have any name. I typically also name the file the “main” procedure is in the same as the package name to indicate it is the root of all things.
Something like:
Every file below will have at the top:
package myproject
myproject (top level folder)
--> myproject.odin (contains main procedure and any other procedure that make sense to be with main)
--> structs.odin (misc. struct definitions, struct creators, enums, etc.)
--> draw.odin (example category for draw procedures/structs)
--> controls.odin (I might put all my keyboard/mouse controls procedures/struct here)
--> init.odin (I may put init procedures here)
--> etc, etc ....
It is possible to separate things into different package names, but this is not the first choice. It’s more of an advanced approach to be used for very specific reasons. Circular references are a thing to be careful of, and force a very specific hierarchy. (i.e. package ‘A’ cannot import package ‘B’ if ‘B’ also imports from ‘A’.)
An example of this can be seen in the core/math package. The main entry point is in the math.odin file. All other files in the same directory level are also in the package “math”. The sub-directory core/math/cmplx has it’s own package name “math_cmplx” and would be imported separately. It only extends “math”, but the base math package does not use it. Another way to look at it, the “math” package provides base level support for the “cmplx” package, but not the other way around.
Lastly, I have an SDL3 hellope project available for reference if you are interested. It’s all in one file though, but may still be useful? On Windows, SDL3.dll, or on Linux, SDL3.lib must be in the same directory as the compiled exe for it to run. Copy them from “odin/vendor/sdl3” sdl3_hellope
I’ve found a solution using rawptr but it involve a lot of unknown in the code. Then after your answer i started searching for “official” information regarding the organisation of Odin projects and found this : Frequently Asked Questions | Odin Programming Language
I kinda disagree with the statemant, I don’t mind typing / prefixing my function or structures but having like +30 files in the same folder is kinda meh to me.
I’ll keep working on my little sokoban and see how it goes.
That is the common reaction, including me at first. Though with time, I understand the decision. I’m often on the command line, so changing directory to multiple sub-directories, or having multiple terminal tabs, I’ve found is more cumbersome than having all 30+ files in the same directory. I can just simply ls | grep filename and find my file very easily. Also tab complete for opening files, etc.
I don’t mind typing / prefixing my function or structures but having like +30 files in the same folder is kinda meh to me.
I feel you and at the same time it makes a lot of things easier.
We use a lot of Python at work and in Python it is quite easy to make deeply structured packages by simply adding directories and init.py files. One thinks it makes the code better and more readable but in practice it led to unnecessary abstraction and import problems when testing the packages partially. We always had the hussle to correctly set everything up for a new colleague and it did cost us some time. That’s why we switched to putting all python files in one directory and prefixing them by topics. We were skeptical at first but now…
We call it the flat programming style. It might have been a skill issue but this new style made import problems go away and has other benefits:
You want to start? Here is one directory of all files. You get a complete overview of all functionality, there is nothing hidden from you.
You want to refactor something? No problem, just move it from one file to another without thinking too much about artificial hierarchies.