![]() |
|
Allegro and Box2D |
Naturally
Member #12,748
April 2011
|
I have this code which is slightly modified from the Box2D HelloWorld solution to use Allegro and make the box fall down instead of up: Quote: /*
*
*/ #include <Box2D/Box2D.h> const float32 SCALE(30.0f); // Define the gravity vector. // Do we want to let bodies sleep? // Construct a world object, which will hold and simulate the rigid bodies. // Define the ground body. // Call the body factory which allocates memory for the ground body // Define the ground box shape. // The extents are the half-widths of the box. // Add the ground fixture to the ground body. // Define the dynamic body. We set its position and call the body factory. // Define another box shape for our dynamic body. // Define the dynamic body fixture. // Set the box density to be non-zero, so it will be dynamic. // Override the default friction. fixtureDef.restitution = 0.4f; // Prepare for simulation. Typically we use a time step of 1/60 of a al_init(); al_set_target_bitmap(box); // Clear applied body forces. We didn't apply any forces, but you // Now print the position and angle of the body. al_draw_bitmap(ground, groundPos.x * SCALE, groundPos.y * SCALE, 0); // When the world destructor is called, all bodies and joints are freed. This can return 0; I'm trying to learn Box2D, and so far my biggest/only problem is converting meters to pixels. I have a variable to says 30 pixels = 1 meter, but when I draw bitmaps to visually see the ground and the box in the Box2D HelloWorld code, it doesn't seem to draw right. The box falls through the top of the "ground" and lands on the bottom of it. The only way around it is to + 20 when I draw the y axis for the ground, or - 20 from the y axis when I draw the y axis for the falling box, or +10 to the y axis for the ground and -10 for the y axis for the falling box. I don't want to do this 'cause it makes things overly complicated for me especially if I use varying sizes for the ground and boxes. Plus when I look at other code all they do is multiply it by the scale to know where to draw it. It also makes me wonder if the x axis is even right, it's hard to know when I'm not 100% sure Allegro is drawing the bitmaps exactly where they would be in Box2D's world. Help me please Image: http://i.imgur.com/ISO7g.png |
Edgar Reynaldo
Major Reynaldo
May 2007
![]() |
I don't know Box2D, so I can't help you there. It would make your post much more readable if you edited it to use <code>code goes here...</code> tags though, and then you might get better responses. My Website! | EAGLE GUI Library Demos | My Deviant Art Gallery | Spiraloid Preview | A4 FontMaker | Skyline! (Missile Defense) Eagle and Allegro 5 binaries | Older Allegro 4 and 5 binaries | Allegro 5 compile guide |
cgman24
Member #12,536
February 2011
![]() |
Your code is very confusing-looking, so I made something similar from scratch. Hopefully it will help clear up some points for you. I tried to demonstrate some other things as well. 1
2#include <Box2D/Box2D.h>
3#include <allegro5/allegro.h>
4#include <cstdio>
5
6
7const int SCREEN_W = 640;
8const int SCREEN_H = 480;
9//The scale. 32 is a better number than 30, because almost all screen resolution dimensions are a multiple of 32.
10const int PIX_METER = 32;
11const int FPS = 60;
12int main(int argc, char** argv)
13{
14 B2_NOT_USED(argc);
15 B2_NOT_USED(argv);
16
17 b2Vec2 gravity(0.0f, 10.0f);
18 bool doSleep = true;
19 b2World world(gravity, doSleep);
20
21 // Define the ground body.
22 b2BodyDef groundBodyDef;
23 //Box2D positions are the center.
24 //Put it in the middle: 10.0f, 7.5f
25 groundBodyDef.position.Set((float)(SCREEN_W/2)/PIX_METER, (float)(SCREEN_H/2)/PIX_METER);
26
27 b2Body* groundBody = world.CreateBody(&groundBodyDef);
28 b2PolygonShape groundBox;
29
30 // The extents are the half-widths of the box.
31 //I chose these numbers arbitrarily
32 float g_width = 6.0f;
33 float g_height = 2.4f;
34 groundBox.SetAsBox(g_width/2, g_height/2);
35
36 // Add the ground fixture to the ground body.
37 groundBody->CreateFixture(&groundBox, 0.0f);
38
39 // Define the dynamic body. We set its position and call the body factory.
40 b2BodyDef bodyDef;
41 bodyDef.type = b2_dynamicBody;
42 bodyDef.position.Set((float)(SCREEN_W/2)/PIX_METER, 0.0f); //top of the screen
43 b2Body* body = world.CreateBody(&bodyDef);
44
45 // Define another box shape for our dynamic body.
46 b2PolygonShape dynamicBox;
47 float d_width = 2.0f;
48 float d_height = 2.0f;
49 dynamicBox.SetAsBox(d_width/2, d_height/2);
50
51 b2FixtureDef fixtureDef;
52 fixtureDef.shape = &dynamicBox;
53 fixtureDef.density = 1.0f;
54 fixtureDef.friction = 0.3f;
55 body->CreateFixture(&fixtureDef);
56
57 //give the body some spin and some motion to make it interesting
58 body->SetAngularVelocity(0.8f);
59 b2Vec2 initial_v (1.6f, 0.0f);
60 body->SetLinearVelocity(initial_v);
61
62 // Prepare for simulation. Typically we use a time step of 1/60 of a
63 // second (60Hz) and 10 iterations. This provides a high quality simulation
64 // in most game scenarios.
65 float32 timeStep = 1.0f / FPS;
66 int32 velocityIterations = 10;
67 int32 positionIterations = 10;
68
69 //prepare for drawing
70 ALLEGRO_DISPLAY *display = NULL;
71 ALLEGRO_EVENT_QUEUE *event_queue = NULL;
72 ALLEGRO_TIMER *timer = NULL;
73 ALLEGRO_BITMAP *ground = NULL;
74 ALLEGRO_BITMAP *box = NULL;
75 bool redraw = true;
76 //ALWAYS check return values of these Allegro functions. It will save you headaches later.
77 if(!al_init()) {
78 fprintf(stderr, "failed to initialize allegro!\n");
79 return -1;
80 }
81 timer = al_create_timer(1.0 / FPS);
82 if(!timer) {
83 fprintf(stderr, "failed to create timer!\n");
84 return -1;
85 }
86
87 display = al_create_display(SCREEN_W, SCREEN_H);
88 if(!display) {
89 fprintf(stderr, "failed to create display!\n");
90 al_destroy_timer(timer);
91 return -1;
92 }
93 //typically, if using Box2D, you will have everything operating with Box2D coordinates throughout your game.
94 //This is because Box2D methods return in Box2D coordinates.
95 //Then, when drawing, convert them to "Allegro coordinates" using the scale.
96 //Here, the g_ variables are in Box2D coordinates, so we convert them to Allegro coordinates to represent the box on the screen.
97 ground = al_create_bitmap(g_width*PIX_METER, g_height*PIX_METER);
98 if(!ground) {
99 fprintf(stderr, "failed to create ground bitmap!\n");
100 al_destroy_display(display);
101 al_destroy_timer(timer);
102 return -1;
103 }
104 box = al_create_bitmap(d_width*PIX_METER, d_height*PIX_METER);
105 if(!box) {
106 fprintf(stderr, "failed to create box bitmap!\n");
107 al_destroy_bitmap(ground);
108 al_destroy_display(display);
109 al_destroy_timer(timer);
110 return -1;
111 }
112
113 al_set_target_bitmap(ground);
114 al_clear_to_color(al_map_rgb(255, 0, 255));
115 al_set_target_bitmap(box);
116 al_clear_to_color(al_map_rgb(128, 128, 255));
117
118 al_set_target_bitmap(al_get_backbuffer(display));
119
120 event_queue = al_create_event_queue();
121 if(!event_queue) {
122 fprintf(stderr, "failed to create event_queue!\n");
123 al_destroy_bitmap(ground);
124 al_destroy_bitmap(box);
125 al_destroy_display(display);
126 al_destroy_timer(timer);
127 return -1;
128 }
129
130 al_register_event_source(event_queue, al_get_display_event_source(display));
131 al_register_event_source(event_queue, al_get_timer_event_source(timer));
132 al_clear_to_color(al_map_rgb(0,0,0));
133 al_flip_display();
134 al_start_timer(timer);
135 // This is our little game loop.
136 while (1)
137 {
138 ALLEGRO_EVENT ev;
139 al_wait_for_event(event_queue, &ev);
140
141 if(ev.type == ALLEGRO_EVENT_TIMER) {
142 world.Step(timeStep, velocityIterations, positionIterations);
143 world.ClearForces();
144 redraw = true;
145 }
146 else if(ev.type == ALLEGRO_EVENT_DISPLAY_CLOSE) {
147 break;
148 }
149
150 if (redraw && al_is_event_queue_empty(event_queue)) {
151 redraw = false;
152 al_clear_to_color(al_map_rgb(0,0,0));
153
154 //draw the ground
155 //note that drawing is from the top-left corner,
156 //and NOT the center as it is in Box2D.
157 b2Vec2 g_pos = groundBody->GetPosition(); //the center
158 //we need to get the top left corner from this center
159 float g_x = g_pos.x - g_width/2;
160 float g_y = g_pos.y - g_height/2;
161 //now convert the coordinates and draw
162 al_draw_bitmap(ground, g_x*PIX_METER, g_y*PIX_METER, 0);
163
164 //do the same for the other box
165 b2Vec2 b_pos = body->GetPosition();
166 float32 angle = body->GetAngle();
167 //When using the rotated drawing function, the center is pinned to a point.
168 //so essentially, we can draw from the center.
169 float b_x = b_pos.x;
170 float b_y = b_pos.y;
171
172 float midx = al_get_bitmap_width(box)/2;
173 float midy = al_get_bitmap_height(box)/2;
174
175 al_draw_rotated_bitmap(box, midx, midy, b_x*PIX_METER, b_y*PIX_METER, angle, 0);
176
177 al_flip_display();
178 }
179
180 }
181
182 // When the world destructor is called, all bodies and joints are freed. This can
183 // create orphaned pointers, so be careful about your world management.
184
185 return 0;
186}
Basically, you have two coordinate systems: Box2D and Allegro/Drawing. Box2D is in meters, and Allegro is in pixels. Throughout your game logic, use Box2D coordinates. This is easier because all Box2D methods return in Box2D coordinates (of course). Then, when you draw, you convert to Allegro coordinates using a scaling factor. Here, I set PIX_METER (should probably be PIXELS_PER_METER but I'm too lazy to type all that out) to 32, and use that when drawing. By doing it this way, you can easily change the scale, or do something like a zoom-in/out feature. You just have to keep track of which coordinate system each value is in (you could even prefix them with b2_ or a_ if you wanted. That's probably a good idea, actually). Hope that helps. -cgman
|
Slartibartfast
Member #8,789
June 2007
![]() |
Just skimming, I'm guessing the problem is that Box2D coordinates for bodies give the center of the body, whereas drawing with allegro you specify the corner of the image. ---- |
Neil Walker
Member #210
April 2000
![]() |
The position is indeed the centre point of a shape (e.g. see SetAsBox function). Box2D works best if you think in metres as pixels doesn't make sense in a physics based system. It's entirely up to you where you set your screen origin (most people have centre 0,0 in the middle of the screen), but all you have to do is create a scale and apply that to every object to get a pixel location. In my little programs I made life a little simpler and moved 0 to the edge, e.g. I pretended my player sprite was 1m tall and 0.5m wide and used that as a base for every other object. Regarding up and down, you've probably noticed that it's opposite in the y axis, i.e. increase y to go down the screen in Allegro but increase y to go up in Box2D. This is the same for opengl, etc. Just reverse your y axis. Neil. wii:0356-1384-6687-2022, kart:3308-4806-6002. XBOX:chucklepie |
Naturally
Member #12,748
April 2011
|
Thanks so much! I didn't know Box2D was giving me center coordinates >_< This fixed it: al_draw_bitmap(ground, (groundPos.x * SCALE) - (al_get_bitmap_width(ground) / 2.0f), (groundPos.y * SCALE) - (al_get_bitmap_height(ground) / 2.0f), 0); al_draw_bitmap(fallingBox, (position.x * SCALE) - (al_get_bitmap_width(fallingBox) / 2.0f), (position.y * SCALE) - (al_get_bitmap_height(fallingBox) / 2.0f), 0); Thanks again! xD Edit: Thanks to cgman24 too (Forgot to highlight your name in the credit thing) xD Finished Code for anyone in future that ever needs help like this (Some numbers changed a little from first post): 1/*
2* Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com
3*
4* This software is provided 'as-is', without any express or implied
5* warranty. In no event will the authors be held liable for any damages
6* arising from the use of this software.
7* Permission is granted to anyone to use this software for any purpose,
8* including commercial applications, and to alter it and redistribute it
9* freely, subject to the following restrictions:
10* 1. The origin of this software must not be misrepresented; you must not
11* claim that you wrote the original software. If you use this software
12* in a product, an acknowledgment in the product documentation would be
13* appreciated but is not required.
14* 2. Altered source versions must be plainly marked as such, and must not be
15* misrepresented as being the original software.
16* 3. This notice may not be removed or altered from any source distribution.
17*/
18
19#include <Box2D/Box2D.h>
20#include <allegro5\allegro.h>
21#include <allegro5\allegro_image.h>
22#include <cstdio>
23
24const float32 SCALE(30.0f);
25const int HEIGHT(480);
26const int WIDTH(640);
27// This is a simple example of building and running a simulation
28// using Box2D. Here we create a large ground box and a small dynamic
29// box.
30// There are no graphics for this example. Box2D is meant to be used
31// with your rendering engine in your game engine.
32int main(int argc, char** argv)
33{
34 B2_NOT_USED(argc);
35 B2_NOT_USED(argv);
36
37 // Define the gravity vector.
38 b2Vec2 gravity(0.0f, 10.0f);
39
40 // Do we want to let bodies sleep?
41 bool doSleep = true;
42
43 // Construct a world object, which will hold and simulate the rigid bodies.
44 b2World world(gravity, doSleep);
45
46 // Define the ground body.
47 b2BodyDef groundBodyDef;
48 groundBodyDef.position.Set(200.0f / SCALE, 420.0f / SCALE);
49
50 // Call the body factory which allocates memory for the ground body
51 // from a pool and creates the ground box shape (also from a pool).
52 // The body is also added to the world.
53 b2Body* groundBody = world.CreateBody(&groundBodyDef);
54
55 // Define the ground box shape.
56 b2PolygonShape groundBox;
57
58 // The extents are the half-widths of the box.
59 groundBox.SetAsBox(50.0f / SCALE, 10.0f / SCALE);
60
61 // Add the ground fixture to the ground body.
62 groundBody->CreateFixture(&groundBox, 0.0f);
63
64 // Define the dynamic body. We set its position and call the body factory.
65 b2BodyDef bodyDef;
66 bodyDef.type = b2_dynamicBody;
67 bodyDef.position.Set(255.5f / SCALE, 350.0f / SCALE);
68 b2Body* body = world.CreateBody(&bodyDef);
69
70 // Define another box shape for our dynamic body.
71 b2PolygonShape dynamicBox;
72 dynamicBox.SetAsBox(15.0f / SCALE, 15.0f / SCALE);
73
74 // Define the dynamic body fixture.
75 b2FixtureDef fixtureDef;
76 fixtureDef.shape = &dynamicBox;
77
78 // Set the box density to be non-zero, so it will be dynamic.
79 fixtureDef.density = 1.0f;
80
81 // Override the default friction.
82 fixtureDef.friction = 0.3f;
83
84 //fixtureDef.restitution = 0.4f;
85 // Add the shape to the body.
86 body->CreateFixture(&fixtureDef);
87
88 // Prepare for simulation. Typically we use a time step of 1/60 of a
89 // second (60Hz) and 10 iterations. This provides a high quality simulation
90 // in most game scenarios.
91 float32 timeStep = 1.0f / 60.0f;
92 int32 velocityIterations = 6;
93 int32 positionIterations = 2;
94
95
96 al_init();
97 al_init_image_addon();
98 ALLEGRO_DISPLAY *display(al_create_display(WIDTH, HEIGHT));
99 //ALLEGRO_BITMAP *ground(al_create_bitmap((50.0f / SCALE) * 2 * SCALE, (10.0f / SCALE) * 2 * SCALE));
100 ALLEGRO_BITMAP *ground(al_create_bitmap(100, 20));
101 al_set_target_bitmap(ground);
102 al_clear_to_color(al_map_rgb(255,255,255));
103 //ALLEGRO_BITMAP *box(al_create_bitmap((10.0f / SCALE) * 2 * SCALE, (10.0f / SCALE) * 2 * SCALE));
104 ALLEGRO_BITMAP *fallingBox(al_create_bitmap(30, 30));
105
106 al_set_target_bitmap(fallingBox);
107 al_clear_to_color(al_map_rgb(255, 0, 255));
108 al_set_target_bitmap(al_get_backbuffer(display));
109 al_clear_to_color(al_map_rgb(0,0,0));
110 al_flip_display();
111 // This is our little game loop.
112 for (int32 i = 0; true; ++i)
113 {
114 al_clear_to_color(al_map_rgb(0,0,0));
115 // Instruct the world to perform a single step of simulation.
116 // It is generally best to keep the time step and iterations fixed.
117 world.Step(timeStep, velocityIterations, positionIterations);
118
119 // Clear applied body forces. We didn't apply any forces, but you
120 // should know about this function.
121 world.ClearForces();
122
123 // Now print the position and angle of the body.
124 b2Vec2 position = body->GetPosition();
125 b2Vec2 groundPos = groundBody->GetPosition();
126 float32 angle = body->GetAngle();
127
128 al_draw_bitmap(ground, (groundPos.x * SCALE) - (al_get_bitmap_width(ground) / 2.0f), (groundPos.y * SCALE) - (al_get_bitmap_height(ground) / 2.0f), 0);
129 //al_draw_bitmap(box, position.x * SCALE , position.y * SCALE - 20, 0);
130 al_draw_bitmap(fallingBox, (position.x * SCALE) - (al_get_bitmap_width(fallingBox) / 2.0f), (position.y * SCALE) - (al_get_bitmap_height(fallingBox) / 2.0f), 0);
131 al_flip_display();
132 al_rest(1.0 / 5.0);
133 printf("%4.2f %4.2f %4.2f\n", position.x, position.y, angle);
134 }
135
136 // When the world destructor is called, all bodies and joints are freed. This can
137 // create orphaned pointers, so be careful about your world management.
138
139 return 0;
140}
|
Neil Walker
Member #210
April 2000
![]() |
If you check out the Box2D forums there are quite a few add-ons people have created. The two of note are buoyancy and 'mario' platforums (i.e. jump up through but not down). Neil. wii:0356-1384-6687-2022, kart:3308-4806-6002. XBOX:chucklepie |
|