test_one_way_collision.gd 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498
  1. extends Test
  2. tool
  3. signal all_tests_done()
  4. signal test_done()
  5. const OPTION_OBJECT_TYPE_RIGIDBODY = "Object type/Rigid body (1)"
  6. const OPTION_OBJECT_TYPE_KINEMATIC = "Object type/Kinematic body (2)"
  7. const OPTION_TEST_CASE_ALL = "Test Cases/TEST ALL (0)"
  8. const OPTION_TEST_CASE_ALL_RIGID = "Test Cases/All Rigid Body tests"
  9. const OPTION_TEST_CASE_ALL_KINEMATIC = "Test Cases/All Kinematic Body tests"
  10. const OPTION_TEST_CASE_ALL_ANGLES_RIGID = "Test Cases/Around the clock (Rigid Body)"
  11. const OPTION_TEST_CASE_ALL_ANGLES_KINEMATIC = "Test Cases/Around the clock (Kinematic Body)"
  12. const OPTION_TEST_CASE_MOVING_PLATFORM_RIGID = "Test Cases/Moving Platform (Rigid Body)"
  13. const OPTION_TEST_CASE_MOVING_PLATFORM_KINEMATIC = "Test Cases/Moving Platform (Kinematic Body)"
  14. const TEST_ALL_ANGLES_STEP = 15.0
  15. const TEST_ALL_ANGLES_MAX = 344.0
  16. export(float, 32, 128, 0.1) var _platform_size = 64.0 setget _set_platform_size
  17. export(float, 0, 360, 0.1) var _platform_angle = 0.0 setget _set_platform_angle
  18. export(float) var _platform_speed = 0.0
  19. export(float, 0, 360, 0.1) var _body_angle = 0.0 setget _set_rigidbody_angle
  20. export(Vector2) var _body_velocity = Vector2(400.0, 0.0)
  21. export(bool) var _use_kinematic_body = false
  22. onready var options = $Options
  23. var _rigid_body_template = null
  24. var _kinematic_body_template = null
  25. var _moving_body = null
  26. var _platform_template = null
  27. var _platform_body = null
  28. var _platform_velocity = Vector2.ZERO
  29. var _contact_detected = false
  30. var _target_entered = false
  31. var _test_passed = false
  32. var _test_step = 0
  33. var _test_all_angles = false
  34. var _lock_controls = false
  35. var _test_canceled = false
  36. func _ready():
  37. if not Engine.editor_hint:
  38. options.add_menu_item(OPTION_OBJECT_TYPE_RIGIDBODY, true, not _use_kinematic_body, true)
  39. options.add_menu_item(OPTION_OBJECT_TYPE_KINEMATIC, true, _use_kinematic_body, true)
  40. options.add_menu_item(OPTION_TEST_CASE_ALL)
  41. options.add_menu_item(OPTION_TEST_CASE_ALL_RIGID)
  42. options.add_menu_item(OPTION_TEST_CASE_ALL_KINEMATIC)
  43. options.add_menu_item(OPTION_TEST_CASE_ALL_ANGLES_RIGID)
  44. options.add_menu_item(OPTION_TEST_CASE_ALL_ANGLES_KINEMATIC)
  45. options.add_menu_item(OPTION_TEST_CASE_MOVING_PLATFORM_RIGID)
  46. options.add_menu_item(OPTION_TEST_CASE_MOVING_PLATFORM_KINEMATIC)
  47. options.connect("option_selected", self, "_on_option_selected")
  48. $Controls/PlatformSize/HSlider.value = _platform_size
  49. $Controls/PlatformAngle/HSlider.value = _platform_angle
  50. $Controls/BodyAngle/HSlider.value = _body_angle
  51. $TargetArea2D.connect("body_entered", self, "_on_target_entered")
  52. $Timer.connect("timeout", self, "_on_timeout")
  53. _rigid_body_template = $RigidBody2D
  54. remove_child(_rigid_body_template)
  55. _kinematic_body_template = $KinematicBody2D
  56. remove_child(_kinematic_body_template)
  57. _platform_template = $OneWayKinematicBody2D
  58. remove_child(_platform_template)
  59. _start_test()
  60. func _process(_delta):
  61. if not Engine.editor_hint:
  62. if Input.is_action_just_pressed("ui_accept"):
  63. _reset_test(false)
  64. func _physics_process(delta):
  65. if not Engine.editor_hint:
  66. if _moving_body and not _contact_detected:
  67. if _use_kinematic_body:
  68. var collision = _moving_body.move_and_collide(_body_velocity * delta, false)
  69. if collision:
  70. var colliding_body = collision.collider
  71. _on_contact_detected(colliding_body)
  72. if _platform_body and _platform_velocity != Vector2.ZERO:
  73. var motion = _platform_velocity * delta
  74. _platform_body.global_position += motion
  75. func _input(event):
  76. var key_event = event as InputEventKey
  77. if key_event and not key_event.pressed:
  78. if key_event.scancode == KEY_0:
  79. _on_option_selected(OPTION_TEST_CASE_ALL)
  80. if key_event.scancode == KEY_1:
  81. _on_option_selected(OPTION_OBJECT_TYPE_RIGIDBODY)
  82. elif key_event.scancode == KEY_2:
  83. _on_option_selected(OPTION_OBJECT_TYPE_KINEMATIC)
  84. func _exit_tree():
  85. if not Engine.editor_hint:
  86. _rigid_body_template.free()
  87. _kinematic_body_template.free()
  88. _platform_template.free()
  89. func _set_platform_size(value, reset = true):
  90. if _lock_controls:
  91. return
  92. if value == _platform_size:
  93. return
  94. _platform_size = value
  95. if is_inside_tree():
  96. if Engine.editor_hint:
  97. $OneWayKinematicBody2D/CollisionShape2D.shape.extents.x = value
  98. else:
  99. var platform_collision = _platform_template.get_child(0)
  100. platform_collision.shape.extents.x = value
  101. if _platform_body:
  102. # Bug: need to re-add when changing shape.
  103. var child_index = _platform_body.get_index()
  104. remove_child(_platform_body)
  105. add_child(_platform_body)
  106. move_child(_platform_body, child_index)
  107. if reset:
  108. _reset_test()
  109. func _set_platform_angle(value, reset = true):
  110. if _lock_controls:
  111. return
  112. if value == _platform_angle:
  113. return
  114. _platform_angle = value
  115. if is_inside_tree():
  116. if Engine.editor_hint:
  117. $OneWayKinematicBody2D.rotation = deg2rad(value)
  118. else:
  119. if _platform_body:
  120. _platform_body.rotation = deg2rad(value)
  121. _platform_template.rotation = deg2rad(value)
  122. if reset:
  123. _reset_test()
  124. func _set_rigidbody_angle(value, reset = true):
  125. if _lock_controls:
  126. return
  127. if value == _body_angle:
  128. return
  129. _body_angle = value
  130. if is_inside_tree():
  131. if Engine.editor_hint:
  132. $RigidBody2D.rotation = deg2rad(value)
  133. $KinematicBody2D.rotation = deg2rad(value)
  134. else:
  135. if _moving_body:
  136. _moving_body.rotation = deg2rad(value)
  137. _rigid_body_template.rotation = deg2rad(value)
  138. _kinematic_body_template.rotation = deg2rad(value)
  139. if reset:
  140. _reset_test()
  141. func _on_option_selected(option):
  142. match option:
  143. OPTION_OBJECT_TYPE_KINEMATIC:
  144. _use_kinematic_body = true
  145. _reset_test()
  146. OPTION_OBJECT_TYPE_RIGIDBODY:
  147. _use_kinematic_body = false
  148. _reset_test()
  149. OPTION_TEST_CASE_ALL:
  150. _test_all()
  151. OPTION_TEST_CASE_ALL_RIGID:
  152. _test_all_rigid_body()
  153. OPTION_TEST_CASE_ALL_KINEMATIC:
  154. _test_all_kinematic_body()
  155. OPTION_TEST_CASE_ALL_ANGLES_RIGID:
  156. _use_kinematic_body = false
  157. _test_all_angles = true
  158. _reset_test(false)
  159. OPTION_TEST_CASE_ALL_ANGLES_KINEMATIC:
  160. _use_kinematic_body = true
  161. _test_all_angles = true
  162. _reset_test(false)
  163. OPTION_TEST_CASE_MOVING_PLATFORM_RIGID:
  164. _use_kinematic_body = false
  165. _test_moving_platform()
  166. OPTION_TEST_CASE_MOVING_PLATFORM_KINEMATIC:
  167. _use_kinematic_body = true
  168. _test_moving_platform()
  169. func _start_test_case(option):
  170. Log.print_log("* Starting " + option)
  171. _on_option_selected(option)
  172. yield(self, "all_tests_done")
  173. func _wait_for_test():
  174. _reset_test()
  175. yield(self, "test_done")
  176. func _test_all_rigid_body():
  177. Log.print_log("* All RigidBody test cases...")
  178. _set_platform_size(64.0, false)
  179. _set_rigidbody_angle(0.0, false)
  180. yield(_start_test_case(OPTION_TEST_CASE_ALL_ANGLES_RIGID), "completed")
  181. if _test_canceled:
  182. return
  183. _set_platform_size(64.0, false)
  184. _set_rigidbody_angle(45.0, false)
  185. yield(_start_test_case(OPTION_TEST_CASE_ALL_ANGLES_RIGID), "completed")
  186. if _test_canceled:
  187. return
  188. _set_platform_size(32.0, false)
  189. _set_rigidbody_angle(45.0, false)
  190. yield(_start_test_case(OPTION_TEST_CASE_ALL_ANGLES_RIGID), "completed")
  191. if _test_canceled:
  192. return
  193. yield(_start_test_case(OPTION_TEST_CASE_MOVING_PLATFORM_RIGID), "completed")
  194. if _test_canceled:
  195. return
  196. func _test_all_kinematic_body():
  197. Log.print_log("* All KinematicBody test cases...")
  198. _set_platform_size(64.0, false)
  199. _set_rigidbody_angle(0.0, false)
  200. yield(_start_test_case(OPTION_TEST_CASE_ALL_ANGLES_KINEMATIC), "completed")
  201. if _test_canceled:
  202. return
  203. _set_platform_size(64.0, false)
  204. _set_rigidbody_angle(45.0, false)
  205. yield(_start_test_case(OPTION_TEST_CASE_ALL_ANGLES_KINEMATIC), "completed")
  206. if _test_canceled:
  207. return
  208. _set_platform_size(32.0, false)
  209. _set_rigidbody_angle(45.0, false)
  210. yield(_start_test_case(OPTION_TEST_CASE_ALL_ANGLES_KINEMATIC), "completed")
  211. if _test_canceled:
  212. return
  213. yield(_start_test_case(OPTION_TEST_CASE_MOVING_PLATFORM_KINEMATIC), "completed")
  214. if _test_canceled:
  215. return
  216. func _test_moving_platform():
  217. Log.print_log("* Start moving platform tests")
  218. Log.print_log("* Platform moving away from body...")
  219. _set_platform_size(64.0, false)
  220. _set_rigidbody_angle(0.0, false)
  221. _platform_speed = 50.0
  222. _set_platform_angle(90.0, false)
  223. yield(_wait_for_test(), "completed")
  224. if _test_canceled:
  225. return
  226. _set_platform_angle(-90.0, false)
  227. yield(_wait_for_test(), "completed")
  228. if _test_canceled:
  229. return
  230. Log.print_log("* Platform moving towards body...")
  231. _set_platform_size(64.0, false)
  232. _set_rigidbody_angle(0.0, false)
  233. _platform_speed = -50.0
  234. _set_platform_angle(90.0, false)
  235. yield(_wait_for_test(), "completed")
  236. if _test_canceled:
  237. return
  238. _set_platform_angle(-90.0, false)
  239. yield(_wait_for_test(), "completed")
  240. if _test_canceled:
  241. return
  242. _platform_speed = 0.0
  243. emit_signal("all_tests_done")
  244. func _test_all():
  245. Log.print_log("* TESTING ALL...")
  246. yield(_test_all_rigid_body(), "completed")
  247. if _test_canceled:
  248. return
  249. yield(_test_all_kinematic_body(), "completed")
  250. if _test_canceled:
  251. return
  252. Log.print_log("* Done.")
  253. func _start_test():
  254. var test_label = "Testing: "
  255. var platform_angle = _platform_template.rotation
  256. if _platform_body:
  257. platform_angle = _platform_body.rotation
  258. remove_child(_platform_body)
  259. _platform_body.queue_free()
  260. _platform_body = null
  261. _platform_body = _platform_template.duplicate()
  262. _platform_body.rotation = platform_angle
  263. add_child(_platform_body)
  264. if _use_kinematic_body:
  265. test_label += _kinematic_body_template.name
  266. _moving_body = _kinematic_body_template.duplicate()
  267. else:
  268. test_label += _rigid_body_template.name
  269. _moving_body = _rigid_body_template.duplicate()
  270. _moving_body.linear_velocity = _body_velocity
  271. _moving_body.connect("body_entered", self, "_on_contact_detected")
  272. add_child(_moving_body)
  273. if _platform_speed != 0.0:
  274. var platform_pos = _platform_body.global_position
  275. var body_pos = _moving_body.global_position
  276. var dir = (platform_pos - body_pos).normalized()
  277. _platform_velocity = dir * _platform_speed
  278. else:
  279. _platform_velocity = Vector2.ZERO
  280. if _test_all_angles:
  281. test_label += " - All angles"
  282. $LabelTestType.text = test_label
  283. _contact_detected = false
  284. _target_entered = false
  285. _test_passed = false
  286. _test_step += 1
  287. $Timer.start()
  288. $LabelResult.text = "..."
  289. $LabelResult.self_modulate = Color.white
  290. func _reset_test(cancel_test = true):
  291. _test_canceled = true
  292. _on_timeout()
  293. _test_canceled = false
  294. _test_step = 0
  295. if _test_all_angles:
  296. if cancel_test:
  297. Log.print_log("*** Stop around the clock tests")
  298. _test_all_angles = false
  299. emit_signal("all_tests_done")
  300. else:
  301. Log.print_log("*** Start around the clock tests")
  302. _platform_body.rotation = deg2rad(_platform_angle)
  303. _lock_controls = true
  304. $Controls/PlatformAngle/HSlider.value = _platform_angle
  305. _lock_controls = false
  306. _next_test(true)
  307. func _next_test(force_start = false):
  308. if _moving_body:
  309. remove_child(_moving_body)
  310. _moving_body.queue_free()
  311. _moving_body = null
  312. if _test_all_angles:
  313. var angle = rad2deg(_platform_body.rotation)
  314. if angle >= _platform_angle + TEST_ALL_ANGLES_MAX:
  315. _platform_body.rotation = deg2rad(_platform_angle)
  316. _lock_controls = true
  317. $Controls/PlatformAngle/HSlider.value = _platform_angle
  318. _lock_controls = false
  319. _test_all_angles = false
  320. Log.print_log("*** Done all angles")
  321. else:
  322. angle = _platform_angle + _test_step * TEST_ALL_ANGLES_STEP
  323. _platform_body.rotation = deg2rad(angle)
  324. _lock_controls = true
  325. $Controls/PlatformAngle/HSlider.value = angle
  326. _lock_controls = false
  327. _start_test()
  328. elif force_start:
  329. _start_test()
  330. func _on_contact_detected(_body):
  331. if _contact_detected or _target_entered:
  332. return
  333. _contact_detected = true
  334. _test_passed = _should_collide()
  335. _set_result()
  336. _on_timeout()
  337. func _on_target_entered(_body):
  338. if _contact_detected or _target_entered:
  339. return
  340. _target_entered = true
  341. _test_passed = not _should_collide()
  342. _set_result()
  343. _on_timeout()
  344. func _should_collide():
  345. var platform_rotation = round(rad2deg(_platform_body.rotation))
  346. var angle = fposmod(platform_rotation, 360)
  347. return angle > 180
  348. func _on_timeout():
  349. cancel_timer()
  350. if $Timer.is_stopped():
  351. return
  352. $Timer.stop()
  353. if _test_canceled:
  354. emit_signal("test_done")
  355. emit_signal("all_tests_done")
  356. return
  357. if not _contact_detected and not _target_entered:
  358. Log.print_log("Test TIMEOUT")
  359. _set_result()
  360. yield(start_timer(0.5), "timeout")
  361. if _test_canceled:
  362. emit_signal("test_done")
  363. emit_signal("all_tests_done")
  364. return
  365. var was_all_angles = _test_all_angles
  366. _next_test()
  367. emit_signal("test_done")
  368. if was_all_angles and not _test_all_angles:
  369. emit_signal("all_tests_done")
  370. func _set_result():
  371. var result = ""
  372. if _test_passed:
  373. result = "PASSED"
  374. $LabelResult.self_modulate = Color.green
  375. else:
  376. result = "FAILED"
  377. $LabelResult.self_modulate = Color.red
  378. $LabelResult.text = result
  379. var platform_angle = rad2deg(_platform_body.rotation)
  380. result += ": size=%.1f, angle=%.1f, body angle=%.1f" % [_platform_size, platform_angle, _body_angle]
  381. Log.print_log("Test %s" % result)