-
-
Save karl-zylinski/5ef25b68281b899acb1dd7774f035177 to your computer and use it in GitHub Desktop.
| // Odin + Box2D + Raylib example with stacking boxes and a shape attached to the cursor that can smack the shapes. | |
| // Made (mostly) during this stream: https://www.youtube.com/watch?v=LYW7jdwEnaI | |
| // I have updated this to use the `vendor:box2d` bindings instead of the ones I used on the stream. | |
| package game | |
| import b2 "vendor:box2d" | |
| import rl "vendor:raylib" | |
| create_box :: proc(world_id: b2.WorldId, pos: b2.Vec2) -> b2.BodyId{ | |
| body_def := b2.DefaultBodyDef() | |
| body_def.type = .dynamicBody | |
| body_def.position = pos | |
| body_id := b2.CreateBody(world_id, body_def) | |
| shape_def := b2.DefaultShapeDef() | |
| shape_def.density = 1 | |
| shape_def.friction = 0.3 | |
| box := b2.MakeBox(20, 20) | |
| box_def := b2.DefaultShapeDef() | |
| _ = b2.CreatePolygonShape(body_id, box_def, box) | |
| return body_id | |
| } | |
| main :: proc() { | |
| rl.InitWindow(1280, 720, "Box2D + Raylib example") | |
| world_def := b2.DefaultWorldDef() | |
| world_def.gravity = b2.Vec2{0, -1} | |
| world_id := b2.CreateWorld(world_def) | |
| defer b2.DestroyWorld(world_id) | |
| ground := rl.Rectangle { | |
| 0, 600, | |
| 1280, 120, | |
| } | |
| ground_body_def := b2.DefaultBodyDef() | |
| ground_body_def.position = b2.Vec2{ground.x, -ground.y-ground.height} | |
| ground_body_id := b2.CreateBody(world_id, ground_body_def) | |
| ground_box := b2.MakeBox(ground.width, ground.height) | |
| ground_shape_def := b2.DefaultShapeDef() | |
| _ = b2.CreatePolygonShape(ground_body_id, ground_shape_def, ground_box) | |
| bodies: [dynamic]b2.BodyId | |
| px: f32 = 400 | |
| py: f32 = -400 | |
| num_per_row := 10 | |
| num_in_row := 0 | |
| for _ in 0..<50 { | |
| b := create_box(world_id, {px, py}) | |
| append(&bodies, b) | |
| num_in_row += 1 | |
| if num_in_row == num_per_row { | |
| py += 30 | |
| px = 200 | |
| num_per_row -= 1 | |
| num_in_row = 0 | |
| } | |
| px += 30 | |
| } | |
| body_def := b2.DefaultBodyDef() | |
| body_def.type = .dynamicBody | |
| body_def.position = b2.Vec2{0, 4} | |
| body_id := b2.CreateBody(world_id, body_def) | |
| shape_def := b2.DefaultShapeDef() | |
| shape_def.density = 1000 | |
| shape_def.friction = 0.3 | |
| circle: b2.Circle | |
| circle.radius = 40 | |
| _ = b2.CreateCircleShape(body_id, shape_def, circle) | |
| time_step: f32 = 1.0 / 60 | |
| sub_steps: i32 = 4 | |
| for !rl.WindowShouldClose() { | |
| rl.BeginDrawing() | |
| rl.ClearBackground(rl.BLACK) | |
| rl.DrawRectangleRec(ground, rl.RED) | |
| mouse_pos := rl.GetMousePosition() | |
| b2.Body_SetTransform(body_id, {mouse_pos.x, -mouse_pos.y}, {}) | |
| b2.World_Step(world_id, time_step, sub_steps) | |
| for b in bodies { | |
| position := b2.Body_GetPosition(b) | |
| a := b2.Rot_GetAngle(b2.Body_GetRotation(b)) | |
| // Y position is flipped because raylib has Y down and box2d has Y up. | |
| rl.DrawRectanglePro({position.x, -position.y, 40, 40}, {20, 20}, a*(180/3.14), rl.YELLOW) | |
| } | |
| rl.DrawCircleV(mouse_pos, 40, rl.MAGENTA) | |
| rl.EndDrawing() | |
| } | |
| rl.CloseWindow() | |
| } |
Hi @cstrachan88! Your stuff looks very proper! Happy that the video inspired someone to try it themselves
Yeah! Your videos are great. I mostly bash things together with raylib for fun every once in a while, and your tutorials on Odin definitely helped a lot getting started. I thought it would be nice and a good excuse to try out Box2d.
Btw, I removed the axis flipping from my code. Everything is flipped when I reverse the y-axis, including text/textures/etc. I never noticed before since I almost always just use circles and squares.
Thank you!
Yeah the axis flipping in code of the rendering is a dangerous move :D I think perhaps somehow consistently interfacing with box2d and taking flip into account is the way to go, but I'm not sure yet.
Hello! Thanks for the example, I was trying it and got this:
Error: 'shape_def' of type 'ShapeDef' has no field 'friction'
shape_def.friction = 0.3
^~~~~~~~^
So I learned that ShapeDef no longer exposes friction directly as a field in this version.
The API moved friction into SurfaceMaterial.
But we can do this instead and it works:
shape_def := b2.DefaultShapeDef()
shape_def.density = 1
material := b2.DefaultSurfaceMaterial()
material.friction = 0.3
shape_def.material = material
Hey @karl-zylinski , I ended up following along with your video and adding my own spin here. I used my typical raylib game-loop setup. Thanks for the tutorial!
Also see here for how I flipped the raylib Y-axis.