raylib/box2d
Licence This example has its own licence, rather than Odin's: raylib/box2d/LICENSE
MIT License
Copyright (c) 2023 Erin Catto
The rest of the licence
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
Code
main.odin ¶134 linesSource
1package box2d
2
3import b2 "vendor:box2d"
4import rl "vendor:raylib"
5
6// Original: https://github.com/erincatto/box2d-raylib
7
8Entity :: struct {
9 body_id: b2.BodyId,
10 extent: b2.Vec2,
11 texture: rl.Texture,
12}
13
14draw_entity :: proc(entity: Entity) {
15 // The boxes were created centered on the bodies, but raylib draws textures starting at the top left corner.
16 // Body_GetWorldPoint gets the top left corner of the box accounting for rotation.
17 p := b2.Body_GetWorldPoint(entity.body_id, -entity.extent)
18 rotation := b2.Body_GetRotation(entity.body_id)
19 radians := b2.Rot_GetAngle(rotation)
20
21 rl.DrawTextureEx(entity.texture, p, rl.RAD2DEG * radians, 1., rl.WHITE)
22
23 // I used these circles to ensure the coordinates are correct
24 // rl.DrawCircleV(p, 5., rl.BLACK)
25 // p = b2.Body_GetWorldPoint(entity.body_id, 0)
26 // rl.DrawCircleV(p, 5., rl.BLUE)
27 // p = b2.Body_GetWorldPoint(entity.body_id, entity.extent)
28 // rl.DrawCircleV(p, 5., rl.RED)
29}
30
31GROUND_COUNT :: 14
32BOX_COUNT :: 10
33
34main :: proc() {
35 width := i32(1920)
36 height := i32(1080)
37 rl.InitWindow(width, height, "box2d-raylib")
38 defer rl.CloseWindow()
39
40 rl.SetTargetFPS(60)
41
42 // 128 pixels per meter is appropriate for this scene. The boxes are 128 pixels wide.
43 length_units_per_meter := f32(128.)
44 b2.SetLengthUnitsPerMeter(length_units_per_meter)
45
46 world_def := b2.DefaultWorldDef()
47
48 // Realistic gravity is achieved by multiplying gravity by the length unit.
49 world_def.gravity.y = 9.8 * length_units_per_meter
50 world_id := b2.CreateWorld(world_def)
51
52 ground_texture := rl.LoadTexture("ground.png")
53 defer rl.UnloadTexture(ground_texture)
54
55 box_texture := rl.LoadTexture("box.png")
56 defer rl.UnloadTexture(box_texture)
57
58 ground_extent := b2.Vec2{.5 * f32(ground_texture.width), .5 * f32(ground_texture.height)}
59 box_extent := b2.Vec2{.5 * f32(box_texture.width), .5 * f32(box_texture.height)}
60
61 // These polygons are centered on the origin and when they are added to a body they
62 // will be centered on the body position.
63 ground_polygon := b2.MakeBox(ground_extent.x, ground_extent.y)
64 box_polygon := b2.MakeBox(box_extent.x, box_extent.y)
65
66 ground_entities: [GROUND_COUNT]Entity
67 for &entity, i in ground_entities {
68 body_def := b2.DefaultBodyDef()
69 body_def.position = {(2. * f32(i) + 2.) * ground_extent.x, f32(height) - ground_extent.y - 100.}
70
71 // I used this rotation to test the world to screen transformation
72 // body_def.rotation = b2.MakeRot(.25 * b2.PI * f32(i))
73
74 entity.body_id = b2.CreateBody(world_id, body_def)
75 entity.extent = ground_extent
76 entity.texture = ground_texture
77 shape_def := b2.DefaultShapeDef()
78 _ = b2.CreatePolygonShape(entity.body_id, shape_def, &ground_polygon)
79 }
80
81 box_entities: [BOX_COUNT]Entity
82 box_index: int
83 for i in 1..=4 {
84 y := f32(height) - box_extent.y - 100. - (2.5 * f32(i) + 2.) * box_extent.y - 20.
85
86 for j in i..=4 {
87 x := .5 * f32(width) + (3. * f32(j) - f32(i) - 3.) * box_extent.x
88
89 body_def := b2.DefaultBodyDef()
90 body_def.type = .dynamicBody
91 body_def.position = {x, y}
92
93 entity := &box_entities[box_index]
94 entity.body_id = b2.CreateBody(world_id, body_def)
95 entity.texture = box_texture
96 entity.extent = box_extent
97 shape_def := b2.DefaultShapeDef()
98 _ = b2.CreatePolygonShape(entity.body_id, shape_def, &box_polygon)
99
100 box_index += 1
101 }
102 }
103 assert(box_index == BOX_COUNT)
104
105 pause: bool
106 for !rl.WindowShouldClose() {
107 if rl.IsKeyPressed(.P) {
108 pause = !pause
109 }
110
111 if !pause {
112 delta_time := rl.GetFrameTime()
113 b2.World_Step(world_id, delta_time, 4)
114 }
115
116 rl.BeginDrawing()
117 defer rl.EndDrawing()
118
119 rl.ClearBackground(rl.DARKGRAY)
120
121 message :: "Hello Box2D!"
122 font_size := i32(36)
123 text_width := rl.MeasureText(message, font_size)
124 rl.DrawText(message, (width - text_width) / 2, 50, font_size, rl.LIGHTGRAY)
125
126 for entity in ground_entities {
127 draw_entity(entity)
128 }
129
130 for entity in box_entities {
131 draw_entity(entity)
132 }
133 }
134}
Assets 2
Declarations Used 33
- vendor:box2d Body_GetRotation · Body_GetWorldPoint · BodyId · CreateBody · CreatePolygonShape · CreateWorld · DefaultBodyDef · DefaultShapeDef · DefaultWorldDef · MakeBox · Rot_GetAngle · SetLengthUnitsPerMeter · Vec2 · World_Step
- vendor:raylib BeginDrawing · ClearBackground · CloseWindow · DARKGRAY · DrawText · DrawTextureEx · EndDrawing · GetFrameTime · InitWindow · IsKeyPressed · LIGHTGRAY · LoadTexture · MeasureText · RAD2DEG · SetTargetFPS · Texture · UnloadTexture · WHITE · WindowShouldClose