|
(Fixed) Storing and reading sprite data from a linked list |
Winfield
Member #15,244
July 2013
|
Note: a character I pasted in my previous attempt killed the post. I hope someone can delete that one. Sorry. :/ I'm writing a small sprite loading and management system for my game which reads sprite data out of Allegro config files which look like this: 1[still_up_1]
2x = 64
3y = 0
4w = 64
5h = 96
6
7[still_down_1]
8x = 192
9y = 0
10w = 64
11h = 96
12
13[still_left_1]
14x = 384
15y = 0
16w = 64
17h = 96
18
19[still_right_1]
20x = 256
21y = 480
22w = 64
23h = 96
24
25
26[walk_up_1]
27x = 0
28y = 0
29w = 64
30h = 96
31
32[walk_up_2]
33x = 64
34y = 0
35w = 64
36h = 96
37
38[walk_up_3]
39x = 128
40y = 0
41w = 64
42h = 96
I store that data in a series of structs as follows: 1const char *sprite_directions[] = {"up", "down", "left", "right", NULL};
2const char *sprite_states[] = { "still", "walk", NULL };
3
4typedef struct
5{
6 char state[32]; // Textual identifier for animation (walk, run, etc)
7 char dir[32]; // Direction (north, south, etc)
8 int cycle; // Frame number
9 int x; // Starting X of frame in bitmap
10 int y; // duh
11 int h; // Width on bitmap
12 int w; // yeah
13} ANNE_SPRITE_FRAME;
14
15typedef struct
16{
17 GList *frame;
18} ANNE_SPRITE_ANIMATIONS;
19
20typedef struct
21{
22 ALLEGRO_BITMAP *bitmap;
23 char name[255];
24 ANNE_SPRITE_ANIMATIONS anim;
25 ANNE_SPRITE_FRAME current;
26} ANNE_SPRITE;
As you can see, each frame has a direction, state, and animation index, and each state (walk, stand, run, etc) can have an indeterminate number of frames. I have several functions for working with these - to load a sprite: 1// Loads a sprite from the filesystem and into memory, and initializes a starting
2// frame.
3ANNE_SPRITE anne_sprite_load(char sprite_name[]){
4 ANNE_SPRITE *sprite = malloc(sizeof(*sprite));
5 ANNE_SPRITE_ANIMATIONS *anim = malloc(sizeof(*anim));
6
7 anim->frame = NULL;
8
9 int k = 0;
10
11 char def_file_name[255];
12 char image_file_name[255];
13 char current_anim_state[64];
14 char current_anim_frame[128];
15
16 char state[32];
17 char dir[16];
18
19 int cycle = 0;
20 int x = 0;
21 int y = 0;
22 int w = 0;
23 int h = 0;
24 srand(time(NULL));
25
26 sprintf(def_file_name, "data/sprites/%s.spr", sprite_name);
27 sprintf(image_file_name, "data/sprites/%s.png", sprite_name);
28 sprintf(sprite->name, "%s", sprite_name);
29 sprintf(sprite->current.state, "%s", sprite_states[0]);
30 sprintf(sprite->current.dir, "%s", sprite_directions[0]);
31
32 // for convenience we use the config reader to parse the sprite definition file
33 ALLEGRO_CONFIG* sprite_definition = al_load_config_file(def_file_name);
34
35
36
37 for (int i = 0; 1; i++) {
38
39 if (sprite_states[i] == NULL) { break; }
40 sprintf(current_anim_state, "%s", sprite_states[i]);
41
42 #ifdef DEBUG
43 printf("i | %s\n", sprite_states[i]);
44 #endif
45
46 for (int j = 0; 1; j++) {
47 // The center loop simply iterates through the directions with the
48 // innermost loop.
49 if (sprite_directions[j] == NULL) { break; }
50 for (k = 1; 1; k++) {
51 // In the innermost loop, we're stepping through a single state/direction
52 // pair and extracting the bitmap coordinates and dimensions and feeding them
53 // into a struct which we store in the animation.
54 //
55 // Let's get the current animation frame title from our lookups...
56 sprintf(current_anim_frame, "%s_%s_%i", sprite_states[i], sprite_directions[j], k);
57
58 // If it's missing any values, we can't render it properly. In this case, we break
59 // the current loop because chances are we've already read in all of this animation's
60 // frames.
61 if ( NULL == al_get_config_value(sprite_definition, current_anim_frame, "x") ||
62 NULL == al_get_config_value(sprite_definition, current_anim_frame, "y") ||
63 NULL == al_get_config_value(sprite_definition, current_anim_frame, "w") ||
64 NULL == al_get_config_value(sprite_definition, current_anim_frame, "h")
65 ) { break; }
66
67 sprintf(state, "%s", sprite_states[i]);
68 sprintf(dir, "%s", sprite_directions[j]);
69 x = atoi(al_get_config_value(sprite_definition, current_anim_frame, "x"));
70 y = atoi(al_get_config_value(sprite_definition, current_anim_frame, "y"));
71 w = atoi(al_get_config_value(sprite_definition, current_anim_frame, "w"));
72 h = atoi(al_get_config_value(sprite_definition, current_anim_frame, "h"));
73
74 ANNE_SPRITE_FRAME thisFrame;
75 sprintf(thisFrame.state, "%s", sprite_states[i]);
76 sprintf(thisFrame.dir, "%s", dir);
77 thisFrame.x = x;
78 printf("> x: %i | ", x);
79 thisFrame.y = y;
80 thisFrame.w = w;
81 thisFrame.h = h;
82 thisFrame.cycle = k;
83
84
85 anim->frame = g_list_append(anim->frame, &thisFrame); // Prepend would be more performant but performance is irrelevant for sprite loading :)
86
87 #ifdef DEBUG
88 printf("j | state %s:%s, dir %s:%s | x %i:%i, y %i:%i, h %i:%i, w %i:%i, k %i:%i. | frame: %s\n",
89 ((ANNE_SPRITE_FRAME *) anim->frame->data)->state,state,
90 ((ANNE_SPRITE_FRAME *) anim->frame->data)->dir,dir,
91 ((ANNE_SPRITE_FRAME *) anim->frame->data)->x,x,
92 ((ANNE_SPRITE_FRAME *) anim->frame->data)->y,y,
93 ((ANNE_SPRITE_FRAME *) anim->frame->data)->h,h,
94 ((ANNE_SPRITE_FRAME *) anim->frame->data)->w,w,
95 ((ANNE_SPRITE_FRAME *) anim->frame->data)->cycle,k,
96 current_anim_frame);
97 #endif
98 }
99 }
100 }
This appears to work correctly, and the debug printout at the end would appear to indicate that all the data is being stored correctly. However, when I try to read that data out later: printf("frame | state: %s dir: %s cycle: %i x: %i y: %i w: %i h: %i\n", ((ANNE_SPRITE_FRAME *) search->data)->state, ((ANNE_SPRITE_FRAME *) search->data)->dir, ((ANNE_SPRITE_FRAME *) search->data)->cycle, ((ANNE_SPRITE_FRAME *) search->data)->x, ((ANNE_SPRITE_FRAME *) search->data)->y, ((ANNE_SPRITE_FRAME *) search->data)->w, ((ANNE_SPRITE_FRAME *) search->data)->h ); I get garbage data like this: 1frame | state: (Redacted) dir: right cycle: -3446<form action id="post_form" name="post_form" method="post" onsubmit="return validate_post();"><form xmlns="http://www.w3.org/1999/xhtml" action="" id="post_form" name="post_form" method="post" onsubmit="return validate_post();">
2<input type="hidden" name="forum_id" value="" />
3
4<table id="table-add-post-inner" width="800">
5<tbody>
6 <tr id="tr-topic">
7 <td class="label">Topic:</td>
8 <td>
9<input name="topic" type="hidden" value="Storing and reading sprite data from a linked list" />Storing and reading sprite data from a linked list </td>
10 </tr>
11 <tr id="tr-icon">
12 <td class="label">Icon:</td>
13 <td>
14 <div>
15 <input type="radio" name="icon" class="checkbox" tabindex="1" value="default.gif" checked="checked" /><img src="/forums/icons/default.gif" width="16" height="16" alt="default" />
16 <input type="radio" name="icon" class="checkbox" tabindex="1" value="c.gif" /><img src="/forums/icons/c.gif" width="16" height="16" alt="c" />
17 <input type="radio" name="icon" class="checkbox" tabindex="1" value="cpp.gif" /><img src="/forums/icons/cpp.gif" width="16" height="16" alt="c++" />
18 <input type="radio" name="icon" class="checkbox" tabindex="1" value="display.gif" /><img src="/forums/icons/display.gif" width="16" height="16" alt="display" />
19 <input type="radio" name="icon" class="checkbox" tabindex="1" value="joystick.gif" /><img src="/forums/icons/joystick.gif" width="16" height="16" alt="joystick" />
20 <input type="radio" name="icon" class="checkbox" tabindex="1" value="mad.gif" /><img src="/forums/icons/mad.gif" width="16" height="16" alt="mad" />
21 <input type="radio" name="icon" class="checkbox" tabindex="1" value="network.gif" /><img src="/forums/icons/network.gif" width="16" height="16" alt="network" />
22 <input type="radio" name="icon" class="checkbox" tabindex="1" value="note.gif" /><img src="/forums/icons/note.gif" width="16" height="16" alt="midi" />
23 <input type="radio" name="icon" class="checkbox" tabindex="1" value="question.gif" /><img src="/forums/icons/question.gif" width="16" height="16" alt="question" />
24 <input type="radio" name="icon" class="checkbox" tabindex="1" value="smile.gif" /><img src="/forums/icons/smile.gif" width="16" height="16" alt="smiley" />
25 <input type="radio" name="icon" class="checkbox" tabindex="1" value="speaker.gif" /><img src="/forums/icons/speaker.gif" width="16" height="16" alt="sound" />
26 </div>
27 </td>
28 </tr>
29 <tr id="tr-message">
30 <td width="100" valign="top" class="label">Message:</td>
31 <td width="700">
32
33<div id="post-988957-upload-button" class="upload-button" draggable="true" style="position: relative; overflow: hidden;">Drop Attachments Here<input multiple="multiple" style="opacity: 0; position: absolute; top: 0; left: 0px; width: 500px; height: 32px; background: transparent; border: none;" type="file" /></div>
34
35<div id="post-988957-files" class="upload-files">
36
37
38</div>
39
40<input id="btnPost" name="submit_button" tabindex="5" type="submit" class="button" value="Update Post" />
41
42<div class="mockup-box2"><div class="toolbar"><span class="button"><img src="/theme/default/icon/preview.png" /><span> Preview</span></span><span class="button"><img src="/theme/default/icon/help.png" /><span> Formatting Help</span></span></div><div class="container"><div class="compose" style="visibility: visible;"><textarea id="mub-body" class="mockup-box2" name="body" tabindex="2" rows="20" cols="50" style="height: 348px;"></textarea></div><div class="preview" style="visibility: hidden; display: block;"></div><input type="hidden" name="recovery_token" value="post-988957" /><input type="hidden" name="attachments" value="" /></div></div></td></tr></tbody></table></form>07570 x: 0 y: -532077906 w: -1434671328 h: 32604
43frame | state: (Redacted) dir: right cycle: -344607570 x: 0 y: -532077906 w: -1434671328 h: 32604
44frame | state: (Redacted) dir: right cycle: -344607570 x: 0 y: -532077906 w: -1434671328 h: 32604
My sanity check printf confirms that there are 17 frames in the frameset, as I expected, but I've been trying to confirm whether the junk output is due to a mistake saving the data or a mistake reading it since last night. If anyone could take a look, I'd really appreciate it. I would like to note that I'm aware of hashmaps, and in particular I'm considering rewriting in order to take advantage of Sparsehash. There are a couple reasons why I'm putting that off. Most importantly, I'm concerned about adding more code I don't understand, to replace a problem I've failed to diagnose. The flexibility of a linked list is also attractive and given the relatively small sets involved the performance penalty of iterating through them should be minimal. Edit again: It appears I'm an idiot who allocated the variables on the stack. |
|