![]() |
|
Create bitmap, expand the bitmap, suggestions. Cookies. |
OnlineCop
Member #7,919
October 2006
![]() |
I'm rewriting the game known as Chain Rxn flash game found on Facebook (http://apps.facebook.com/chainrxn/), or Boomshine on the "originator's" site (http://www.k2xl.com/games/boomshine/), and just have the early stages of the game up. Nothing fancy so far, and the code is more spaghetti than anything. I have everything, for now, in a single file if anyone can give me feedback. What I am trying to do right now is make the ball grow from the size that it IS (roughly 16x16 or 32x32 pixels) to about 10 times its size, stay that big for a bit, then shrink to nothingness. Total time that it will be stretched and shrunk before being "dead" for the rest of the round: 3-4 seconds. I could create another, larger, bitmap and reference that instead, using stretch_blit to either stretch up (from the smaller image) or stretch down (from the larger), though I don't know how that will affect the semi-transparent properties that each of these Ball objects will need. You can check out the flash counterparts to see what they need to try to look like when they "pop". Suggestions and feedback? I'll be either updating my original post with changes, or adding new posts with code as I make modifications! 1#include <allegro.h>
2#include <cmath>
3#include <iostream>
4#include <vector>
5
6
7/* Stolen from BZflag (BattleZone Capture the Flag game)'s 'common.h' file.
8 * I thought I'd be nice enough to at least credit them that I took the code
9 * from their files, though I'll probably redo this later before it gets
10 * officially released. We'll see. Proper headings and all that will follow
11 * if it does.
12 */
13
14/* (radians <--> degrees) conversion values */
15#define DEG2RAD 0.0174532925199432957692369076848861271344287189
16#define RAD2DEG 57.29577951308232087679815481410517033240547247
17#define DEG2RADf ((float)DEG2RAD)
18#define RAD2DEGf ((float)RAD2DEG)
19
20
21const float possible_angles[] =
22{
23 DEG2RADf * 30.0f, DEG2RADf * 45.0f, DEG2RADf * 60.0f, // Q1, top-right
24 DEG2RADf * 120.0f, DEG2RADf * 135.0f, DEG2RADf * 150.0f, // Q2, top-left
25 DEG2RADf * 210.0f, DEG2RADf * 225.0f, DEG2RADf * 240.0f, // Q3, bottom-left
26 DEG2RADf * 300.0f, DEG2RADf * 315.0f, DEG2RADf * 330.0f, // Q4, bottom-right
27};
28const unsigned NUM_ANGLES = sizeof(possible_angles) / sizeof(float);
29
30
31const unsigned MIN_SPEED = 1;
32const unsigned MAX_SPEED = 4;
33
34
35
36class Ball
37{
38public:
39 enum eState
40 {
41 STATE_MOVING = 0, // Kinda implemented
42 STATE_STOPPED, // Just barely implemented
43 STATE_DEAD // Not yet implemented, next on the the TODO
44 } state;
45
46 float x, y; // Will always be the CENTER of the ball, not the top-left corner
47 float angle; // Should be 30, 45, or 60
48 float velocity; // Slower typically makes levels HARDER, not EASIER
49 int color; // Uses an 'int' so it can include a transparency value
50 BITMAP* image; // Well, it has to be drawn as SOMETHING
51
52
53 Ball() :
54 state(STATE_MOVING),
55 x(0), y(0),
56 angle(possible_angles[0]),
57 velocity(0),
58 color(0),
59 image(NULL)
60 {
61 // Nothing to do
62 }
63
64
65 virtual ~Ball()
66 {
67 if (image)
68 {
69 destroy_bitmap(image);
70 image = NULL;
71 }
72 state = STATE_DEAD;
73 }
74
75
76 /* Must be created AFTER SCREEN_W and SCREEN_H are initialized */
77 void Init(unsigned size = 32)
78 {
79 image = create_bitmap(size, size);
80 clear_bitmap(image);
81 int temp = rand();
82 int color = makecol((temp >> 16) & 0xFF, (temp >> 8) & 0xFF, temp & 0xFF);
83
84 /* Sides and bottoms of circles look "sheared off" unless they have an
85 * odd number of pixels. This trims one pixel off the right and bottom
86 * edges automatically.
87 */
88 if (size % 2 == 0)
89 {
90 circlefill(image, size / 2, size / 2, (size / 2) - 1, color);
91 }
92 else
93 {
94 circlefill(image, size / 2, size / 2, size / 2, color);
95 }
96
97 /* Guarantee that none start right near the edge to prevent some odd
98 * errors we get with the bouncing math. To do this, give a buffer of
99 * about 32 around each edge initially.
100 */
101 x = (rand() % (SCREEN_W - 64)) + 32;
102 y = (rand() % (SCREEN_H - 64)) + 32;
103 angle = possible_angles[rand() % NUM_ANGLES];
104 velocity = rand() % (MAX_SPEED - MIN_SPEED) + MIN_SPEED;
105 }
106
107
108 /* TODO: These will all be semi-transparent, with fully transparent outer
109 * borders so you don't see them overlap as they cross each other.
110 */
111 void Draw(BITMAP* dest)
112 {
113 if (dest && image && state != STATE_DEAD)
114 {
115 blit(image, dest, 0, 0, x - image->w / 2, y - image->h / 2, image->w, image->h);
116 }
117 }
118
119
120 void Update(clock_t delta)
121 {
122 if (state == STATE_MOVING)
123 {
124 x += velocity * cos(angle) * delta;
125 y += velocity * sin(angle) * delta;
126
127 /* First handle horizontal corrections */
128 if ((x - image->w / 2 < 0) || (x + image->w / 2 > SCREEN_W))
129 {
130 velocity = -velocity;
131 angle = -angle;
132 }
133
134 /* Second handle vertical corrections */
135 if ((y - image->h / 2 < 0) || (y + image->h / 2 > SCREEN_H))
136 {
137 angle = -angle;
138 }
139 }
140 }
141
142
143 /* TODO: flesh out to actually grow to be a nice "explosion" for a few
144 * seconds, wait, then shrink rapidly then change state to STATE_DEAD.
145 */
146 void Pop()
147 {
148 if (state == STATE_MOVING)
149 {
150 state = STATE_STOPPED;
151 }
152 }
153
154
155 /* This will be removed completely; the real game will never have this,
156 * and it is only for temporary debugging.
157 */
158 void Unpop()
159 {
160 if (state == STATE_STOPPED)
161 {
162 state = STATE_MOVING;
163 }
164 }
165};
166
167
168
169///////////////////////////////////////////////////////////////////////////////
170
171volatile int ticks = 0;
172void ticker()
173{
174 ++ticks;
175} END_OF_FUNCTION(ticker)
176
177
178
179///////////////////////////////////////////////////////////////////////////////
180
181volatile int game_time = 0;
182void game_time_ticker()
183{
184 ++game_time;
185} END_OF_FUNCTION(game_time_ticker)
186
187
188const int updates_per_second = 60;
189
190
191
192///////////////////////////////////////////////////////////////////////////////
193
194int main(int argc, char** argv)
195{
196 unsigned int numBalls = 16;
197 if (argc == 2)
198 {
199 numBalls = atoi(argv[1]);
200 }
201
202 /* Double buffer, where everything is drawn before it's dumped to the screen */
203 BITMAP *screen_buffer = NULL;
204
205 int x = 0;
206 int y = 0;
207 int color = 0;
208
209 bool quit = false;
210
211 int fps = 0;
212 int frames_done = 0;
213 int old_time = 0;
214
215 int frames_array[10]; //an array to store the number of frames we did during the last 10 tenths of a second
216 int frame_index = 0; //used to store the index of the last updated value in the array
217 for (int ii = 0; ii < 10; ++ii)
218 {
219 frames_array[ii] = 0; //initialize the array to 0
220 }
221
222
223
224 srand(time(NULL));
225
226
227
228 allegro_init();
229 install_keyboard();
230 install_timer();
231
232 LOCK_VARIABLE(ticks);
233 LOCK_FUNCTION(ticker);
234 install_int_ex(ticker, BPS_TO_TIMER(updates_per_second));
235
236 LOCK_VARIABLE(game_time);
237 LOCK_FUNCTION(game_time_ticker);
238 install_int_ex(game_time_ticker, BPS_TO_TIMER(10)); //i.e. game time is in tenths of seconds
239
240
241 set_color_depth(16);
242 if (set_gfx_mode(GFX_AUTODETECT_WINDOWED, 800, 600, 0, 0) != 0)
243 {
244 set_gfx_mode(GFX_TEXT, 0, 0, 0, 0);
245 allegro_message("Unable to set any graphic mode\n%s\n", allegro_error);
246 return -1;
247 }
248
249
250 /* Create the arena: should be the same size as the window that the balls
251 * will use to bounce around in.
252 */
253 screen_buffer = create_bitmap(SCREEN_W, SCREEN_H);
254 clear_bitmap(screen_buffer);
255
256 x = SCREEN_W / 2;
257 y = SCREEN_H / 2;
258 color = makecol(255, 0, 0);
259
260
261 std::vector<Ball*> balls;
262 Ball* ball;
263 for (unsigned i = 0; i < numBalls; ++i)
264 {
265 ball = new Ball;
266 ball->Init(16);
267 balls.push_back(ball);
268 }
269
270
271
272 /* One ball, at random, will be able to be paused and unpaused when the
273 * SPACE and ENTER key are pressed, respectively. Just to see that the
274 * Pop() functionality is initially working like it should, and that the
275 * Ball object is properly changing states.
276 */
277 unsigned randomly_targeted_ball = rand() % numBalls;
278
279
280 while (!quit)
281 {
282 while (ticks == 0)
283 {
284 rest(100 / updates_per_second);
285 }
286
287
288 while (ticks > 0)
289 {
290 int old_ticks = ticks;
291
292 // Do logic start
293 // /*{*/
294
295 //DoLogic();
296 if (key[KEY_ESC])
297 {
298 quit = true;
299 }
300
301 if (key[KEY_SPACE])
302 {
303 balls[randomly_targeted_ball]->Pop();
304 }
305 if (key[KEY_ENTER])
306 {
307 balls[randomly_targeted_ball]->Unpop();
308 }
309
310 for (std::vector<Ball*>::iterator itr_b = balls.begin(); itr_b != balls.end(); ++itr_b)
311 {
312 Ball* ball = *itr_b;
313 if (ball)
314 {
315 ball->Update(ticks);
316 }
317 }
318
319 // /*}*/
320 // Do logic end
321
322 --ticks;
323
324 if (old_ticks <= ticks)
325 {
326 break;
327 }
328 }
329
330
331 if (game_time >= old_time + 1) // i.e. a 0.1 second has passed since we last counted the frames
332 {
333 fps -= frames_array[frame_index]; //decrement the fps by the frames done a second ago
334 frames_array[frame_index] = frames_done; //store the number of frames done this 0.1 second
335 fps += frames_done; //increment the fps by the newly done frames
336
337 frame_index = (frame_index + 1) % 10; //increment the frame index and snap it to 10
338
339 frames_done = 0;
340 old_time += 1;
341 }
342
343
344 // Draw everything start
345 // /*{*/
346
347 //DrawEverything();
348 for (std::vector<Ball*>::iterator itr_b = balls.begin(); itr_b != balls.end(); ++itr_b)
349 {
350 Ball* ball = *itr_b;
351 ball->Draw(screen_buffer);
352 }
353
354 /* Blit buffer to screen */
355 blit(screen_buffer, screen, 0, 0, (SCREEN_W - screen_buffer->w) / 2, (SCREEN_H - screen_buffer->h) / 2, screen_buffer->w, screen_buffer->h);
356
357 /* clears sprite buffer with color 0 */
358 clear_bitmap(screen_buffer);
359
360 // /*}*/
361 // Draw everything end
362
363 ++frames_done;
364 }
365
366
367 /* Free the memory for all allocated balls. This should happen at the end
368 * of every level, which is why I'm writing it (instead of having the end
369 * of the program clean up the memory for me).
370 */
371 for (std::vector<Ball*>::iterator itr_b = balls.begin(); itr_b != balls.end(); ++itr_b)
372 {
373 Ball* ball = *itr_b;
374 if (ball)
375 {
376 delete ball;
377 ball = NULL;
378 }
379 }
380
381
382 return 0;
383} END_OF_MAIN()
|
Arthur Kalliokoski
Second in Command
February 2005
![]() |
I'd say OpenGL would be easiest (allegrogl) They all watch too much MSNBC... they get ideas. |
Schyfis
Member #9,752
May 2008
![]() |
If you draw the balls as primitive circles (instead of a pre-created bitmap), you can easily change the size of them. ________________________________________________________________________________________________________ |
OnlineCop
Member #7,919
October 2006
![]() |
Arthur: I've used OpenGL but not allegrogl, so I'll take a look at it; it seems like the most logical approach, since I'd really rather have an arbitrary shape (say, for example, changing the shape from a sphere to a rotating triangle or even a "chain link" so I can get away with making a knock-off without stepping on anyone's copyright) and OpenGL is the best way to handle that. Schyfis: Would 'my_alpha_value' be black (you've no doubt seen the code, and may have seen that the surrounding color appears to be "black" around the outer edge of the balls) or a different value? Will I need it if I decide to try to use OpenGL as Arthur suggested?
|
Tobias Dammers
Member #2,604
August 2002
![]() |
OnlineCop said: I've used OpenGL but not allegrogl, In that case, you can treat allegrogl as a convenience library for setting up an OpenGL window in a cross-platform way, and adding allegro's input, sound, file, and what have you routines to it. All regular OpenGL commands are available in allegrogl, plus it loads extensions for you automatically. --- |
Schyfis
Member #9,752
May 2008
![]() |
OnlineCop said: Would 'my_alpha_value' be black I'm not sure what you mean. my_alpha_value is a value from 0 to 255, with 0 being fully transparent and 255 being fully opaque. ________________________________________________________________________________________________________ |
OnlineCop
Member #7,919
October 2006
![]() |
How's the best way to transition states over a period of time? First, the balls need to be bouncing around and ignore all collisions with everything EXCEPT balls whose states are non-STATE_MOVING (or STATE_DEAD). When a ball gets popped, it needs to grow for a short period of time, stay big, then shrink, and finally die. I thought that keyframes would be the best way to go with this. Until they actual get popped, there will be no keyframe (or, there will be a single keyframe whose value returns the default value or size of the ball). As soon as the ball collides with another popped ball, it adds four more keyframes: (max_size, time_now + 2 seconds) (max_size, time_now + 4 seconds) (min_size, time_now + 6 seconds) After 6 seconds, the ball dies. Of course, there will need to be some sort of method of dealing with a dead ball so it is no longer updated. Any ideas or thoughts on this? Should I be using some sort of Event manager instead to be handing the Pop event instead, or each of the different life cycles, rather than keyframes? What's the best way to do this part in your opinion(s)?
|
|