Howdy folks,
Old timey C programmer here, I've written a game in C and I'm playing with the idea of writing it in Rust as an exercise.
Background: the engine is vector based, so I have loads and loads of x and y arrays, where the data for all visuals is essentially stored like
sprite->animations[WALK]->frame[WALK0]->polygon[FACE]->x[...]
sprite->animations[WALK]->frame[WALK0]->polygon[FACE]->y[...]
So a sprite is an array of animations, animations are an array of frames, frames are arrays of polygons, and polygons are arrays of ints.
Nothing is loaded from disc, I'm basically transpiling SVGs to C structs, where the result is a macro hell of static arrays and structs in psuedocode:
// mysprite.h
extern sprite MYSPRITE;
// mysprite.c
static sprite MYSPRITE = {
.animations = animation_t[]{
{
.frames = frame_t[]{
.polygons = polygon_t[]{
(polygon_t){
.x = {1, 2, 3},
.y = {3, 4, 5}
}
}
}
}
}
}
etc, etc, but imagine this going on for 1k LOC per sprite.
And thus, all sprites are loaded from .data onto the heap, and persist for the lifetime of the application.
Anyway, I'm trying to figure out a way to essentially reproduce this in Rust. I'd like to have a way to fetch these data chunks from modules in Rust, where the end code looks like
use sprites::{bullet,character,monster};
let local_bullet = new_sprite_from(sprite::bullet);
local_bullet.x = 320;
local_bullet.y = 320;
draw_sprite(local_bullet);
This is essentially how my code functions now, except without the namespacing, everything is just global, so it's a matter of a header inclusion to just get the address.
Finally, the problem:
How do I create const static structs (or what would be a good replacement for them), with dynamic length members to create a similar tree structure?
I've tried:
// const pointers
struct CPolygon {
x: *const [i16],
y: *const [i16],
}
static cp: CPolygon = CPolygon {
x: &[1, 2, 3],
y: &[4, 5, 6],
};
// *const [i16]` cannot be shared between threads safely
// vectors
struct VPolygon {
x: Vec<[i16]>,
y: Vec<[i16]>,
}
static vp: VPolygon = VPolygon {
x: [1, 2, 3],
y: [4, 5, 6],
};
// doesn't have a size known at compile-time
// boxes
struct BPolygon {
x: Box<[i16]>,
y: Box<[i16]>,
}
static bp: BPolygon = BPolygon {
x: Box::new([1, 2, 3]),
y: Box::new([4, 5, 6]),
};
// calls in statics are limited to constant functions, tuple structs and tuple variants
// my least favorite, but seems to work, writing a ::new() function
struct NPolygon {
x: Box<[i16]>,
y: Box<[i16]>,
}
struct NFrame {
polygons: Box<NPolygon>
}
fn gen_fram0() -> NFrame {
let f = NFrame {
polygons: Box::new(
NPolygon {
x: Box::new([1, 2, 3]),
y: Box::new([4, 5, 6]),
}
)
};
return f;
}
//
I suppose I've answered my own question here. The bottom being the solution and just doing
use sprites::{bullet};
let local_bullet = sprites::bullet::new();
local_bullet.x = 320;
local_bullet.y = 320;
draw_sprite(local_bullet);
But as a new goober, would appreciate any feedback or tips. Thanks!