karl2d_box2d.odin 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. // This example shows a stack of boxes and the player has a circle that can push the boxes.
  2. //
  3. // This example needs some cleaning up: It leaks lots of box2D things and can perhaps be done more
  4. // compactly. Originally made during a 1h stream: https://www.youtube.com/watch?v=LYW7jdwEnaI
  5. package karl2d_box2d_example
  6. import b2 "vendor:box2d"
  7. import k2 "../.."
  8. import "core:math"
  9. import "core:log"
  10. world_id: b2.WorldId
  11. time_acc: f32
  12. circle_body_id: b2.BodyId
  13. bodies: [dynamic]b2.BodyId
  14. GROUND :: k2.Rect {
  15. 0, 600,
  16. 1280, 120,
  17. }
  18. main :: proc() {
  19. context.logger = log.create_console_logger()
  20. init()
  21. run := true
  22. for run {
  23. run = step()
  24. }
  25. shutdown()
  26. }
  27. init :: proc() {
  28. k2.init(1280, 720, "Karl2D + Box2D example")
  29. b2.SetLengthUnitsPerMeter(40)
  30. world_def := b2.DefaultWorldDef()
  31. world_def.gravity = b2.Vec2{0, -900}
  32. world_id = b2.CreateWorld(world_def)
  33. ground_body_def := b2.DefaultBodyDef()
  34. ground_body_def.position = b2.Vec2{GROUND.x, -GROUND.y-GROUND.h}
  35. ground_body_id := b2.CreateBody(world_id, ground_body_def)
  36. ground_box := b2.MakeBox(GROUND.w, GROUND.h)
  37. ground_shape_def := b2.DefaultShapeDef()
  38. _ = b2.CreatePolygonShape(ground_body_id, ground_shape_def, ground_box)
  39. px: f32 = 400
  40. py: f32 = -400
  41. num_per_row := 10
  42. num_in_row := 0
  43. for _ in 0..<50 {
  44. b := create_box(world_id, {px, py})
  45. append(&bodies, b)
  46. num_in_row += 1
  47. if num_in_row == num_per_row {
  48. py += 30
  49. px = 200
  50. num_per_row -= 1
  51. num_in_row = 0
  52. }
  53. px += 30
  54. }
  55. body_def := b2.DefaultBodyDef()
  56. body_def.type = .dynamicBody
  57. body_def.position = b2.Vec2{0, 4}
  58. circle_body_id = b2.CreateBody(world_id, body_def)
  59. shape_def := b2.DefaultShapeDef()
  60. shape_def.density = 1000
  61. shape_def.material.friction = 0.3
  62. circle: b2.Circle
  63. circle.radius = 40
  64. _ = b2.CreateCircleShape(circle_body_id, shape_def, circle)
  65. }
  66. create_box :: proc(world_id: b2.WorldId, pos: b2.Vec2) -> b2.BodyId{
  67. body_def := b2.DefaultBodyDef()
  68. body_def.type = .dynamicBody
  69. body_def.position = pos
  70. body_id := b2.CreateBody(world_id, body_def)
  71. shape_def := b2.DefaultShapeDef()
  72. shape_def.density = 1
  73. shape_def.material.friction = 0.3
  74. box := b2.MakeBox(20, 20)
  75. box_def := b2.DefaultShapeDef()
  76. _ = b2.CreatePolygonShape(body_id, box_def, box)
  77. return body_id
  78. }
  79. step :: proc() -> bool {
  80. k2.new_frame()
  81. dt := k2.get_frame_time()
  82. time_acc += dt
  83. k2.process_events()
  84. k2.clear(k2.GRAY)
  85. k2.draw_rect(GROUND, k2.GREEN)
  86. pos := k2.get_mouse_position()
  87. b2.Body_SetTransform(circle_body_id, {pos.x, -pos.y}, {})
  88. SUB_STEPS :: 4
  89. TIME_STEP :: 1.0 / 60
  90. for time_acc >= TIME_STEP {
  91. b2.World_Step(world_id, TIME_STEP, SUB_STEPS)
  92. time_acc -= TIME_STEP
  93. }
  94. for b in bodies {
  95. position := b2.Body_GetPosition(b)
  96. r := b2.Body_GetRotation(b)
  97. a := math.atan2(r.s, r.c)
  98. // Y position is flipped because raylib has Y down and box2d has Y up.
  99. k2.draw_rect_ex({position.x, -position.y, 40, 40}, {20, 20}, a*(180/3.14), k2.RL_YELLOW)
  100. }
  101. k2.draw_circle(pos, 40, k2.RL_MAGENTA)
  102. k2.present()
  103. free_all(context.temp_allocator)
  104. return !k2.shutdown_wanted()
  105. }
  106. shutdown :: proc() {
  107. b2.DestroyWorld(world_id)
  108. k2.shutdown()
  109. }