Questions about global variables or state owned ones

#1

Good morning, lads. I need some help about little details I must know before starting to make a game. I’m very much new to Rust and Amethyst, please do take it easy on me. So,

  1. Is there a way to store a mutable variable (more specifically a 2D array of unknown size at compile tile) at a State, or have it globally available? I’m aware of mutable statics but I’d rather not want to write unsafe everywhere, although I guess I could encapsulate it in a function. However, you need to specify array size in static arrays if I’m not very much mistaken, and that’s a no go. You see I need such a 2D array for this is a procedurally generated tile based game and I’d need to know and change tiles and even map size.

  2. This is related to the above. If the map is global there’s no issue, so this is just a technical question about Rust. How do you pass a mutable 2D array of unknown size as a parameter? I’ve searched this and people go in depth of Rust mechanics but do not answer, after all, how to do it. Surely there is a way?

  3. I promise I had more questions before going to sleep but since then I’ve forgotten them. I’ll leave this here in case I remember.

  4. You need to make this forum more visible… I just found it by accident, looking at your news, which is not exactly the place I would expect to find it.

Although I wasn’t expecting to find my dead family in the news either. I’m sorry, obligatory dark humor.

1 Like

(Thomas Schaller) #2

Welcome @MisterRUBI! Let me give you an answer to your technical questions, I’ll leave the other one to our Community Team :slight_smile:

If you need a dynamic 2D array, a 2D array in Rust is actually not what you want. Instead, you’ll want to use a one-dimensional, flat array and pass the width.

// Create a 5 x 3 map
let mut map = vec![
    1, 2, 3, 4, 5,
    1, 2, 3, 4, 5,
    1, 2, 3, 4, 5,
];

work_with_map(&mut map, 5);

Now, work_with_map looks something like this:

fn work_with_map(map: &mut [u32], width: usize) {
    let height = map.len() / width;

    for y in 0..height {
        for x in 0..width {
            let number = &mut map[y * width + x];
        }
    }
}

Yes. You can either store it in your state (if that’s the only place you need it) or, alternatively, store it in the World as a resource, which are essentially just globals. You can read this chapter about resources to learn more.

1 Like

#3

Ah, yes, I thought about using index magic… admittedly I would like to avoid that for reasons of ugly, but I guess there’s no way around. It’ll be rather complex changing the map size like this, as you’ll have to insert elements mid-array to expand it’s width. I suppose I could implement a struct to make it easier. Kind of disappointed with Rust though, not gonna lie :smile:

And thank you very much for pointing me to the right direction… I know it seems I’m a dumb little bastard for not reading the tutorial, but I’m a more practical person and went right to the pong example. Although I haven’t finished that either, so I guess I still am a dumb little bastard.

If it’s worth anything, from what I have seen so far this is probably the engine of my wildest dreams. Great job into every aspect of it.

0 Likes

(Khionu Sybiern) #4

We do have it linked in the footer of the website, but we can make it a point to review where else we can put it! Thank you for raising this concern!

1 Like

#5

For anyone that reads and needs, a simple generic implementation of a 2D array:

pub struct Map<T> {
    vec: Vec<T>,
    width: usize,
    height: usize
}

impl<T> Map<T> {
    pub fn new(default_value: T, width: usize, height: usize) -> Self
        where T: Copy
    {
        Map {
            width: width,
            height: height,
            vec: vec![default_value; width * height]
        }
    }

    pub fn get(&self, x: usize, y: usize) -> &T {
        &self.vec[y * self.width + x]
    }

    pub fn set(&mut self, x: usize, y: usize, value: T) {
        self.vec[y * self.width + x] = value;
    }
    
    pub fn width(&self) -> usize {
        self.width
    }

    pub fn height(&self) -> usize {
        self.height
    }
}

macro_rules! map {
    ($d:expr; $w:expr, $h:expr) => {
        Map::new($d, $w, $h)
    };
}

For consistency sake there’s a macro to match the vec! and array constructor syntax e.g map![false; 5, 3] creates a 5 wide 3 tall map filled with false.

0 Likes