And I get weird texture id's and sizes get print out like:
button textureID: 980224768
button texture size: 0 x -8619008
button textureID: 32767
button texture size: 6 x 100663296
button textureID: 60106480
button texture size: 32767 x 2
button textureID: 100663296
button texture size: 5061087 x 0
I suppose that I'm doing something wrong with memory but I don't know.
#Getting weird textures in Raylib
41 messages · Page 1 of 1 (latest)
A slice (such as []Button) is just a pointer to data that exists somewhere else. When you assign a literal to a slice, as you're doing with button_list in set_and_init_screen, what it actually does is create a fixed array on the stack and then set the slice point to that fixed array. The stack space that the array is in is no longer reserved once the proc returns, and can be overwritten by any other procs that gets called
So what is the correct way to do it?
I think I understood it
g_state.button_list[0] = Button{
{GAME_SIZE[0] / 2 - g_state.assets.textures.gui.resume_button.width - 20, 150},
g_state.assets.textures.gui.resume_button,
}
g_state.button_list[1] = Button{
{GAME_SIZE[0] / 2 + 20, 100},
g_state.assets.textures.gui.select_save_button,
}
g_state.button_list[2] = Button{
{GAME_SIZE[0] / 2 - g_state.assets.textures.gui.help_button.width - 20, 300},
g_state.assets.textures.gui.help_button,
}
g_state.button_list[3] = Button{
{GAME_SIZE[0] / 2 + 20, 300},
g_state.assets.textures.gui.quit_button,
}```
Is this how I should do it?
Don't forget to delete(g_state.button_list) when you don't need it.
Also, i would use dynamic array for this case, something like:
g_state.button_list = make([dynamic] Button) // no need to say button count here
// now just add buttons as needed (no need to specify index)
append(&g_state.button_list, Button{
{GAME_SIZE[0] / 2 - g_state.assets.textures.gui.resume_button.width - 20, 150},
g_state.assets.textures.gui.resume_button,
})
// ...
thank you both
and i also get a segmentation fault if i delete() and set a new button list while iterating over it using a for in loop
i kinda fixed it by breaking the for loop after updating
and because that the button drawing runs every game frame only a flash happens
but is there any way to circumvent it from either segfaulting or having it flash
Hard to say without seeing what you're actually doing. If you're going the dynamic array route, you may not need to delete it at all; just clear it and add the new values
im using slices
like here
can post a chunk of the code..
That would probably help
draw_and_handle_button :: proc(button: Button) -> bool {
mouse_pos := GetScaledMousePosition()
hovered := rl.CheckCollisionPointRec(
mouse_pos,
rl.Rectangle {
f32(button.position.x),
f32(button.position.y),
f32(button.texture.width),
f32(button.texture.height),
},
)
if rl.IsMouseButtonPressed(rl.MouseButton.LEFT) && hovered {
button.callback()
return false // Should break when false if looping over button_list // Prevents segmenation fault because button may modify the button list
}
draw_button(button, hovered)
return true
}
for button in g_state.button_list {
ok := draw_and_handle_button(button)
if !ok {
break
}
}```
GlobalState :: struct {
...
button_list: []Button,
...}
set_and_init_screen :: proc(screen: Screen, force: bool = false) {
if g_state.current_screen == screen && !force {
return
}
fmt.println("Freeing button list")
free_button_list()
fmt.println("Setting current screen")
g_state.previous_screen = g_state.current_screen
g_state.current_screen = screen
#partial switch screen {
case .MAIN_MENU:
fmt.println("Setting up main menu")
// Allocate the button list on the heap
g_state.button_list = make([]Button, 4)
g_state.button_list[0] = Button {
{GAME_SIZE[0] / 2 - g_state.assets.textures.gui.resume_button.width - 20, 150},
g_state.assets.textures.gui.resume_button,
proc() {
fmt.println("Resume button pressed")
//set_and_init_screen(.GAME)
},
}
g_state.button_list[1] = Button {
{GAME_SIZE[0] / 2 + 20, 150},
g_state.assets.textures.gui.select_save_button,
proc() {
set_and_init_screen(.SELECT_LEVEL)
},
}
g_state.button_list[2] = Button {
{GAME_SIZE[0] / 2 - g_state.assets.textures.gui.help_button.width - 20, 300},
g_state.assets.textures.gui.help_button,
proc() {
set_and_init_screen(.STARS_OBTAINED)
},
}
g_state.button_list[3] = Button {
{GAME_SIZE[0] / 2 + 20, 300},
g_state.assets.textures.gui.quit_button,
proc() {
g_state.exit_next_frame = true
},
}
case .GAME:
fmt.println("Setting up game")
case:
fmt.println("!!!!!!! Unimplemented screen")
}
}
if i dont do break here
the game segfaults because i delete the button_list before updating it in the button callback and on the next iteration of the for loop, the game crashes
if i break after calling callback, it doesnt crash but this causes a flash in the game rendering which would be good if not happen
If you try and use the buttons after you've deleted the slice, then that'll definitely cause issues. You probably need to draw and handle the buttons separately; handle them first, do any necessary state changes, and only draw once you've decided what's actually going to go on screen
but even if i seperately iterate it would still crash
because the callback first deletes the button_list and then updates it with new data
which when for loop iterates again segfaults
maybe a dynamic array will fix it but i dont think that its necessary because the data is not that dynamic
A dynamic array would make it easier to re-use the same memory, instead of having to delete it and reallocate every time you want to change it.
For the handling part, you'd probably still want the same logic to stop handling buttons once you've pressed ones. But for drawing, you don't need to worry about the button list changing mid-iteration
ah yes the separation will hide the flash, thanks
so i tested and just using a dynamic array instead of slice does fix the issue too (segfault and flash) (without needing to break)
should i fix it by using dynamic_array or by separating the button drawing/handling logic and breaking in the handling like i did before?
The dynamic array will (somewhat) help prevent crashes in that the array won't be moved as often, but you can still get a different form of flashing issue if you don't separate the drawing logic. It's very common for game logic to be update first, then draw. If you try and do both at once, you can end up "splitting" your states, i.e. you draw the first 2 buttons of one state, but the second was clicked so it chagnes state, and you draw the third and on buttons from the other state
well the flashing was happening because i was breaking in the for loop to prevent segfaulting
but in the dynamic array no segfault happens and i can remove the break
separation also means iterating two times but probably it would be a micro optimization so shouldnt be too important i guess
do you iterate an array while adding/removing items into/from it? keep in mind that dynamic array can reallocate and move its content when you append items. So i would suggest to do in two steps: add buttons and draw them -- are two separate parts.
You still shouldn't count on being able to change the contents of the dynamic array mid-iteration without anything breaking
okay i will separate them, thanks for the help
sorry to bother again but how exactly do i separate
for button in g_state.button_list {
ok, hovered := handle_button(button)
if !ok {
break
}
}
// draw buttons
for button in g_state.button_list {
draw_button(button, hovered)
}```
draw function needs is hovered
maybe a "hovered_buttons" dynamic array ?
well. i would do it like:
- add
is_hovered: boolto yourButtonstruct - now you can separate all: add all buttons -> update state of all buttons (set/clear is_hovered) -> draw all buttons
but then i would need to explicitly set hovered to false when initializing a Button struct
Anything you don't set is zeroed by default. For booleans, that means false
not exactly. if you init strcut every time before drawing/updating, it will be false by default. the "zero value" of type bool is false
compiler says Too few values in structure literal, expected 4, got 3 if i try to do that
Ah, I guess that only works if you initialize things by name
you need to specify field names if you don't specify all in order
or just add false in your init list -- up to you
yea it doesnt complain if i do that, would be great if you could omit some without having to do everything named