Compare commits

...

146 Commits

Author SHA1 Message Date
Aaron Franke
bf94d62472 [3.3] Simplify list of branches in the README (#1255) 2025-10-02 17:00:58 -07:00
Rémi Verschelde
95d97d9001 Update README for new branches, matches Godot upstream
(cherry picked from commit c0180d20d1)
2023-02-28 18:36:34 +01:00
Aaron Franke
53ea602c07 Update README for the new 3.3 branch 2021-11-05 10:15:06 -05:00
Aaron Franke
874d3bcc33 Merge pull request #657 from Calinou/allow-fallback-gles2
Allow 3D demos to fallback to GLES2
2021-11-05 11:07:01 -04:00
Hugo Locurcio
cbb5c94c6f Allow 3D demos to fallback to GLES2
A GLES2-specific tweak is now documented for the GUI in 3D demo.

This also tweaks shadow quality and performance to find a better
balance and result in smoother shadows, including when using GLES2
(thanks to the use of PCF13 shadow filter mode).

In demos that allow falling back to GLES2, ETC1 texture import
is enabled to allow exporting to Android or HTML5 without having
to tweak anything.
2021-11-05 09:57:51 -05:00
Aaron Franke
44aefaecb6 Merge pull request #655 from Calinou/bullet-shower-no-check-collision-with-other-bullets
Don't check bullet collision with other bullets in the Bullet shower demo
2021-10-26 10:33:38 -04:00
Hugo Locurcio
7a7af4cf4e Don't check bullet collision with other bullets in the Bullet shower demo
This improves performance by reducing the number of collision checks
that need to be done.
2021-10-25 23:16:29 +02:00
Rémi Verschelde
1916f87ac5 Merge pull request #654 from aaronfranke/circlepop-noready 2021-10-15 21:54:09 +02:00
Aaron Franke
36e8b45bd4 Remove useless "_ready" in the Circle Pop demo 2021-10-15 14:35:14 -05:00
Rémi Verschelde
89b64e33e2 CI: Ping actions/checkout@v2, no need to be more specific 2021-10-15 21:20:16 +02:00
Gunnar Ahlberg
2b10e6724e Fix leaked object - Label (#648)
This fixes a warning of leaked instances.
2021-09-13 00:05:26 -05:00
Hugo Locurcio
b9685cb369 Merge pull request #645 from Calinou/use-remotesync-keyword
Use `remotesync` instead of the deprecated `sync` in networking demos
2021-08-29 17:09:25 +02:00
Hugo Locurcio
d1f25ca4aa Use remotesync instead of the deprecated sync in networking demos
The `sync` keyword has been deprecated since Godot 3.1.
2021-08-29 12:22:37 +02:00
Aaron Franke
11a72411cc Merge pull request #644 from Calinou/ci-update-to-godot-3.3.3
GitHub Actions: Update to Godot 3.3.3 for HTML5 deployment
2021-08-22 14:55:44 -05:00
Hugo Locurcio
5057fcff50 GitHub Actions: Update to Godot 3.3.3 for HTML5 deployment 2021-08-22 11:56:01 +02:00
Aaron Franke
d791cd9bda Merge pull request #643 from shahediqbal13/mono-iap-signal-mismatch
Google play billing method signature mismatch in demo with Godot's android billing plugin method
2021-08-18 18:46:42 -04:00
Shahed Iqbal
7d7c728227 Fixes following issues:
1. Google play billing method(OnGodotGooglePlayBilling_sku_details_query_error) signature in GooglePlayBilling class doesn't match with Godot's android library exposed method
Check: https://github.com/godotengine/godot-google-play-billing/blob/master/godot-google-play-billing/src/main/java/org/godotengine/godot/plugin/googleplaybilling/GodotGooglePlayBilling.java
Line: 236.

2. "OnConnectError" method signature mismatch
2021-08-19 03:23:44 +06:00
Aaron Franke
5fb81434e7 Merge pull request #642 from nathanfranke/opensimplexnoise-improvements
Simplify and improve OpenSimplexNoise viewer
2021-08-18 00:05:26 -04:00
Nathan Franke
c3c4fdf4fa Simplify and improve OpenSimplexNoise viewer 2021-08-17 23:02:55 -05:00
Aaron Franke
9ea18370d3 Add link to the Godot Asset Library for Skeleton2D 2021-08-17 21:03:15 -05:00
Aaron Franke
f9333dce01 Merge pull request #640 from shahediqbal13/mono-iap-signal-mismatch
Mono IAP signal method definition mismatch.
2021-08-17 21:24:11 -04:00
Aaron Franke
84a87a5128 Merge pull request #641 from aaronfranke/desc
Ensure most demos have descriptions and screenshots
2021-08-17 20:49:22 -04:00
Aaron Franke
7d64830cfe Ensure most demos have descriptions and screenshots 2021-08-16 21:13:06 -05:00
Shahed Iqbal
f08916c90f Mono IAP signal method definition mismatch. Updated OnPurchaseConsumptionError() method to match with GooglePlayBilling's signal 2021-08-15 02:48:05 +06:00
Aaron Franke
89978a7421 Merge pull request #636 from Powerbyte7/patch-1
Fix jumps in scale and rotation when pinching
2021-07-18 11:19:48 -07:00
Powerbyte7
6ca2a45a21 Fix jumps in scale and rotation when pinching
When pressing with two fingers at once and pinching,  an old coordinate contained in the curr_state dictionary gets added to the base_state dictionary, which causes unintended jumps in both scale and rotation. By clearing base_state the script functions as intended.
2021-07-18 17:00:59 +02:00
Agnis "NeZvērs" Aldiņš
57f8628b50 Update impact, rigid groundcheck, moving platform (#634) 2021-07-17 13:00:51 -04:00
Aaron Franke
a4e8231f5a Merge pull request #635 from aaronfranke/tweaks
Minor tweaks to Pong and Dodge the Creeps
2021-07-12 13:15:01 -07:00
Aaron Franke
f71816ed31 Minor tweaks to Pong and Dodge the Creeps 2021-07-11 13:08:01 -04:00
Aaron Franke
ef069d49ae Merge pull request #632 from aaronfranke/fsm-bullets
Fix bullets in the Finite State Machine demo
2021-07-06 20:34:41 -04:00
Aaron Franke
742ea87708 Merge pull request #633 from starptr/master
Use the Jump sound already present in the Platformer 2D demo
2021-07-06 20:32:50 -04:00
Yuto Nishida
45f5417822 Add jump sound effect 2021-07-06 16:40:15 -07:00
Aaron Franke
f28a09ea0d Fix bullets in the Finite State Machine demo 2021-07-05 01:09:50 -04:00
Aaron Franke
85c1805d33 Merge pull request #631 from aaronfranke/not
Use "not" instead of the exclamation mark in GDScript files
2021-07-05 01:00:28 -04:00
Aaron Franke
7e129db12e Use "not" instead of the exclamation mark in GDScript files
Also add String casts
2021-07-04 03:46:21 -04:00
Aaron Franke
7bfc57d1ae Merge pull request #628 from aaronfranke/skeleton2d
Add a Skeleton2D demo
2021-06-25 19:19:26 -04:00
Aaron Franke
cd48c9a9cc Add a Skeleton2D demo 2021-06-25 19:12:53 -04:00
Rémi Verschelde
244b759787 Merge pull request #627 from aaronfranke/no-builtin-e
Replace built-in scripts and delete strange "e" scripts
2021-06-21 20:57:16 +02:00
Aaron Franke
6875a21545 Replace built-in scripts and delete strange "e" scripts 2021-06-21 12:33:42 -04:00
Aaron Franke
694ee7fa36 Merge pull request #626 from aaronfranke/jrpg-simplify
Vastly simplify the JRPG demo
2021-06-21 12:22:44 -04:00
Aaron Franke
6e3db7c64d Vastly simplify the JRPG demo 2021-06-20 22:47:24 -04:00
Agnis "NeZvērs" Aldiņš
2d4d23302a 3D physics tests - Moving platform (#623) 2021-06-09 20:57:49 -04:00
Aaron Franke
4456027f91 Merge pull request #625 from aaronfranke/3d2d-robot
Simplify 3D robot in the 3D in 2D demo
2021-06-07 09:40:49 -04:00
Aaron Franke
19312b2899 Simplify 3D robot in the 3D in 2D demo 2021-06-06 23:28:53 -04:00
Aaron Franke
ca17967de1 Merge pull request #622 from aaronfranke/waypoint-camera-current
Have waypoints check if the camera is current
2021-05-29 03:19:57 -04:00
Aaron Franke
491fb265b1 Have waypoints check if the camera is current
If not, get the current camera.
2021-05-29 03:16:07 -04:00
Agnis "NeZvērs" Aldiņš
08be1b7f03 Additional 3D physics tests - RigidBody impact and ground check (#619)
Co-authored-by: Camille Mohr-Daurat <pouleyKetchoup@gmail.com>
2021-05-29 02:58:01 -04:00
Aaron Franke
4ef90a836a Merge pull request #621 from nellodotca/master
Fixed project settings to match tutorial
2021-05-24 21:09:43 -04:00
nello
bfd903a933 Fixed project settings to match tutorial 2021-05-24 19:14:12 -03:00
Aaron Franke
e0db0b8f6d Merge pull request #615 from nekomatata/physics-tests-draw-shape-clean
Fix hack to draw shapes in 3D physics tests
2021-05-19 15:45:22 -04:00
PouleyKetchoupp
4d21951b71 Fix hack to draw shapes in 3D physics tests
Using Shape::get_debug_mesh instead of the previous hack to draw a mesh
instance based on a collision shape.
2021-05-05 13:41:51 -07:00
Aaron Franke
7656c08454 Merge pull request #614 from aaronfranke/gridmap-perf
Improve performance in GridMap demos by adjusting octant size
2021-05-04 15:22:10 -04:00
Aaron Franke
e894e4655a Improve performance in GridMap demos 2021-05-04 02:48:32 -04:00
Aaron Franke
2ce76ff4e5 Update web deploy CI to use Godot 3.3 2021-04-24 04:20:39 -04:00
Aaron Franke
e5d829eb8f Merge pull request #613 from nekomatata/physics-tests-contacts-update
Update contact tests in physics tests for 2D & 3D
2021-04-24 02:32:19 -05:00
PouleyKetchoupp
7f025e000e Update contact tests in physics tests for 2D & 3D
- Create bodies by duplicating the ones from the scene to allow custom
settings on them for testing purpose
- Rename 3D test with multiple groups of bodies "Contact Islands"
instead of "Contacts Extended" for clarity
- Added "Contact Islands" test for 2D
- Fixed log spamming with "Contact Islands" tests due to printing log
messages for each group of bodies
- Added parameter to randomize spawn positions in order to make
contact separation more balanced (avoids artifacts like a huge column
for circles in 2D test)
- Using smaller shapes and larger amount of objects by default to test
more extreme case
2021-04-21 18:25:35 -07:00
Aaron Franke
5132941a84 Merge pull request #612 from nekomatata/physics-tests-3.3
Physics Tests 3.3 update
2021-04-21 19:51:44 -05:00
PouleyKetchoupp
ef265cca0a Physics Tests 3.3 update
Fix custom collision shape drawing in physics tests:
CollisionShape debug draw has changed in 3.3 and now requires a body
to be rendered, so the trick to display custom physics shapes in the
physics tests had to be updated.

Cylinder support:
Now cylinders are supported in Godot Physics, so the exception to avoid
spamming errors when cylinders are used can be removed.

Rigid body picking:
Added mouse-picking to Test Shapes in both 2D and 3D.
2021-04-21 16:50:33 -07:00
Aaron Franke
31bb09233b Update the OS test demo for Godot 3.3 2021-04-21 19:30:53 -04:00
Aaron Franke
57f5e0835d Merge pull request #558 from aaronfranke/update-3.2.4
Update projects to Godot 3.3
2021-04-21 18:20:01 -05:00
Aaron Franke
814909538f Update projects to Godot 3.3 2021-04-21 19:17:12 -04:00
Rémi Verschelde
94ec2ea5d9 Merge pull request #607 from aaronfranke/3.2-readme
Update README for the new 3.2 branch
2021-04-21 09:57:08 +02:00
Aaron Franke
40aec7c068 Update README for the new 3.2 branch 2021-04-14 13:46:19 -04:00
Aaron Franke
ead2777f48 Merge pull request #606 from nekomatata/physics-tests-contacts-update
Updated 2d/3d physics contact performance tests
2021-04-14 12:34:24 -05:00
PouleyKetchoupp
0a0d44d4f1 Updated 2d/3d physics contact performance tests 2021-04-14 08:19:10 -07:00
Aaron Franke
4911866f3d Merge pull request #604 from waimus/os_midi_scan_fix
Fix MIDI devices scanning
2021-04-05 16:51:00 -04:00
waimus
d7e1052205 Fix MIDI devices scanning 2021-04-06 03:10:33 +07:00
Aaron Franke
8e2dbf3f55 Merge pull request #602 from aaronfranke/etc
Use ETC instead of ETC2 for all GLES2 demos
2021-03-30 02:31:43 -04:00
Aaron Franke
2ee9b47f6c Use ETC instead of ETC2 for all GLES2 demos 2021-03-29 18:30:14 -04:00
Aaron Franke
d8dc94c1ff Merge pull request #601 from aaronfranke/ternary-volume
Use fewer ternary operators and decrease volume of Platformer 2D
2021-03-29 18:29:28 -04:00
Aaron Franke
d989bf6209 Use fewer ternary operators and decrease volume of Platformer 2D 2021-03-28 22:03:03 -04:00
Aaron Franke
021070215c Merge pull request #595 from dalexeev/bullet-shower-improve
Small improvement for Bullet Shower Demo
2021-03-26 20:20:31 -07:00
Aaron Franke
ac61cba05b Merge pull request #597 from aaronfranke/joy-24
Handle up to 24 joypad buttons in the Joypads demo
2021-03-15 04:34:12 -04:00
Aaron Franke
21e829416f Handle up to 24 joypad buttons in the Joypads demo 2021-03-13 23:28:22 -04:00
Danil Alexeev
cf7e4b31f4 Small improvement for Bullet Shower Demo 2021-03-13 21:04:13 +03:00
Aaron Franke
dc5c1016ce Merge pull request #594 from aaronfranke/assetlib-5c154da
Add links to the Asset Library after release 3.2-5c154da
2021-03-11 21:56:54 -08:00
Aaron Franke
8a0824a948 Add links to the Asset Library after release 3.2-5c154da
Also expand the CODEOWNERS file
2021-03-12 00:32:11 -05:00
Aaron Franke
5c154dac25 Merge pull request #593 from nekomatata/physics-tests-cancel-fix
Physics test cases, cancel previous running test properly
2021-03-09 18:49:38 -05:00
PouleyKetchoupp
7f095a6092 Physics test cases, cancel previous running test properly
Allows canceling running test cases (including all tests cases) properly and without error.
2021-03-08 12:27:13 -07:00
Aaron Franke
35687c3ead Merge pull request #592 from aaronfranke/kine-char-3d-pos
Set the reset position from the initial start position in KC3D
2021-03-03 14:55:35 -05:00
Aaron Franke
f91fe01f3e Set the reset position from the initial start position in KC3D 2021-03-03 14:41:44 -05:00
Aaron Franke
43d29bfbbb Merge pull request #591 from aaronfranke/misc
Misc improvements and tweaks for 3.2.3
2021-03-03 14:19:31 -05:00
Aaron Franke
7dff4e748d Merge pull request #590 from aaronfranke/kine-char-3d
Improve the Kinematic Character 3D demo
2021-03-03 14:18:33 -05:00
Aaron Franke
4913cd868a Misc fixes and tweaks 2021-03-03 02:59:17 -05:00
Aaron Franke
973c12264c Improve the Kinematic Character 3D demo 2021-03-03 02:55:05 -05:00
Aaron Franke
fecbed5fb2 Merge pull request #586 from Calinou/improve-demo-configuration
Improve several demos' configuration
2021-03-02 18:25:05 -05:00
Aaron Franke
82e68e378b Merge pull request #589 from Calinou/improve-3d-platformer-demo
Improve the 3D platformer demo
2021-03-02 18:22:31 -05:00
Aaron Franke
bbf4cff5f7 Merge pull request #588 from Calinou/readd-bullet-shower-demo
Port the Bullet Shower demo from Godot 2.1
2021-03-02 18:22:23 -05:00
Hugo Locurcio
3d6ba65cfc Improve the 3D platformer demo
- Increase gravity, player speed and air acceleration for a less floaty
  feeling.
- Clean up the code to use constants when relevant and remove unused enums.
2021-03-02 19:36:25 +01:00
Hugo Locurcio
ca0f74ee44 Port the Bullet Shower demo from Godot 2.1
This demo showcases how to use low-level Servers to achieve better
CPU performance when drawing large amounts of objects.

The code has been updated for Godot 3.2, cleaned up and has received
additional comments.
2021-03-02 18:32:01 +01:00
Hugo Locurcio
aa65867e43 Improve several demos' configuration
- Enable anisotropic filtering in 3D demos, and set the quality to
  16× on desktop and 4× on mobile.
- Enable 4× MSAA on some 3D demos that didn't use it beforehand.
- On GLES3 demos, disable MSAA on mobile as these demos are often
  more demanding.
- Use more conservative framebuffer allocation settings for better
  performance.
- Use PCF13 shadow filtering in GLES2 demos on desktop to benefit
  from soft shadows in Godot 3.2.4 and later.
  In Godot 3.2.3, this will make shadows smoother but still "blocky".
- Use Lossless compression instead of VRAM compression for
  small textures such as the voxel demo texture atlas.
2021-02-28 22:28:44 +01:00
Aaron Franke
c2e7a30e42 Merge pull request #587 from aaronfranke/web-readme
Link to the web export in the README and format names nicer
2021-02-28 16:18:29 -05:00
Aaron Franke
4dbfd92e6f Link to the web export in the README and format names nicer 2021-02-28 15:50:59 -05:00
Aaron Franke
c0d9e483c2 Merge pull request #582 from Calinou/deploy-html5-demos
Deploy exported HTML5 demos to GitHub Pages
2021-02-27 23:16:36 -05:00
Hugo Locurcio
36db05c3b9 Deploy exported HTML5 demos to GitHub Pages
This makes it possible for users to test Godot's features without
having to download anything.
2021-02-28 05:12:06 +01:00
ThomasFederau
fc032119ca Added interpolation functionality to ik_look_at node (#585) 2021-02-26 22:29:47 -05:00
Aaron Franke
98ed996780 Merge pull request #584 from nekomatata/physics-tests-2d-character-update
Updated 2D character controller physics tests
2021-02-26 09:25:58 -05:00
PouleyKetchoupp
fa83ee0277 Updated 2D character controller physics tests
Added new test for 2D character controller:
Character - Pixels
Functional test for pixel art related issues around KinematicBody and
RigidBody character controllers.

Adjusted existing tests and added more test cases to cover most use
cases from recent fixed issues and regressions for KinematicBody.

Added a more automated way to run all tests with checks to see which
ones failed in character controller tests.

Also fixed some minor issues with the log scrollbar.
2021-02-22 20:09:43 -07:00
Aaron Franke
7c137510e7 Merge pull request #583 from aaronfranke/trucktown-force-spedometer
Use a higher engine force when slow and add a spedometer in Truck Town
2021-02-22 21:46:03 -05:00
Aaron Franke
10a7e3d301 Use a higher engine force when slow and add a spedometer in Truck Town
Co-authored-by: Hugo Locurcio <hugo.locurcio@hugo.pro>
2021-02-22 13:56:17 -05:00
Aaron Franke
feaf406fee Merge pull request #581 from Calinou/truck-town-improve-controls-camera
Improve controls and camera handling in the Truck Town demo
2021-02-22 13:46:05 -05:00
Hugo Locurcio
d90e401d2a Improve controls and camera handling in the Truck Town demo
- Increase movement and steering speed significantly.
- Increase gravity slightly for a less floaty feeling.
- Simplify camera code (height is now constant).
- Tweaked camera distance and height to fit each vehicle.
- Fix script error when pressing Escape in the main menu
  (the demo will now quit).
2021-02-21 20:00:04 +01:00
Aaron Franke
99ad90bd0d Merge pull request #580 from Calinou/simplify-3d-scaling-setup
Simplify the 3D scaling demo setup, enable filtering by default
2021-02-12 23:57:49 -05:00
Hugo Locurcio
4adaaa2eb2 Simplify the 3D scaling demo setup, enable filtering by default
It turns out using a TextureRect node isn't necessary :)

The typical ViewportContainer + Viewport setup can be used just
fine to enable filtering on the ViewportTexture returned by the
Viewport.

The performance of the new method is equivalent to the old one.
2021-02-13 02:56:51 +01:00
Aaron Franke
b946d20762 Merge pull request #575 from Faless/joy/remap_wizard
[Joypads] Add SDL config re-mapping tool.
2021-02-07 16:24:18 -05:00
Fabio Alessandrelli
2a13307276 [Joypads] Add SDL config re-mapping tool.
Most of the code is in the remap folder, but it depends on the gamepad
diagram scene.
It allows remapping of pads to values that godot can understand.
It also comes with some default mapping for the HTML5 platform.
2021-02-07 13:19:18 +01:00
Aaron Franke
0b3e046953 Merge pull request #577 from nekomatata/physics-test-controllers
Add physics tests for 2D character controller
2021-01-22 20:01:39 -05:00
Aaron Franke
68e095c4d6 Merge pull request #578 from nekomatata/physics-tests-key-bindings
Changed key bindings in physics tests 2D/3D
2021-01-22 19:55:28 -05:00
PouleyKetchoupp
fe54ebbb3a Changed key bindings in physics tests 2D/3D
Changed debug collision shortcut from 'D' to 'C' to keep WASD available
for other functions in some tests.

Unbound arrows from UI shortcuts for the same reason.
2021-01-22 17:33:48 -07:00
PouleyKetchoupp
cdf0ed3be9 Add physics tests for 2D character controller
Two tests for character controller, with options to use RigidBody2D,
KinematicBody2D or KinematicBody2D with RayShape2D.

Tilemap: Tests for moving and jumping within tilemap blocks, with a
specific one-way collision test case scenario based on Block Climb Test
from https://github.com/madmiraal/godot-gym.

Slopes: Tests for moving and jumping in slopes, with different cases
based on snap and stop-on-slope parameters for kinematic bodies.
2021-01-22 17:24:28 -07:00
Aaron Franke
da9e24dfa7 Merge pull request #576 from nekomatata/physics-tests-broadphase-update
Update broadphase performance test in physics tests
2021-01-21 05:08:05 -05:00
PouleyKetchoupp
1c1ad17b43 Update broadphase performance test in physics tests
Start logging physics tick one frame earlier for each operation
Disable debug collision to avoid rendering bottleneck
Fixes in adding/removing bodies to avoid bottlenecks outside of physics
2D: Increase message queue size to allow adding more objects at once
3D: Remove camera to disable rendering altogether
3D: Fix error with create_rigidbody_box missing default value
2021-01-20 10:04:50 -07:00
Aaron Franke
5618c2b45a Merge pull request #574 from nekomatata/physics-tests-pause
Support for pause in 2D/3D physics tests
2021-01-06 23:56:36 -05:00
PouleyKetchoupp
3878948300 Support for pause in 2D/3D physics tests
New controls for all tests:
P to toggle pause on/off

Affects the running tests but not menus.
2021-01-06 21:25:34 -07:00
Aaron Franke
ca4cde1c26 Merge pull request #573 from nekomatata/physics-test-one-way-collision
Add One Way Collision for 2D Physics tests
2021-01-06 23:00:43 -05:00
PouleyKetchoupp
6a738c1ede Add One Way Collision for 2D Physics tests 2021-01-06 20:25:27 -07:00
Aaron Franke
04e9afb4cf Merge pull request #570 from aaronfranke/mr-k-inspired
Update the Drag and Drop demo and the Tween demo
2021-01-06 21:45:53 -05:00
Aaron Franke
e73af12f49 Script updates and simplification 2021-01-06 01:32:12 -05:00
Aaron Franke
6bdbeafca2 Update Tween demo to use Containers 2021-01-03 03:01:52 -06:00
Aaron Franke
21cbaafb2f Use a GridContainer in the Drag and Drop demo 2021-01-02 19:07:31 -06:00
Aaron Franke
35426410d5 Merge pull request #567 from aaronfranke/add-3d-waypoints-demo
Add a 3D waypoints demo
2021-01-02 14:47:30 -06:00
Hugo Locurcio
54a8d37e6c Add a 3D waypoints demo
Co-authored-by: Aaron Franke <arnfranke@yahoo.com>
2021-01-02 14:45:05 -06:00
Aaron Franke
d5dae1cbb7 Merge pull request #569 from aaronfranke/add-control-gallery-demo
Add a control gallery demo
2021-01-02 14:38:05 -06:00
Hugo Locurcio
06dc40ba65 Add a control gallery demo
This project showcases what Godot's various Control nodes can do
(and what they look like, so that new users can figure them out).
2021-01-02 00:39:59 -06:00
Aaron Franke
7c604f336d Merge pull request #568 from aaronfranke/2021
Update copyright statements for 2021
2021-01-01 22:30:54 -06:00
Aaron Franke
e3a31afe40 Update copyright statements for 2021 2021-01-01 21:49:36 -06:00
Aaron Franke
289d658baa Merge pull request #566 from nekomatata/physics-test-joints
Add joints test to 2D/3D physics tests
2020-12-31 01:22:21 -06:00
PouleyKetchoupp
7a437d1d23 Add joints test to 2D/3D physics tests 2020-12-30 20:15:08 -07:00
Aaron Franke
08e3f1efd0 Merge pull request #565 from aaronfranke/save-load-loading
Move Saving and Loading demo to Loading category
2020-12-30 14:23:10 -06:00
Aaron Franke
0d9c0d15c6 Move Saving and Loading demo to Loading category 2020-12-28 14:00:04 -06:00
Aaron Franke
96baaa09e3 Merge pull request #563 from aaronfranke/mr-k-platformer
Add a coin counter and pause menu fading to Platformer 2D
2020-12-28 13:48:22 -06:00
Mr.K GameDev
e004d2564e 2D Platformer UI Update
Co-authored-by: Aaron Franke <arnfranke@yahoo.com>
2020-12-26 23:35:45 -06:00
Aaron Franke
651ef54920 Merge pull request #562 from nekomatata/physics-tests-owner
Add PouleyKetchoupp to owners for physics tests
2020-12-19 11:59:55 -06:00
Aaron Franke
4a60286512 Merge pull request #561 from nekomatata/physics-test-collision-pairs
Add collision pairs test to 2D/3D physics tests
2020-12-19 11:59:26 -06:00
PouleyKetchoupp
1148a6bda0 Add PouleyKetchoupp to owners for physics tests 2020-12-19 10:46:18 -07:00
PouleyKetchoupp
9ad473c633 Add collision pairs test to 2D/3D physics tests
Functional test used for checking/debugging different collision cases for all possible pairs of shape types.
2020-12-18 20:51:54 -07:00
Aaron Franke
e38be6dec0 Merge pull request #560 from nekomatata/physics-tests-2d
Add 2D Physics Tests
2020-12-16 23:11:54 -05:00
PouleyKetchoupp
8241be5817 Add demo: Physics Tests 2D
Similar to its 3D counterpart, with tests using 2D physics.
2020-12-16 09:11:35 -07:00
Aaron Franke
1c836ecde9 Merge pull request #559 from nekomatata/physics-tests-3d-update
Fixes and adjustments in 3D physics tests
2020-12-14 20:36:01 -05:00
PouleyKetchoupp
6dd09308fa Fixes and adjustments in 3D physics tests
Add Functional Test / Stack & Pyramid
For testing stack stability.

Add Functional Test / Raycasts
Visually test raycast on different shapes.

Add Performance Test / Broadphase
Add/move/remove lots of non-colliding objects and measure time.

Fix leaks on exit
Some Nodes are copied and removed from the scene to be used as templates,
they need to be freed manually on exit.

Fix Performance Test / Contacts
Positions adjusted, some shape types were not created at the center.
2020-12-14 17:25:26 -07:00
Aaron Franke
555e43c896 Merge pull request #517 from Calinou/add-save-load-demo
Add a saving/loading demo with various serialization formats
2020-12-12 18:27:32 -05:00
Hugo Locurcio
2bd5b1c8ee Add a saving/loading demo with various serialization formats
This demo showcases how to save a simple game with ConfigFile and JSON.
2020-12-13 00:21:47 +01:00
Aaron Franke
14f2f1a713 Merge pull request #557 from aaronfranke/3din2d
Simplify 3D in 2D demo
2020-12-08 18:50:27 -05:00
Aaron Franke
3d9bcc6d97 Simplify 3D in 2D demo 2020-12-06 22:00:51 -05:00
Aaron Franke
3147c6c5bd Merge pull request #554 from aaronfranke/assetlib-5bd2bbf
Add links to the Asset Library after release 3.2-5bd2bbf
2020-11-28 23:31:51 -05:00
Aaron Franke
20a515153f Add links to the Asset Library after release 3.2-5bd2bbf 2020-11-28 23:21:06 -05:00
678 changed files with 17932 additions and 3263 deletions

View File

@@ -2,10 +2,15 @@
root = true
# Unix-style newlines with a newline ending every file.
[*.cs]
[*]
charset = utf-8
end_of_line = lf
insert_final_newline = true
[*.cs]
csharp_space_after_cast = false
indent_size = 4
[*.csproj]
insert_final_newline = false
indent_size = 2

11
.github/CODEOWNERS vendored
View File

@@ -2,5 +2,12 @@
# Each line is a file pattern followed by one or more owners.
# Owners can be @users, @org/teams or emails
/misc/2.5d @aaronfranke
/mono/2.5d @aaronfranke
/.github/dist/ @Calinou
/3d/voxel/ @aaronfranke
/misc/matrix_transform/ @aaronfranke
/misc/2.5d/ @aaronfranke
/mono/2.5d/ @aaronfranke
/2d/physics_tests/ @pouleyKetchoupp
/3d/physics_tests/ @pouleyKetchoupp

View File

@@ -1,9 +1,9 @@
---
name: Bug Report
about: Report a bug with one of the demo projects.
title: ''
title: ""
labels: bug
assignees: ''
assignees: ""
---

View File

@@ -1,9 +1,9 @@
---
name: Feature / Enhancement Request
about: Adding new features or improving existing ones.
title: ''
title: ""
labels: enhancement
assignees: ''
assignees: ""
---

0
.github/dist/.nojekyll vendored Normal file
View File

23
.github/dist/export_presets.cfg vendored Normal file
View File

@@ -0,0 +1,23 @@
[preset.0]
name="HTML5"
platform="HTML5"
runnable=true
custom_features=""
export_filter="all_resources"
include_filter=""
exclude_filter=""
export_path=""
script_export_mode=1
script_encryption_key=""
[preset.0.options]
custom_template/debug=""
custom_template/release=""
variant/export_type=0
vram_texture_compression/for_desktop=true
vram_texture_compression/for_mobile=false
html/custom_html_shell=""
html/head_include=""
html/full_window_size=true

19
.github/dist/footer.html vendored Normal file
View File

@@ -0,0 +1,19 @@
<!-- The list of demos will be inserted above by the CI process. -->
</ul>
<h2>Unavailable demos</h2>
<ul>
<li><code>2d/hdr/</code>: Not supported on HTML5 yet.
<li><code>3d/voxel/</code>: Not supported on HTML5 yet.
<li><code>audio/device_changer/</code>: Not supported on HTML5 due to browser limitations.
<li><code>loading/background_load/</code>: Not supported on HTML5 yet.
<li><code>loading/multiple_threads_loading/</code>: Not supported on HTML5 yet.
<li><code>loading/threads/</code>: Not supported on HTML5 yet.
<li><code>misc/matrix_transform/</code>: Results are only visible in the editor.
<li><code>mobile/android_iap/</code>: Only relevant on native Android.
<li><code>mobile/sensors/</code>: Not supported on HTML5 yet.
<li><code>mono/*/</code>: Not available yet (requires Mono-enabled HTML5 build).</li>
<li><code>networking/*/</code>: Doesn't make sense to be hosted on a static host, as the server must be hosted on the same origin due to the browser's same-origin policy.</li>
<li><code>plugins/*/</code>: Only effective within the editor.</li>
</ul>
</body>
</html>

118
.github/dist/header.html vendored Normal file
View File

@@ -0,0 +1,118 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Godot demos exported to HTML5</title>
<style>
:root {
--background-color: #fff;
--text-color: #222;
--link-color: hsl(220, 100%, 45%);
--link-underline-color: hsla(220, 100%, 45%, 0.3);
}
@media (prefers-color-scheme: dark) {
:root {
--background-color: #222;
--text-color: #eee;
--link-color: hsl(200, 100%, 70%);
--link-underline-color: hsla(200, 100%, 70%, 0.3);
}
}
*:focus {
/* More visible outline for better keyboard navigation. */
outline: 0.125rem solid hsl(220, 100%, 62.5%);
/* Make the outline always appear above other elements. */
position: relative;
}
html {
background-color: var(--background-color);
color: var(--text-color);
}
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif;
max-width: 50rem;
margin: 0 auto;
padding: 0.75rem;
line-height: 1.618rem;
}
h2 {
margin-top: 2.5rem;
}
a {
color: var(--link-color);
text-decoration-color: var(--link-underline-color);
text-decoration-thickness: 0.125rem;
}
a:hover {
filter: brightness(117.5%);
}
a:active {
filter: brightness(82.5%);
}
ul {
padding-left: 0;
}
li {
display: block;
}
li a {
display: inline-block;
width: 100%;
height: 4rem;
margin-left: 0.5rem;
}
li a:hover {
background-color: hsla(0, 0%, 50%, 0.1);
}
li a * {
float: left;
}
li a p {
height: 24px;
margin: 20px 10px;
}
</style>
</head>
<body>
<h1>Godot demo projects</h1>
<p>
This page lists
<a href="https://github.com/godotengine/godot-demo-projects">official Godot demo projects</a>
exported to HTML5 for testing purposes. These projects are deployed automatically
on every commit on the <code>master</code> branch of the repository.
</p>
<p>
The HTML5 exports on this page are provided for demonstration purposes only.
Some of these demos may not function or render correctly on HTML5,
especially on mobile devices.
For best performance, it's recommended to
<a href="https://godotengine.org/download">download</a> a native editor
and run the demo project by importing its files in the project manager.
</p>
<p>
See the
<a href="https://docs.godotengine.org/en/stable/getting_started/workflow/export/exporting_for_web.html">Exporting for the Web</a>
documentation for information on exporting your own projects to HTML5.
</p>
<h2>List of demos</h2>
<ul>
<!-- The list of demos will be inserted below by the CI process. -->

View File

@@ -4,10 +4,10 @@ on: [push, pull_request]
jobs:
format:
name: File formatting (file_format.sh)
runs-on: ubuntu-20.04
runs-on: ubuntu-24.04
steps:
- name: Checkout
uses: actions/checkout@v2
uses: actions/checkout@v5
- name: Install dependencies
run: |

3
.gitignore vendored
View File

@@ -5,6 +5,8 @@
.import/
export.cfg
export_presets.cfg
# Dummy HTML5 export presets file for continuous integration
!.github/dist/export_presets.cfg
# Imported translations (automatically generated from CSV files)
*.translation
@@ -16,4 +18,5 @@ mono_crash.*.json
# System/tool-specific ignores
.directory
.DS_Store
*~

View File

@@ -0,0 +1,20 @@
# Bullet Shower
This demonstrates how to manage large amounts of objects efficiently using
low-level Servers.
See
[Optimization using Servers](https://docs.godotengine.org/en/latest/tutorials/performance/using_servers.html)
in the documentation for more information.
Language: GDScript
Renderer: GLES 2
Check out this demo on the asset library: https://godotengine.org/asset-library/asset/887
## Screenshots
![No collision](screenshots/no_collision.png)
![Collision](screenshots/collision.png)

BIN
2d/bullet_shower/bullet.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 312 B

View File

@@ -2,15 +2,15 @@
importer="texture"
type="StreamTexture"
path="res://.import/sprite.png-e28cedc69371816a3468e6325b327ece.stex"
path="res://.import/bullet.png-ff1424653e10246c11e3724e402c519e.stex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://grid_movement/pawns/sprite.png"
dest_files=[ "res://.import/sprite.png-e28cedc69371816a3468e6325b327ece.stex" ]
source_file="res://bullet.png"
dest_files=[ "res://.import/bullet.png-ff1424653e10246c11e3724e402c519e.stex" ]
[params]

View File

@@ -0,0 +1,93 @@
extends Node2D
# This demo is an example of controling a high number of 2D objects with logic
# and collision without using nodes in the scene. This technique is a lot more
# efficient than using instancing and nodes, but requires more programming and
# is less visual. Bullets are managed together in the `bullets.gd` script.
const BULLET_COUNT = 500
const SPEED_MIN = 20
const SPEED_MAX = 80
const bullet_image = preload("res://bullet.png")
var bullets = []
var shape
class Bullet:
var position = Vector2()
var speed = 1.0
# The body is stored as a RID, which is an "opaque" way to access resources.
# With large amounts of objects (thousands or more), it can be significantly
# faster to use RIDs compared to a high-level approach.
var body = RID()
func _ready():
randomize()
shape = Physics2DServer.circle_shape_create()
# Set the collision shape's radius for each bullet in pixels.
Physics2DServer.shape_set_data(shape, 8)
for _i in BULLET_COUNT:
var bullet = Bullet.new()
# Give each bullet its own speed.
bullet.speed = rand_range(SPEED_MIN, SPEED_MAX)
bullet.body = Physics2DServer.body_create()
Physics2DServer.body_set_space(bullet.body, get_world_2d().get_space())
Physics2DServer.body_add_shape(bullet.body, shape)
# Don't make bullets check collision with other bullets to improve performance.
# Their collision mask is still configured to the default value, which allows
# bullets to detect collisions with the player.
Physics2DServer.body_set_collision_layer(bullet.body, 0)
# Place bullets randomly on the viewport and move bullets outside the
# play area so that they fade in nicely.
bullet.position = Vector2(
rand_range(0, get_viewport_rect().size.x) + get_viewport_rect().size.x,
rand_range(0, get_viewport_rect().size.y)
)
var transform2d = Transform2D()
transform2d.origin = bullet.position
Physics2DServer.body_set_state(bullet.body, Physics2DServer.BODY_STATE_TRANSFORM, transform2d)
bullets.push_back(bullet)
func _process(_delta):
# Order the CanvasItem to update every frame.
update()
func _physics_process(delta):
var transform2d = Transform2D()
var offset = get_viewport_rect().size.x + 16
for bullet in bullets:
bullet.position.x -= bullet.speed * delta
if bullet.position.x < -16:
# The bullet has left the screen; move it back to the right.
bullet.position.x = offset
transform2d.origin = bullet.position
Physics2DServer.body_set_state(bullet.body, Physics2DServer.BODY_STATE_TRANSFORM, transform2d)
# Instead of drawing each bullet individually in a script attached to each bullet,
# we are drawing *all* the bullets at once here.
func _draw():
var offset = -bullet_image.get_size() * 0.5
for bullet in bullets:
draw_texture(bullet_image, bullet.position + offset)
# Perform cleanup operations (required to exit without error messages in the console).
func _exit_tree():
for bullet in bullets:
Physics2DServer.free_rid(bullet.body)
Physics2DServer.free_rid(shape)
bullets.clear()

Binary file not shown.

After

Width:  |  Height:  |  Size: 907 B

View File

@@ -2,15 +2,15 @@
importer="texture"
type="StreamTexture"
path="res://.import/panel_rect.png-52b8de43da3f3ba3a0682eb789a33286.stex"
path="res://.import/face_happy.png-38d387d31ec13459f749c93ce3d75d80.stex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://theme/panel/panel_rect.png"
dest_files=[ "res://.import/panel_rect.png-52b8de43da3f3ba3a0682eb789a33286.stex" ]
source_file="res://face_happy.png"
dest_files=[ "res://.import/face_happy.png-38d387d31ec13459f749c93ce3d75d80.stex" ]
[params]

Binary file not shown.

After

Width:  |  Height:  |  Size: 846 B

View File

@@ -2,15 +2,15 @@
importer="texture"
type="StreamTexture"
path="res://.import/obstacle.png-303025fbfb0bdc414a247e8ee1624a90.stex"
path="res://.import/face_sad.png-0ac7165eab24f595aba17a746a66c550.stex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://grid_movement/tilesets/grid/obstacle.png"
dest_files=[ "res://.import/obstacle.png-303025fbfb0bdc414a247e8ee1624a90.stex" ]
source_file="res://face_sad.png"
dest_files=[ "res://.import/face_sad.png-0ac7165eab24f595aba17a746a66c550.stex" ]
[params]

BIN
2d/bullet_shower/icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

@@ -2,15 +2,15 @@
importer="texture"
type="StreamTexture"
path="res://.import/blue.png-1646430371c0817627bfbad8bb1bf0ab.stex"
path="res://.import/icon.png-487276ed1e3a0c39cad0279d744ee560.stex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://turn_combat/combatants/sprites/blue.png"
dest_files=[ "res://.import/blue.png-1646430371c0817627bfbad8bb1bf0ab.stex" ]
source_file="res://icon.png"
dest_files=[ "res://.import/icon.png-487276ed1e3a0c39cad0279d744ee560.stex" ]
[params]

View File

@@ -0,0 +1,33 @@
extends Node2D
# This demo is an example of controling a high number of 2D objects with logic
# and collision without using nodes in the scene. This technique is a lot more
# efficient than using instancing and nodes, but requires more programming and
# is less visual. Bullets are managed together in the `bullets.gd` script.
# The number of bullets currently touched by the player.
var touching = 0
onready var sprite = $AnimatedSprite
func _ready():
# The player follows the mouse cursor automatically, so there's no point
# in displaying the mouse cursor.
Input.set_mouse_mode(Input.MOUSE_MODE_HIDDEN)
func _input(event):
if event is InputEventMouseMotion:
position = event.position - Vector2(0, 16)
func _on_body_shape_entered(_body_id, _body, _body_shape, _local_shape):
touching += 1
if touching >= 1:
sprite.frame = 1
func _on_body_shape_exited(_body_id, _body, _body_shape, _local_shape):
touching -= 1
if touching == 0:
sprite.frame = 0

View File

@@ -0,0 +1,41 @@
; Engine configuration file.
; It's best edited using the editor UI and not directly,
; since the parameters that go here are not all obvious.
;
; Format:
; [section] ; section goes between []
; param=value ; assign values to parameters
config_version=4
_global_script_classes=[ ]
_global_script_class_icons={
}
[application]
config/name="Bullet Shower"
config/description="Demonstrates how to manage large amounts of objects efficiently using low-level Servers."
run/main_scene="res://shower.tscn"
config/icon="res://icon.png"
[display]
window/dpi/allow_hidpi=true
window/stretch/mode="2d"
window/stretch/aspect="expand"
[physics]
2d/cell_size=64
common/enable_pause_aware_picking=true
[rendering]
quality/driver/driver_name="GLES2"
quality/intended_usage/framebuffer_allocation=0
quality/intended_usage/framebuffer_allocation.mobile=0
vram_compression/import_etc=true
vram_compression/import_etc2=false
environment/default_clear_color=Color( 0.133333, 0.133333, 0.2, 1 )

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 152 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 150 KiB

View File

@@ -0,0 +1,34 @@
[gd_scene load_steps=7 format=2]
[ext_resource path="res://bullets.gd" type="Script" id=2]
[ext_resource path="res://face_happy.png" type="Texture" id=3]
[ext_resource path="res://face_sad.png" type="Texture" id=4]
[ext_resource path="res://player.gd" type="Script" id=5]
[sub_resource type="SpriteFrames" id=1]
animations = [ {
"frames": [ ExtResource( 3 ), ExtResource( 4 ) ],
"loop": true,
"name": "default",
"speed": 5.0
} ]
[sub_resource type="CircleShape2D" id=2]
radius = 27.0
[node name="Shower" type="Node2D"]
[node name="Bullets" type="Node2D" parent="."]
script = ExtResource( 2 )
[node name="Player" type="Area2D" parent="."]
script = ExtResource( 5 )
[node name="AnimatedSprite" type="AnimatedSprite" parent="Player"]
frames = SubResource( 1 )
[node name="CollisionShape2D" type="CollisionShape2D" parent="Player"]
shape = SubResource( 2 )
[connection signal="body_shape_entered" from="Player" to="Player" method="_on_body_shape_entered"]
[connection signal="body_shape_exited" from="Player" to="Player" method="_on_body_shape_exited"]

View File

@@ -53,5 +53,6 @@ text = "Start"
[node name="MessageTimer" type="Timer" parent="."]
one_shot = true
[connection signal="pressed" from="StartButton" to="." method="_on_StartButton_pressed"]
[connection signal="timeout" from="MessageTimer" to="." method="_on_MessageTimer_timeout"]

View File

@@ -44,8 +44,8 @@ func _on_MobTimer_timeout():
direction += rand_range(-PI / 4, PI / 4)
mob.rotation = direction
# Choose the velocity.
var velocity = Vector2(rand_range(mob.min_speed, mob.max_speed), 0)
# Choose the velocity for the mob.
var velocity = Vector2(rand_range(150.0, 250.0), 0.0)
mob.linear_velocity = velocity.rotated(direction)

View File

@@ -47,6 +47,7 @@ stream = ExtResource( 5 )
[node name="DeathSound" type="AudioStreamPlayer" parent="."]
stream = ExtResource( 6 )
[connection signal="hit" from="Player" to="." method="game_over"]
[connection signal="timeout" from="MobTimer" to="." method="_on_MobTimer_timeout"]
[connection signal="timeout" from="ScoreTimer" to="." method="_on_ScoreTimer_timeout"]

View File

@@ -1,9 +1,5 @@
extends RigidBody2D
#warning-ignore-all:unused_class_variable
export var min_speed = 150
export var max_speed = 250
func _ready():
$AnimatedSprite.playing = true
var mob_types = $AnimatedSprite.frames.get_animation_names()
@@ -12,7 +8,3 @@ func _ready():
func _on_VisibilityNotifier2D_screen_exited():
queue_free()
func _on_start_game():
queue_free()

View File

@@ -10,20 +10,20 @@
[sub_resource type="SpriteFrames" id=1]
animations = [ {
"frames": [ ExtResource( 4 ), ExtResource( 5 ) ],
"frames": [ ExtResource( 2 ), ExtResource( 3 ) ],
"loop": true,
"name": "walk",
"speed": 4.0
"name": "fly",
"speed": 3.0
}, {
"frames": [ ExtResource( 6 ), ExtResource( 7 ) ],
"loop": true,
"name": "swim",
"speed": 4.0
}, {
"frames": [ ExtResource( 2 ), ExtResource( 3 ) ],
"frames": [ ExtResource( 4 ), ExtResource( 5 ) ],
"loop": true,
"name": "fly",
"speed": 3.0
"name": "walk",
"speed": 4.0
} ]
[sub_resource type="CapsuleShape2D" id=2]
@@ -50,4 +50,5 @@ rotation = 1.5708
shape = SubResource( 2 )
[node name="VisibilityNotifier2D" type="VisibilityNotifier2D" parent="."]
[connection signal="screen_exited" from="VisibilityNotifier2D" to="." method="_on_VisibilityNotifier2D_screen_exited"]

View File

@@ -67,4 +67,5 @@ speed_scale = 2.0
local_coords = false
process_material = SubResource( 7 )
texture = ExtResource( 2 )
[connection signal="body_entered" from="." to="." method="_on_Player_body_entered"]

View File

@@ -14,12 +14,16 @@ Renderer: GLES 3 (particles are not available in GLES 2)
Note: There is a C# version available [here](https://github.com/godotengine/godot-demo-projects/tree/master/mono/dodge_the_creeps).
Note: There is a GDNative C++ version available [here](https://github.com/godotengine/gdnative-demos/tree/master/cpp/dodge_the_creeps).
Check out this demo on the asset library: https://godotengine.org/asset-library/asset/515
## Screenshots
![GIF from the documentation](https://docs.godotengine.org/en/latest/_images/dodge_preview.gif)
![Screenshot](screenshots/dodge.png)
## Copying
`art/House In a Forest Loop.ogg` Copyright &copy; 2012 [HorrorPen](https://opengameart.org/users/horrorpen), [CC-BY 3.0: Attribution](http://creativecommons.org/licenses/by/3.0/). Source: https://opengameart.org/content/loop-house-in-a-forest

View File

@@ -8,11 +8,6 @@
config_version=4
_global_script_classes=[ ]
_global_script_class_icons={
}
[application]
config/name="Dodge the Creeps"
@@ -29,6 +24,8 @@ config/icon="res://icon.png"
window/size/width=480
window/size/height=720
window/stretch/mode="2d"
window/stretch/aspect="keep"
[input]

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

View File

@@ -1,15 +1,50 @@
[gd_scene load_steps=5 format=2]
[gd_scene load_steps=6 format=2]
[ext_resource path="res://player/Player.tscn" type="PackedScene" id=1]
[ext_resource path="res://debug/Explanations.tscn" type="PackedScene" id=2]
[ext_resource path="res://fonts/source_code_pro_explanations.tres" type="DynamicFont" id=2]
[ext_resource path="res://debug/StatesStackDiplayer.tscn" type="PackedScene" id=3]
[ext_resource path="res://debug/ControlsPanel.tscn" type="PackedScene" id=4]
[ext_resource path="res://fonts/source_code_pro_explanations_bold.tres" type="DynamicFont" id=5]
[node name="Demo" type="Node"]
[node name="Player" parent="." instance=ExtResource( 1 )]
position = Vector2( 640, 400 )
[node name="Explanations" parent="." instance=ExtResource( 2 )]
[node name="Explanations" type="RichTextLabel" parent="."]
anchor_right = 1.0
anchor_bottom = 1.0
margin_left = 10.0
margin_top = -370.0
margin_right = -10.0
margin_bottom = -730.0
rect_clip_content = false
mouse_filter = 2
size_flags_vertical = 4
custom_fonts/bold_font = ExtResource( 5 )
custom_fonts/normal_font = ExtResource( 2 )
bbcode_enabled = true
bbcode_text = "This example shows how to apply the State programming pattern in GDScript, including Hierarchical States, and a pushdown automaton.
States are common in games. You can use the pattern to:
1. Separate each behavior and transitions between behaviors, thus make scripts shorter and easier to manage
2. Respect the Single Responsibility Principle. Each State object represents [b]one[/b] action
3. Improve your code's structure. Look at the scene tree and FileSystem tab: without looking at the code, you'll know what the Player can or cannot do.
You can read more about States in the excellent [url=http://gameprogrammingpatterns.com/state.html]Game Programming Patterns ebook[/url]."
text = "This example shows how to apply the State programming pattern in GDScript, including Hierarchical States, and a pushdown automaton.
States are common in games. You can use the pattern to:
1. Separate each behavior and transitions between behaviors, thus make scripts shorter and easier to manage
2. Respect the Single Responsibility Principle. Each State object represents one action
3. Improve your code's structure. Look at the scene tree and FileSystem tab: without looking at the code, you'll know what the Player can or cannot do.
You can read more about States in the excellent Game Programming Patterns ebook."
__meta__ = {
"_edit_lock_": true
}
[node name="Control" type="Control" parent="."]
anchor_right = 1.0

View File

@@ -7,7 +7,7 @@ func _process(_delta):
var numbers = ""
var index = 0
for state in fsm_node.states_stack:
states_names += state.get_name() + "\n"
states_names += String(state.get_name()) + "\n"
numbers += str(index) + "\n"
index += 1
$States.text = states_names

View File

@@ -41,7 +41,6 @@ use_filter = true
font_data = ExtResource( 14 )
[node name="Player" type="KinematicBody2D"]
position = Vector2( 628.826, 391.266 )
script = ExtResource( 1 )
__meta__ = {
"_edit_horizontal_guides_": [ ]
@@ -81,11 +80,11 @@ texture = ExtResource( 9 )
[node name="BodyPivot" type="Position2D" parent="."]
[node name="Body" type="Sprite" parent="BodyPivot"]
position = Vector2( 0, -58.8242 )
position = Vector2( 0, -58 )
texture = ExtResource( 10 )
[node name="BulletSpawn" type="Node2D" parent="BodyPivot"]
position = Vector2( 1.17401, -61.266 )
position = Vector2( 0, -58 )
script = ExtResource( 11 )
[node name="CooldownTimer" type="Timer" parent="BodyPivot/BulletSpawn"]
@@ -93,7 +92,7 @@ wait_time = 0.2
one_shot = true
[node name="WeaponPivot" type="Position2D" parent="BodyPivot"]
position = Vector2( 1.17401, -61.266 )
position = Vector2( 0, -58 )
script = ExtResource( 12 )
[node name="Offset" type="Position2D" parent="BodyPivot/WeaponPivot"]
@@ -110,12 +109,16 @@ margin_top = -172.0
margin_right = 110.0
margin_bottom = -138.0
custom_fonts/font = SubResource( 4 )
text = "Test"
text = "Idle"
align = 1
valign = 1
uppercase = true
script = ExtResource( 15 )
[connection signal="state_changed" from="StateMachine" to="StateNameDisplayer" method="_on_StateMachine_state_changed"]
__meta__ = {
"_edit_use_anchors_": false
}
[connection signal="state_changed" from="StateMachine" to="BodyPivot/WeaponPivot/Offset/Sword" method="_on_StateMachine_state_changed"]
[connection signal="state_changed" from="StateMachine" to="StateNameDisplayer" method="_on_StateMachine_state_changed"]
[connection signal="animation_finished" from="AnimationPlayer" to="StateMachine" method="_on_animation_finished"]
[connection signal="attack_finished" from="BodyPivot/WeaponPivot/Offset/Sword" to="StateMachine/Attack" method="_on_Sword_attack_finished"]

View File

@@ -4,14 +4,15 @@ var bullet = preload("Bullet.tscn")
func _unhandled_input(event):
if event.is_action_pressed("fire"):
fire(owner.look_direction)
fire()
func fire(direction):
func fire():
if not $CooldownTimer.is_stopped():
return
$CooldownTimer.start()
var new_bullet = bullet.instance()
new_bullet.direction = direction
add_child(new_bullet)
new_bullet.position = global_position
new_bullet.direction = owner.look_direction

View File

@@ -11,4 +11,4 @@ func _physics_process(_delta):
func _on_StateMachine_state_changed(current_state):
text = current_state.get_name()
text = String(current_state.get_name())

View File

@@ -19,7 +19,10 @@ var height = 0.0
func initialize(speed, velocity):
horizontal_speed = speed
max_horizontal_speed = speed if speed > 0.0 else base_max_horizontal_speed
if speed > 0.0:
max_horizontal_speed = speed
else:
max_horizontal_speed = base_max_horizontal_speed
enter_velocity = velocity
@@ -27,7 +30,10 @@ func enter():
var input_direction = get_input_direction()
update_look_direction(input_direction)
horizontal_velocity = enter_velocity if input_direction else Vector2()
if input_direction:
horizontal_velocity = enter_velocity
else:
horizontal_velocity = Vector2()
vertical_speed = 600.0
owner.get_node("AnimationPlayer").play("idle")

View File

@@ -22,7 +22,11 @@ func update(_delta):
emit_signal("finished", "idle")
update_look_direction(input_direction)
speed = max_run_speed if Input.is_action_pressed("run") else max_walk_speed
if Input.is_action_pressed("run"):
speed = max_run_speed
else:
speed = max_walk_speed
var collision_info = move(speed, input_direction)
if not collision_info:
return

View File

@@ -8,11 +8,6 @@
config_version=4
_global_script_classes=[ ]
_global_script_class_icons={
}
[application]
config/name="Hierarchical Finite State Machine"
@@ -102,3 +97,5 @@ attack={
[rendering]
quality/driver/driver_name="GLES2"
vram_compression/import_etc=true
vram_compression/import_etc2=false

View File

@@ -8,11 +8,6 @@
config_version=4
_global_script_classes=[ ]
_global_script_class_icons={
}
[application]
config/name="GD Paint"
@@ -37,3 +32,5 @@ singletons=[ ]
[rendering]
quality/driver/driver_name="GLES2"
vram_compression/import_etc=true
vram_compression/import_etc2=false

View File

@@ -8,11 +8,6 @@
config_version=4
_global_script_classes=[ ]
_global_script_class_icons={
}
[application]
config/name="HDR for 2D"

View File

@@ -8,11 +8,6 @@
config_version=4
_global_script_classes=[ ]
_global_script_class_icons={
}
[application]
config/name="Hexagonal Game"
@@ -68,4 +63,6 @@ move_up={
[rendering]
quality/driver/driver_name="GLES2"
vram_compression/import_etc=true
vram_compression/import_etc2=false
environment/default_clear_color=Color( 0.172549, 0.219608, 0.129412, 1 )

View File

@@ -8,11 +8,6 @@
config_version=4
_global_script_classes=[ ]
_global_script_class_icons={
}
[application]
config/name="Scene Instancing Demo"
@@ -39,4 +34,6 @@ singletons=[ ]
[rendering]
quality/driver/driver_name="GLES2"
vram_compression/import_etc=true
vram_compression/import_etc2=false
environment/default_clear_color=Color( 0.301961, 0.301961, 0.301961, 1 )

View File

@@ -8,11 +8,6 @@
config_version=4
_global_script_classes=[ ]
_global_script_class_icons={
}
[application]
config/name="Isometric Game"
@@ -80,4 +75,6 @@ use_pixel_snap=true
[rendering]
quality/driver/driver_name="GLES2"
vram_compression/import_etc=true
vram_compression/import_etc2=false
environment/default_clear_color=Color( 0.0784314, 0.105882, 0.145098, 1 )

View File

@@ -8,11 +8,6 @@
config_version=4
_global_script_classes=[ ]
_global_script_class_icons={
}
[application]
config/name="Kinematic Character 2D"
@@ -76,4 +71,6 @@ multithread/thread_rid_pool_prealloc=60
[rendering]
quality/driver/driver_name="GLES2"
vram_compression/import_etc=true
vram_compression/import_etc2=false
environment/default_clear_color=Color( 0.156, 0.1325, 0.25, 1 )

View File

@@ -266,4 +266,5 @@ shape = SubResource( 12 )
[node name="Camera2D" type="Camera2D" parent="."]
offset = Vector2( 265, 247 )
current = true
[connection signal="body_entered" from="Princess" to="Princess" method="_on_body_entered"]

View File

@@ -8,11 +8,6 @@
config_version=4
_global_script_classes=[ ]
_global_script_class_icons={
}
[application]
config/name="2D Lights as Mask"
@@ -37,3 +32,5 @@ shadow_filter=3
[rendering]
quality/driver/driver_name="GLES2"
vram_compression/import_etc=true
vram_compression/import_etc2=false

View File

@@ -8,11 +8,6 @@
config_version=4
_global_script_classes=[ ]
_global_script_class_icons={
}
[application]
config/name="2D Lights and Shadows"
@@ -41,3 +36,5 @@ shadow_filter=2
[rendering]
quality/driver/driver_name="GLES2"
vram_compression/import_etc=true
vram_compression/import_etc2=false

View File

@@ -8,11 +8,6 @@
config_version=4
_global_script_classes=[ ]
_global_script_class_icons={
}
[application]
config/name="Navigation Polygon 2D"
@@ -46,4 +41,6 @@ click={
[rendering]
quality/driver/driver_name="GLES2"
vram_compression/import_etc=true
vram_compression/import_etc2=false
environment/default_clear_color=Color( 0.160784, 0.172549, 0.278431, 1 )

View File

@@ -6,7 +6,7 @@ const MASS = 10.0
const ARRIVE_DISTANCE = 10.0
export(float) var speed = 200.0
var _state = null
var _state = States.IDLE
var _path = []
var _target_point_world = Vector2()

View File

@@ -8,11 +8,6 @@
config_version=4
_global_script_classes=[ ]
_global_script_class_icons={
}
[application]
config/name="Grid-based Pathfinding with Astar"
@@ -38,3 +33,5 @@ click={
[rendering]
quality/driver/driver_name="GLES2"
vram_compression/import_etc=true
vram_compression/import_etc2=false

View File

@@ -19,11 +19,11 @@ _data = [ Vector2( 0, 1 ), 0.0, 0.0, 0, 0, Vector2( 1, 85.0781 ), 0.0, 0.0, 0, 0
[sub_resource type="CurveTexture" id=3]
curve = SubResource( 2 )
[sub_resource type="Curve" id=31]
[sub_resource type="Curve" id=4]
_data = [ Vector2( 0, 1 ), 0.0, 0.0, 0, 0, Vector2( 1, 0 ), 0.0, 0.0, 0, 0 ]
[sub_resource type="CurveTexture" id=5]
curve = SubResource( 31 )
curve = SubResource( 4 )
[sub_resource type="ParticlesMaterial" id=6]
emission_shape = 1

View File

@@ -8,11 +8,6 @@
config_version=4
_global_script_classes=[ ]
_global_script_class_icons={
}
[application]
config/name="2D Particles"

View File

@@ -142,4 +142,5 @@ texture = ExtResource( 4 )
[node name="Enabler" type="VisibilityEnabler2D" parent="."]
rect = Rect2( -5, -5, 10, 10 )
pause_particles = false
[connection signal="body_entered" from="." to="." method="_on_body_enter"]

View File

@@ -83,4 +83,5 @@ one_shot = true
[node name="AnimationPlayer" type="AnimationPlayer" parent="."]
anims/shutdown = SubResource( 4 )
[connection signal="timeout" from="Timer" to="." method="disable"]

View File

@@ -215,8 +215,8 @@ script = ExtResource( 1 )
[node name="Sprite" type="Sprite" parent="."]
texture = ExtResource( 2 )
vframes = 2
hframes = 16
vframes = 2
[node name="Smoke" type="Particles2D" parent="Sprite"]
self_modulate = Color( 1, 1, 1, 0.26702 )

View File

@@ -156,10 +156,11 @@ mipmap_policy=1
quality/intended_usage/framebuffer_allocation=0
quality/intended_usage/framebuffer_allocation.mobile=1
quality/2d/use_pixel_snap=true
2d/snapping/use_gpu_pixel_snap=true
quality/filters/anisotropic_filter_level=2
quality/filters/use_nearest_mipmap_filter=true
quality/depth/hdr=false
quality/2d/use_pixel_snap=true
[texture_import]

View File

@@ -0,0 +1,21 @@
# 2D Physics Tests
This demo contains a series of tests for the 2D
physics engine.
They can be used for different purpose:
- Functional tests to check for regressions and
behavior of the 2D physics engine
- Performance tests to evaluate performance
of the 2D physics engine
Language: GDScript
Renderer: GLES 2
Check out this demo on the asset library: https://godotengine.org/asset-library/asset/888
## Screenshots
![Screenshot](screenshots/screenshot.png)

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

View File

@@ -0,0 +1,34 @@
[remap]
importer="texture"
type="StreamTexture"
path="res://.import/godot-head.png-6a90da7ab6a8c80b4170f240c8e33e70.stex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://assets/texture/godot-head.png"
dest_files=[ "res://.import/godot-head.png-6a90da7ab6a8c80b4170f240c8e33e70.stex" ]
[params]
compress/mode=0
compress/lossy_quality=0.7
compress/hdr_mode=0
compress/bptc_ldr=0
compress/normal_map=0
flags/repeat=0
flags/filter=true
flags/mipmaps=false
flags/anisotropic=false
flags/srgb=2
process/fix_alpha_border=true
process/premult_alpha=false
process/HDR_as_SRGB=false
process/invert_color=false
stream=false
size_limit=0
detect_3d=true
svg/scale=1.0

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

View File

@@ -0,0 +1,34 @@
[remap]
importer="texture"
type="StreamTexture"
path="res://.import/tiles_demo.png-4d398d5cc02bc85a2809dc13fbc9a3c2.stex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://assets/tileset/tiles_demo.png"
dest_files=[ "res://.import/tiles_demo.png-4d398d5cc02bc85a2809dc13fbc9a3c2.stex" ]
[params]
compress/mode=0
compress/lossy_quality=0.7
compress/hdr_mode=0
compress/bptc_ldr=0
compress/normal_map=0
flags/repeat=0
flags/filter=true
flags/mipmaps=false
flags/anisotropic=false
flags/srgb=2
process/fix_alpha_border=true
process/premult_alpha=false
process/HDR_as_SRGB=false
process/invert_color=false
stream=false
size_limit=0
detect_3d=true
svg/scale=1.0

View File

@@ -0,0 +1,335 @@
[gd_resource type="TileSet" load_steps=14 format=2]
[ext_resource path="res://assets/tileset/tiles_demo.png" type="Texture" id=1]
[sub_resource type="ConvexPolygonShape2D" id=1]
points = PoolVector2Array( 0, 6, 32, 6, 32, 32, 0, 32 )
[sub_resource type="ConvexPolygonShape2D" id=2]
points = PoolVector2Array( 0, 6, 28, 6, 28, 32, 0, 32 )
[sub_resource type="ConvexPolygonShape2D" id=3]
points = PoolVector2Array( 0, 0, 32, 0, 32, 32, 0, 32 )
[sub_resource type="ConvexPolygonShape2D" id=4]
points = PoolVector2Array( 0, 6, 32, 6, 32, 32, 0, 32 )
[sub_resource type="ConvexPolygonShape2D" id=5]
points = PoolVector2Array( 32, 38, 32, 64, 0, 64, 0, 6 )
[sub_resource type="ConvexPolygonShape2D" id=6]
points = PoolVector2Array( 0, 0, 28, 0, 28, 32, 0, 32 )
[sub_resource type="ConvexPolygonShape2D" id=7]
points = PoolVector2Array( 28, 6, 32, 6, 32, 32, 0, 32, 0, 0, 28, 0 )
[sub_resource type="ConvexPolygonShape2D" id=8]
points = PoolVector2Array( 0, 6, 32, 6, 32, 32, 0, 32 )
[sub_resource type="ConvexPolygonShape2D" id=9]
points = PoolVector2Array( 0, 6, 28, 6, 28, 32, 0, 32 )
[sub_resource type="ConvexPolygonShape2D" id=10]
points = PoolVector2Array( 0, 0, 32, 0, 32, 32, 0, 32 )
[sub_resource type="ConvexPolygonShape2D" id=11]
points = PoolVector2Array( 0, 0, 32, 0, 32, 24, 0, 24 )
[sub_resource type="ConvexPolygonShape2D" id=12]
points = PoolVector2Array( 0, 0, 28, 0, 28, 24, 0, 24 )
[resource]
0/name = "ground"
0/texture = ExtResource( 1 )
0/tex_offset = Vector2( 0, 0 )
0/modulate = Color( 0, 0, 1, 1 )
0/region = Rect2( 0, 0, 32, 32 )
0/tile_mode = 0
0/occluder_offset = Vector2( 0, 0 )
0/navigation_offset = Vector2( 0, 0 )
0/shape_offset = Vector2( 0, 0 )
0/shape_transform = Transform2D( 1, 0, 0, 1, 0, 0 )
0/shape = SubResource( 1 )
0/shape_one_way = false
0/shape_one_way_margin = 1.0
0/shapes = [ {
"autotile_coord": Vector2( 0, 0 ),
"one_way": false,
"one_way_margin": 1.0,
"shape": SubResource( 1 ),
"shape_transform": Transform2D( 1, 0, 0, 1, 0, 0 )
} ]
0/z_index = 0
1/name = "ground_end"
1/texture = ExtResource( 1 )
1/tex_offset = Vector2( 0, 0 )
1/modulate = Color( 1, 1, 1, 1 )
1/region = Rect2( 32, 0, 32, 32 )
1/tile_mode = 0
1/occluder_offset = Vector2( 0, 0 )
1/navigation_offset = Vector2( 0, 0 )
1/shape_offset = Vector2( 0, 0 )
1/shape_transform = Transform2D( 1, 0, 0, 1, 0, 0 )
1/shape = SubResource( 2 )
1/shape_one_way = false
1/shape_one_way_margin = 1.0
1/shapes = [ {
"autotile_coord": Vector2( 0, 0 ),
"one_way": false,
"one_way_margin": 1.0,
"shape": SubResource( 2 ),
"shape_transform": Transform2D( 1, 0, 0, 1, 0, 0 )
} ]
1/z_index = 0
2/name = "slope"
2/texture = ExtResource( 1 )
2/tex_offset = Vector2( 0, 0 )
2/modulate = Color( 1, 1, 1, 1 )
2/region = Rect2( 64, 64, 32, 64 )
2/tile_mode = 0
2/occluder_offset = Vector2( 0, 0 )
2/navigation_offset = Vector2( 0, 0 )
2/shape_offset = Vector2( 0, 0 )
2/shape_transform = Transform2D( 1, 0, 0, 1, 0, 0 )
2/shape = SubResource( 5 )
2/shape_one_way = false
2/shape_one_way_margin = 1.0
2/shapes = [ {
"autotile_coord": Vector2( 0, 0 ),
"one_way": false,
"one_way_margin": 1.0,
"shape": SubResource( 5 ),
"shape_transform": Transform2D( 1, 0, 0, 1, 0, 0 )
} ]
2/z_index = 0
3/name = "wall"
3/texture = ExtResource( 1 )
3/tex_offset = Vector2( 0, 0 )
3/modulate = Color( 1, 1, 1, 1 )
3/region = Rect2( 32, 32, 32, 32 )
3/tile_mode = 0
3/occluder_offset = Vector2( 0, 0 )
3/navigation_offset = Vector2( 0, 0 )
3/shape_offset = Vector2( 0, 0 )
3/shape_transform = Transform2D( 1, 0, 0, 1, 0, 0 )
3/shape = SubResource( 6 )
3/shape_one_way = false
3/shape_one_way_margin = 1.0
3/shapes = [ {
"autotile_coord": Vector2( 0, 0 ),
"one_way": false,
"one_way_margin": 1.0,
"shape": SubResource( 6 ),
"shape_transform": Transform2D( 1, 0, 0, 1, 0, 0 )
} ]
3/z_index = 0
4/name = "slope_top"
4/texture = ExtResource( 1 )
4/tex_offset = Vector2( 0, 0 )
4/modulate = Color( 1, 1, 1, 1 )
4/region = Rect2( 32, 64, 32, 32 )
4/tile_mode = 0
4/occluder_offset = Vector2( 0, 0 )
4/navigation_offset = Vector2( 0, 0 )
4/shape_offset = Vector2( 0, 0 )
4/shape_transform = Transform2D( 1, 0, 0, 1, 0, 0 )
4/shape = SubResource( 7 )
4/shape_one_way = false
4/shape_one_way_margin = 1.0
4/shapes = [ {
"autotile_coord": Vector2( 0, 0 ),
"one_way": false,
"one_way_margin": 1.0,
"shape": SubResource( 7 ),
"shape_transform": Transform2D( 1, 0, 0, 1, 0, 0 )
} ]
4/z_index = 0
5/name = "one_way"
5/texture = ExtResource( 1 )
5/tex_offset = Vector2( 0, 0 )
5/modulate = Color( 1, 1, 1, 1 )
5/region = Rect2( 64, 0, 32, 32 )
5/tile_mode = 0
5/occluder_offset = Vector2( 0, 0 )
5/navigation_offset = Vector2( 0, 0 )
5/shape_offset = Vector2( 0, 0 )
5/shape_transform = Transform2D( 1, 0, 0, 1, 0, 0 )
5/shape = SubResource( 8 )
5/shape_one_way = true
5/shape_one_way_margin = 1.0
5/shapes = [ {
"autotile_coord": Vector2( 0, 0 ),
"one_way": true,
"one_way_margin": 1.0,
"shape": SubResource( 8 ),
"shape_transform": Transform2D( 1, 0, 0, 1, 0, 0 )
} ]
5/z_index = 0
6/name = "one_way_end"
6/texture = ExtResource( 1 )
6/tex_offset = Vector2( 0, 0 )
6/modulate = Color( 1, 1, 1, 1 )
6/region = Rect2( 96, 0, 32, 32 )
6/tile_mode = 0
6/occluder_offset = Vector2( 0, 0 )
6/navigation_offset = Vector2( 0, 0 )
6/shape_offset = Vector2( 0, 0 )
6/shape_transform = Transform2D( 1, 0, 0, 1, 0, 0 )
6/shape = SubResource( 9 )
6/shape_one_way = true
6/shape_one_way_margin = 1.0
6/shapes = [ {
"autotile_coord": Vector2( 0, 0 ),
"one_way": true,
"one_way_margin": 1.0,
"shape": SubResource( 9 ),
"shape_transform": Transform2D( 1, 0, 0, 1, 0, 0 )
} ]
6/z_index = 0
7/name = "rock"
7/texture = ExtResource( 1 )
7/tex_offset = Vector2( 0, 0 )
7/modulate = Color( 1, 1, 1, 1 )
7/region = Rect2( 0, 32, 32, 32 )
7/tile_mode = 0
7/occluder_offset = Vector2( 0, 0 )
7/navigation_offset = Vector2( 0, 0 )
7/shape_offset = Vector2( 0, 0 )
7/shape_transform = Transform2D( 1, 0, 0, 1, 0, 0 )
7/shape = SubResource( 10 )
7/shape_one_way = false
7/shape_one_way_margin = 1.0
7/shapes = [ {
"autotile_coord": Vector2( 0, 0 ),
"one_way": false,
"one_way_margin": 1.0,
"shape": SubResource( 10 ),
"shape_transform": Transform2D( 1, 0, 0, 1, 0, 0 )
} ]
7/z_index = 0
8/name = "bottom"
8/texture = ExtResource( 1 )
8/tex_offset = Vector2( 0, 0 )
8/modulate = Color( 1, 1, 1, 1 )
8/region = Rect2( 192, 32, 32, 32 )
8/tile_mode = 0
8/occluder_offset = Vector2( 0, 0 )
8/navigation_offset = Vector2( 0, 0 )
8/shape_offset = Vector2( 0, 0 )
8/shape_transform = Transform2D( 1, 0, 0, 1, 0, 0 )
8/shape = SubResource( 11 )
8/shape_one_way = false
8/shape_one_way_margin = 1.0
8/shapes = [ {
"autotile_coord": Vector2( 0, 0 ),
"one_way": false,
"one_way_margin": 1.0,
"shape": SubResource( 11 ),
"shape_transform": Transform2D( 1, 0, 0, 1, 0, 0 )
} ]
8/z_index = 0
9/name = "bottom_end"
9/texture = ExtResource( 1 )
9/tex_offset = Vector2( 0, 0 )
9/modulate = Color( 1, 1, 1, 1 )
9/region = Rect2( 224, 32, 32, 32 )
9/tile_mode = 0
9/occluder_offset = Vector2( 0, 0 )
9/navigation_offset = Vector2( 0, 0 )
9/shape_offset = Vector2( 0, 0 )
9/shape_transform = Transform2D( 1, 0, 0, 1, 0, 0 )
9/shape = SubResource( 12 )
9/shape_one_way = false
9/shape_one_way_margin = 1.0
9/shapes = [ {
"autotile_coord": Vector2( 0, 0 ),
"one_way": false,
"one_way_margin": 1.0,
"shape": SubResource( 12 ),
"shape_transform": Transform2D( 1, 0, 0, 1, 0, 0 )
} ]
9/z_index = 0
10/name = "bottom_corner"
10/texture = ExtResource( 1 )
10/tex_offset = Vector2( 0, 0 )
10/modulate = Color( 1, 1, 1, 1 )
10/region = Rect2( 160, 32, 32, 32 )
10/tile_mode = 0
10/occluder_offset = Vector2( 0, 0 )
10/navigation_offset = Vector2( 0, 0 )
10/shape_offset = Vector2( 0, 0 )
10/shape_transform = Transform2D( 1, 0, 0, 1, 0, 0 )
10/shape = SubResource( 3 )
10/shape_one_way = false
10/shape_one_way_margin = 1.0
10/shapes = [ {
"autotile_coord": Vector2( 0, 0 ),
"one_way": false,
"one_way_margin": 1.0,
"shape": SubResource( 3 ),
"shape_transform": Transform2D( 1, 0, 0, 1, 0, 0 )
} ]
10/z_index = 0
11/name = "tree_trunk_0"
11/texture = ExtResource( 1 )
11/tex_offset = Vector2( 0, 0 )
11/modulate = Color( 1, 1, 1, 1 )
11/region = Rect2( 128, 64, 32, 32 )
11/tile_mode = 0
11/occluder_offset = Vector2( 0, 0 )
11/navigation_offset = Vector2( 0, 0 )
11/shape_offset = Vector2( 0, 0 )
11/shape_transform = Transform2D( 1, 0, 0, 1, 0, 0 )
11/shape_one_way = false
11/shape_one_way_margin = 0.0
11/shapes = [ ]
11/z_index = 0
12/name = "tree_trunk_1"
12/texture = ExtResource( 1 )
12/tex_offset = Vector2( 0, 0 )
12/modulate = Color( 1, 1, 1, 1 )
12/region = Rect2( 128, 32, 32, 32 )
12/tile_mode = 0
12/occluder_offset = Vector2( 0, 0 )
12/navigation_offset = Vector2( 0, 0 )
12/shape_offset = Vector2( 0, 0 )
12/shape_transform = Transform2D( 1, 0, 0, 1, 0, 0 )
12/shape_one_way = false
12/shape_one_way_margin = 0.0
12/shapes = [ ]
12/z_index = 0
13/name = "tree_base"
13/texture = ExtResource( 1 )
13/tex_offset = Vector2( 0, 0 )
13/modulate = Color( 1, 1, 1, 1 )
13/region = Rect2( 128, 96, 32, 32 )
13/tile_mode = 0
13/occluder_offset = Vector2( 0, 0 )
13/navigation_offset = Vector2( 0, 0 )
13/shape_offset = Vector2( 0, 0 )
13/shape_transform = Transform2D( 1, 0, 0, 1, 0, 0 )
13/shape = SubResource( 4 )
13/shape_one_way = false
13/shape_one_way_margin = 1.0
13/shapes = [ {
"autotile_coord": Vector2( 0, 0 ),
"one_way": false,
"one_way_margin": 1.0,
"shape": SubResource( 4 ),
"shape_transform": Transform2D( 1, 0, 0, 1, 0, 0 )
} ]
13/z_index = 0
14/name = "tree_top"
14/texture = ExtResource( 1 )
14/tex_offset = Vector2( 0, 0 )
14/modulate = Color( 1, 1, 1, 1 )
14/region = Rect2( 128, 0, 32, 32 )
14/tile_mode = 0
14/occluder_offset = Vector2( 0, 0 )
14/navigation_offset = Vector2( 0, 0 )
14/shape_offset = Vector2( 0, 0 )
14/shape_transform = Transform2D( 1, 0, 0, 1, 0, 0 )
14/shape_one_way = false
14/shape_one_way_margin = 0.0
14/shapes = [ ]
14/z_index = 0

BIN
2d/physics_tests/icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

View File

@@ -0,0 +1,34 @@
[remap]
importer="texture"
type="StreamTexture"
path="res://.import/icon.png-487276ed1e3a0c39cad0279d744ee560.stex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://icon.png"
dest_files=[ "res://.import/icon.png-487276ed1e3a0c39cad0279d744ee560.stex" ]
[params]
compress/mode=0
compress/lossy_quality=0.7
compress/hdr_mode=0
compress/bptc_ldr=0
compress/normal_map=0
flags/repeat=0
flags/filter=true
flags/mipmaps=false
flags/anisotropic=false
flags/srgb=2
process/fix_alpha_border=true
process/premult_alpha=false
process/HDR_as_SRGB=false
process/invert_color=false
stream=false
size_limit=0
detect_3d=true
svg/scale=1.0

198
2d/physics_tests/main.tscn Normal file
View File

@@ -0,0 +1,198 @@
[gd_scene load_steps=11 format=2]
[ext_resource path="res://utils/label_fps.gd" type="Script" id=1]
[ext_resource path="res://utils/label_version.gd" type="Script" id=2]
[ext_resource path="res://utils/label_engine.gd" type="Script" id=3]
[ext_resource path="res://tests_menu.gd" type="Script" id=4]
[ext_resource path="res://utils/label_test.gd" type="Script" id=5]
[ext_resource path="res://utils/label_pause.gd" type="Script" id=6]
[ext_resource path="res://utils/container_log.gd" type="Script" id=10]
[ext_resource path="res://utils/scroll_log.gd" type="Script" id=11]
[ext_resource path="res://tests.gd" type="Script" id=12]
[sub_resource type="StyleBoxFlat" id=1]
bg_color = Color( 0, 0, 0, 0.176471 )
[node name="Main" type="Control"]
anchor_right = 1.0
anchor_bottom = 1.0
mouse_filter = 2
script = ExtResource( 12 )
__meta__ = {
"_edit_use_anchors_": false
}
[node name="TestsMenu" type="MenuButton" parent="."]
pause_mode = 2
margin_left = 10.0
margin_top = 10.0
margin_right = 125.0
margin_bottom = 30.0
text = "TESTS"
flat = false
script = ExtResource( 4 )
__meta__ = {
"_edit_use_anchors_": false
}
[node name="LabelControls" type="Label" parent="."]
pause_mode = 2
margin_left = 157.0
margin_top = 13.0
margin_right = 646.0
margin_bottom = 27.0
text = "P - TOGGLE PAUSE / R - RESTART / C - TOGGLE COLLISION / F - TOGGLE FULL SCREEN / ESC - QUIT"
__meta__ = {
"_edit_use_anchors_": false
}
[node name="LabelFPS" type="Label" parent="."]
pause_mode = 2
anchor_top = 1.0
anchor_bottom = 1.0
margin_left = 10.0
margin_top = -19.0
margin_right = 50.0
margin_bottom = -5.0
text = "FPS: 0"
script = ExtResource( 1 )
__meta__ = {
"_edit_use_anchors_": false
}
[node name="LabelEngine" type="Label" parent="."]
pause_mode = 2
anchor_top = 1.0
anchor_bottom = 1.0
margin_left = 10.0
margin_top = -39.0
margin_right = 50.0
margin_bottom = -25.0
text = "Physics engine:"
script = ExtResource( 3 )
__meta__ = {
"_edit_use_anchors_": false
}
[node name="LabelVersion" type="Label" parent="."]
pause_mode = 2
anchor_top = 1.0
anchor_bottom = 1.0
margin_left = 10.0
margin_top = -59.0
margin_right = 50.0
margin_bottom = -45.0
text = "Godot Version:"
script = ExtResource( 2 )
__meta__ = {
"_edit_use_anchors_": false
}
[node name="LabelTest" type="Label" parent="."]
pause_mode = 2
anchor_top = 1.0
anchor_bottom = 1.0
margin_left = 10.0
margin_top = -79.0
margin_right = 50.0
margin_bottom = -65.0
text = "Test:"
script = ExtResource( 5 )
__meta__ = {
"_edit_use_anchors_": false
}
[node name="LabelPause" type="Label" parent="."]
pause_mode = 2
anchor_left = 0.5
anchor_top = 1.0
anchor_right = 0.5
anchor_bottom = 1.0
margin_left = -20.0
margin_top = -40.9695
margin_right = 31.0
margin_bottom = -26.9695
text = "PAUSED"
script = ExtResource( 6 )
__meta__ = {
"_edit_use_anchors_": false
}
[node name="PanelLog" type="Panel" parent="."]
pause_mode = 2
anchor_left = 1.0
anchor_top = 1.0
anchor_right = 1.0
anchor_bottom = 1.0
margin_left = -428.0
margin_top = -125.0
custom_styles/panel = SubResource( 1 )
__meta__ = {
"_edit_use_anchors_": false
}
[node name="ButtonClear" type="Button" parent="PanelLog"]
anchor_left = 1.0
anchor_top = 1.0
anchor_right = 1.0
anchor_bottom = 1.0
margin_left = -48.0
margin_top = -25.0
margin_right = -5.0
margin_bottom = -5.0
focus_mode = 0
text = "clear"
__meta__ = {
"_edit_use_anchors_": false
}
[node name="CheckBoxScroll" type="CheckBox" parent="PanelLog"]
anchor_left = 1.0
anchor_top = 1.0
anchor_right = 1.0
anchor_bottom = 1.0
margin_left = -150.0
margin_top = -27.0
margin_right = -54.0
margin_bottom = -3.0
focus_mode = 0
pressed = true
text = "auto-scroll"
__meta__ = {
"_edit_use_anchors_": false
}
[node name="ScrollLog" type="ScrollContainer" parent="PanelLog"]
margin_left = 10.0
margin_top = 5.0
margin_right = 418.0
margin_bottom = 94.0
scroll_horizontal_enabled = false
script = ExtResource( 11 )
__meta__ = {
"_edit_use_anchors_": false
}
auto_scroll = true
[node name="VBoxLog" type="VBoxContainer" parent="PanelLog/ScrollLog"]
margin_right = 408.0
margin_bottom = 89.0
size_flags_horizontal = 3
size_flags_vertical = 3
alignment = 2
script = ExtResource( 10 )
[node name="LabelLog" type="Label" parent="PanelLog/ScrollLog/VBoxLog"]
margin_top = 75.0
margin_right = 408.0
margin_bottom = 89.0
text = "Log start"
valign = 2
autowrap = true
max_lines_visible = 5
__meta__ = {
"_edit_use_anchors_": false
}
[connection signal="pressed" from="PanelLog/ButtonClear" to="PanelLog/ScrollLog/VBoxLog" method="clear"]
[connection signal="toggled" from="PanelLog/CheckBoxScroll" to="PanelLog/ScrollLog" method="set_auto_scroll"]

View File

@@ -0,0 +1,132 @@
; Engine configuration file.
; It's best edited using the editor UI and not directly,
; since the parameters that go here are not all obvious.
;
; Format:
; [section] ; section goes between []
; param=value ; assign values to parameters
config_version=4
_global_script_classes=[ {
"base": "MenuButton",
"class": "OptionMenu",
"language": "GDScript",
"path": "res://utils/option_menu.gd"
}, {
"base": "Node2D",
"class": "Test",
"language": "GDScript",
"path": "res://test.gd"
}, {
"base": "Test",
"class": "TestCharacter",
"language": "GDScript",
"path": "res://tests/functional/test_character.gd"
} ]
_global_script_class_icons={
"OptionMenu": "",
"Test": "",
"TestCharacter": ""
}
[application]
config/name="2D Physics Tests"
config/description="This demo contains a series of tests for the 2D physics engine.
They can be used for different purpose:
- Functional tests to check for regressions and behavior of the 2D physics engine
- Performance tests to evaluate performance of the 2D physics engine"
run/main_scene="res://main.tscn"
config/icon="res://icon.png"
[autoload]
Log="*res://utils/system_log.gd"
System="*res://utils/system.gd"
[debug]
gdscript/warnings/return_value_discarded=false
[display]
window/dpi/allow_hidpi=true
window/stretch/mode="2d"
window/stretch/aspect="expand"
[input]
ui_left={
"deadzone": 0.5,
"events": [ ]
}
ui_right={
"deadzone": 0.5,
"events": [ ]
}
ui_up={
"deadzone": 0.5,
"events": [ ]
}
ui_down={
"deadzone": 0.5,
"events": [ ]
}
toggle_full_screen={
"deadzone": 0.5,
"events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":70,"unicode":0,"echo":false,"script":null)
]
}
exit={
"deadzone": 0.5,
"events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":16777217,"unicode":0,"echo":false,"script":null)
]
}
toggle_debug_collision={
"deadzone": 0.5,
"events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":67,"unicode":0,"echo":false,"script":null)
]
}
restart_test={
"deadzone": 0.5,
"events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":82,"unicode":0,"echo":false,"script":null)
]
}
toggle_pause={
"deadzone": 0.5,
"events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":80,"unicode":0,"echo":false,"script":null)
]
}
character_left={
"deadzone": 0.5,
"events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":16777231,"unicode":0,"echo":false,"script":null)
, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":65,"unicode":0,"echo":false,"script":null)
]
}
character_right={
"deadzone": 0.5,
"events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":16777233,"unicode":0,"echo":false,"script":null)
, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":68,"unicode":0,"echo":false,"script":null)
]
}
character_jump={
"deadzone": 0.5,
"events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":16777232,"unicode":0,"echo":false,"script":null)
, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":87,"unicode":0,"echo":false,"script":null)
]
}
[memory]
limits/message_queue/max_size_kb=10240
[rendering]
quality/driver/driver_name="GLES2"
vram_compression/import_etc=true
vram_compression/import_etc2=false
environment/default_clear_color=Color( 0.184314, 0.184314, 0.184314, 1 )
quality/filters/msaa=2

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 162 KiB

134
2d/physics_tests/test.gd Normal file
View File

@@ -0,0 +1,134 @@
class_name Test
extends Node2D
signal wait_done()
export var _enable_debug_collision = true
var _timer
var _timer_started = false
var _wait_physics_ticks_counter = 0
class Circle2D:
extends Node2D
var center
var radius
var color
func _draw():
draw_circle(center, radius, color)
var _drawn_nodes = []
func _enter_tree():
if not _enable_debug_collision:
get_tree().debug_collisions_hint = false
func _physics_process(_delta):
if _wait_physics_ticks_counter > 0:
_wait_physics_ticks_counter -= 1
if _wait_physics_ticks_counter == 0:
emit_signal("wait_done")
func add_line(pos_start, pos_end, color):
var line = Line2D.new()
line.points = [pos_start, pos_end]
line.width = 1.5
line.default_color = color
_drawn_nodes.push_back(line)
add_child(line)
func add_circle(pos, radius, color):
var circle = Circle2D.new()
circle.center = pos
circle.radius = radius
circle.color = color
_drawn_nodes.push_back(circle)
add_child(circle)
func add_shape(shape, transform, color):
var collision = CollisionShape2D.new()
collision.shape = shape
collision.transform = transform
collision.modulate = color
_drawn_nodes.push_back(collision)
add_child(collision)
func clear_drawn_nodes():
for node in _drawn_nodes:
node.queue_free()
_drawn_nodes.clear()
func create_rigidbody(shape, pickable = false, transform = Transform.IDENTITY):
var collision = CollisionShape2D.new()
collision.shape = shape
collision.transform = transform
var body = RigidBody2D.new()
body.add_child(collision)
if pickable:
var script = load("res://utils/rigidbody_pick.gd")
body.set_script(script)
return body
func create_rigidbody_box(size, pickable = false, use_icon = false, transform = Transform.IDENTITY):
var shape = RectangleShape2D.new()
shape.extents = 0.5 * size
var body = create_rigidbody(shape, pickable, transform)
if use_icon:
var texture = load("res://icon.png")
var icon = Sprite.new()
icon.texture = texture
icon.scale = size / texture.get_size()
body.add_child(icon)
return body
func start_timer(timeout):
if _timer == null:
_timer = Timer.new()
_timer.one_shot = true
add_child(_timer)
_timer.connect("timeout", self, "_on_timer_done")
else:
cancel_timer()
_timer.start(timeout)
_timer_started = true
return _timer
func cancel_timer():
if _timer_started:
_timer.paused = true
_timer.emit_signal("timeout")
_timer.paused = false
func is_timer_canceled():
return _timer and _timer.paused
func wait_for_physics_ticks(tick_count):
_wait_physics_ticks_counter = tick_count
return self
func _on_timer_done():
_timer_started = false

63
2d/physics_tests/tests.gd Normal file
View File

@@ -0,0 +1,63 @@
extends Node
var _tests = [
{
"id": "Functional Tests/Shapes",
"path": "res://tests/functional/test_shapes.tscn",
},
{
"id": "Functional Tests/Box Stack",
"path": "res://tests/functional/test_stack.tscn",
},
{
"id": "Functional Tests/Box Pyramid",
"path": "res://tests/functional/test_pyramid.tscn",
},
{
"id": "Functional Tests/Collision Pairs",
"path": "res://tests/functional/test_collision_pairs.tscn",
},
{
"id": "Functional Tests/Character - Slopes",
"path": "res://tests/functional/test_character_slopes.tscn",
},
{
"id": "Functional Tests/Character - Tilemap",
"path": "res://tests/functional/test_character_tilemap.tscn",
},
{
"id": "Functional Tests/Character - Pixels",
"path": "res://tests/functional/test_character_pixels.tscn",
},
{
"id": "Functional Tests/One Way Collision",
"path": "res://tests/functional/test_one_way_collision.tscn",
},
{
"id": "Functional Tests/Joints",
"path": "res://tests/functional/test_joints.tscn",
},
{
"id": "Functional Tests/Raycasting",
"path": "res://tests/functional/test_raycasting.tscn",
},
{
"id": "Performance Tests/Broadphase",
"path": "res://tests/performance/test_perf_broadphase.tscn",
},
{
"id": "Performance Tests/Contacts",
"path": "res://tests/performance/test_perf_contacts.tscn",
},
{
"id" : "Performance Tests/Contact Islands",
"path" : "res://tests/performance/test_perf_contact_islands.tscn",
},
]
func _ready():
var test_menu = $TestsMenu
for test in _tests:
test_menu.add_test(test.id, test.path)

View File

@@ -0,0 +1,10 @@
[gd_scene load_steps=2 format=2]
[sub_resource type="RectangleShape2D" id=1]
extents = Vector2( 20, 20 )
[node name="StackBox" type="RigidBody2D"]
position = Vector2( -180, -20 )
[node name="CollisionShape2D" type="CollisionShape2D" parent="."]
shape = SubResource( 1 )

View File

@@ -0,0 +1,165 @@
extends Test
class_name TestCharacter
enum E_BodyType {
RIGID_BODY,
KINEMATIC_BODY,
KINEMATIC_BODY_RAY_SHAPE,
}
const OPTION_OBJECT_TYPE_RIGIDBODY = "Object type/Rigid body (1)"
const OPTION_OBJECT_TYPE_KINEMATIC = "Object type/Kinematic body (2)"
const OPTION_OBJECT_TYPE_KINEMATIC_RAYSHAPE = "Object type/Kinematic body with ray shape (3)"
const OPTION_MOVE_KINEMATIC_SNAP = "Move Options/Use snap (Kinematic only)"
const OPTION_MOVE_KINEMATIC_STOP_ON_SLOPE = "Move Options/Use stop on slope (Kinematic only)"
export(Vector2) var _initial_velocity = Vector2.ZERO
export(Vector2) var _constant_velocity = Vector2.ZERO
export(float) var _motion_speed = 400.0
export(float) var _gravity_force = 50.0
export(float) var _jump_force = 1000.0
export(float) var _snap_distance = 0.0
export(float) var _floor_max_angle = 45.0
export(E_BodyType) var _body_type = 0
onready var options = $Options
var _use_snap = true
var _use_stop_on_slope = true
var _body_parent = null
var _rigid_body_template = null
var _kinematic_body_template = null
var _kinematic_body_ray_template = null
var _moving_body = null
func _ready():
options.connect("option_selected", self, "_on_option_selected")
options.connect("option_changed", self, "_on_option_changed")
_rigid_body_template = find_node("RigidBody2D")
if _rigid_body_template:
_body_parent = _rigid_body_template.get_parent()
_body_parent.remove_child(_rigid_body_template)
var enabled = _body_type == E_BodyType.RIGID_BODY
options.add_menu_item(OPTION_OBJECT_TYPE_RIGIDBODY, true, enabled, true)
_kinematic_body_template = find_node("KinematicBody2D")
if _kinematic_body_template:
_body_parent = _kinematic_body_template.get_parent()
_body_parent.remove_child(_kinematic_body_template)
var enabled = _body_type == E_BodyType.KINEMATIC_BODY
options.add_menu_item(OPTION_OBJECT_TYPE_KINEMATIC, true, enabled, true)
_kinematic_body_ray_template = find_node("KinematicBodyRay2D")
if _kinematic_body_ray_template:
_body_parent = _kinematic_body_ray_template.get_parent()
_body_parent.remove_child(_kinematic_body_ray_template)
var enabled = _body_type == E_BodyType.KINEMATIC_BODY_RAY_SHAPE
options.add_menu_item(OPTION_OBJECT_TYPE_KINEMATIC_RAYSHAPE, true, enabled, true)
options.add_menu_item(OPTION_MOVE_KINEMATIC_SNAP, true, _use_snap)
options.add_menu_item(OPTION_MOVE_KINEMATIC_STOP_ON_SLOPE, true, _use_stop_on_slope)
_start_test()
func _process(_delta):
var label_floor = $LabelFloor
if _moving_body:
if _moving_body.is_on_floor():
label_floor.text = "ON FLOOR"
label_floor.self_modulate = Color.green
else:
label_floor.text = "OFF FLOOR"
label_floor.self_modulate = Color.red
else:
label_floor.visible = false
func _input(event):
var key_event = event as InputEventKey
if key_event and not key_event.pressed:
if key_event.scancode == KEY_1:
if _rigid_body_template:
_on_option_selected(OPTION_OBJECT_TYPE_RIGIDBODY)
elif key_event.scancode == KEY_2:
if _kinematic_body_template:
_on_option_selected(OPTION_OBJECT_TYPE_KINEMATIC)
elif key_event.scancode == KEY_3:
if _kinematic_body_ray_template:
_on_option_selected(OPTION_OBJECT_TYPE_KINEMATIC_RAYSHAPE)
func _exit_tree():
if _rigid_body_template:
_rigid_body_template.free()
if _kinematic_body_template:
_kinematic_body_template.free()
if _kinematic_body_ray_template:
_kinematic_body_ray_template.free()
func _on_option_selected(option):
match option:
OPTION_OBJECT_TYPE_RIGIDBODY:
_body_type = E_BodyType.RIGID_BODY
_start_test()
OPTION_OBJECT_TYPE_KINEMATIC:
_body_type = E_BodyType.KINEMATIC_BODY
_start_test()
OPTION_OBJECT_TYPE_KINEMATIC_RAYSHAPE:
_body_type = E_BodyType.KINEMATIC_BODY_RAY_SHAPE
_start_test()
func _on_option_changed(option, checked):
match option:
OPTION_MOVE_KINEMATIC_SNAP:
_use_snap = checked
_start_test()
OPTION_MOVE_KINEMATIC_STOP_ON_SLOPE:
_use_stop_on_slope = checked
_start_test()
func _start_test():
cancel_timer()
if _moving_body:
_body_parent.remove_child(_moving_body)
_moving_body.queue_free()
_moving_body = null
var test_label = "Testing: "
var template = null
match _body_type:
E_BodyType.RIGID_BODY:
template = _rigid_body_template
E_BodyType.KINEMATIC_BODY:
template = _kinematic_body_template
E_BodyType.KINEMATIC_BODY_RAY_SHAPE:
template = _kinematic_body_ray_template
test_label += template.name
_moving_body = template.duplicate()
_body_parent.add_child(_moving_body)
_moving_body._initial_velocity = _initial_velocity
_moving_body._constant_velocity = _constant_velocity
_moving_body._motion_speed = _motion_speed
_moving_body._gravity_force = _gravity_force
_moving_body._jump_force = _jump_force
if _moving_body is KinematicBody2D:
if _use_snap:
_moving_body._snap = Vector2(0, _snap_distance)
_moving_body._stop_on_slope = _use_stop_on_slope
_moving_body._floor_max_angle = _floor_max_angle
$LabelTestType.text = test_label

View File

@@ -0,0 +1,151 @@
extends TestCharacter
const OPTION_TEST_CASE_ALL = "Test Cases/TEST ALL (0)"
const OPTION_TEST_CASE_DETECT_FLOOR_NO_SNAP = "Test Cases/Floor detection (Kinematic Body)"
const OPTION_TEST_CASE_DETECT_FLOOR_MOTION_CHANGES = "Test Cases/Floor detection with motion changes (Kinematic Body)"
const MOTION_CHANGES_DIR = Vector2(1.0, 1.0)
const MOTION_CHANGES_SPEEDS = [0.5, 1.0, 2.0, 5.0, 10.0, 20.0, 50.0]
var _test_floor_detection = false
var _test_motion_changes = false
var _floor_detected = false
var _floor_lost = false
var _failed_reason = ""
func _ready():
options.add_menu_item(OPTION_TEST_CASE_ALL)
options.add_menu_item(OPTION_TEST_CASE_DETECT_FLOOR_NO_SNAP)
options.add_menu_item(OPTION_TEST_CASE_DETECT_FLOOR_MOTION_CHANGES)
func _physics_process(_delta):
if _moving_body:
if _moving_body.is_on_floor():
_floor_detected = true
elif _floor_detected:
_floor_lost = true
if _test_motion_changes:
Log.print_log("Floor lost.")
if _test_motion_changes:
var speed_count = MOTION_CHANGES_SPEEDS.size()
var speed_index = randi() % speed_count
var speed = MOTION_CHANGES_SPEEDS[speed_index]
var velocity = speed * MOTION_CHANGES_DIR
_moving_body._constant_velocity = velocity
#Log.print_log("Velocity: %s" % velocity)
func _input(event):
var key_event = event as InputEventKey
if key_event and not key_event.pressed:
if key_event.scancode == KEY_0:
_on_option_selected(OPTION_TEST_CASE_ALL)
func _on_option_selected(option):
match option:
OPTION_TEST_CASE_ALL:
_test_all()
OPTION_TEST_CASE_DETECT_FLOOR_NO_SNAP:
_start_test_case(option)
return
OPTION_TEST_CASE_DETECT_FLOOR_MOTION_CHANGES:
_start_test_case(option)
return
._on_option_selected(option)
func _start_test_case(option):
Log.print_log("* Starting " + option)
match option:
OPTION_TEST_CASE_DETECT_FLOOR_NO_SNAP:
_test_floor_detection = true
_test_motion_changes = false
_use_snap = false
_body_type = E_BodyType.KINEMATIC_BODY
_start_test()
yield(start_timer(1.0), "timeout")
if is_timer_canceled():
return
_set_result(not _floor_lost)
OPTION_TEST_CASE_DETECT_FLOOR_MOTION_CHANGES:
_test_floor_detection = true
_test_motion_changes = true
_use_snap = false
_body_type = E_BodyType.KINEMATIC_BODY
_start_test()
yield(start_timer(4.0), "timeout")
if is_timer_canceled():
_test_motion_changes = false
return
_test_motion_changes = false
_moving_body._constant_velocity = Vector2.ZERO
_set_result(not _floor_lost)
_:
Log.print_error("Invalid test case.")
func _test_all():
Log.print_log("* TESTING ALL...")
# Test floor detection with no snapping.
yield(_start_test_case(OPTION_TEST_CASE_DETECT_FLOOR_NO_SNAP), "completed")
if is_timer_canceled():
return
# Test floor detection with no snapping.
# In this test case, motion alternates different speeds.
yield(_start_test_case(OPTION_TEST_CASE_DETECT_FLOOR_MOTION_CHANGES), "completed")
if is_timer_canceled():
return
Log.print_log("* Done.")
func _set_result(test_passed):
var result = ""
if test_passed:
result = "PASSED"
else:
result = "FAILED"
if not test_passed and not _failed_reason.empty():
result += _failed_reason
else:
result += "."
Log.print_log("Test %s" % result)
func _start_test():
._start_test()
_failed_reason = ""
_floor_detected = false
_floor_lost = false
if _test_floor_detection:
_failed_reason = ": floor was not detected consistently."
if _test_motion_changes:
# Always use the same seed for reproducible results.
rand_seed(123456789)
_moving_body._gravity_force = 0.0
_moving_body._motion_speed = 0.0
_moving_body._jump_force = 0.0
else:
_moving_body._initial_velocity = Vector2(30, 0)
_test_floor_detection = false
else:
_test_motion_changes = false

View File

@@ -0,0 +1,151 @@
[gd_scene load_steps=12 format=2]
[ext_resource path="res://tests/functional/test_character_pixels.gd" type="Script" id=1]
[ext_resource path="res://utils/rigidbody_controller.gd" type="Script" id=2]
[ext_resource path="res://tests/test_options.tscn" type="PackedScene" id=3]
[ext_resource path="res://tests/static_scene_flat.tscn" type="PackedScene" id=4]
[ext_resource path="res://utils/kinematicbody_controller.gd" type="Script" id=7]
[sub_resource type="PhysicsMaterial" id=1]
friction = 0.0
[sub_resource type="RectangleShape2D" id=2]
extents = Vector2( 3, 5 )
[sub_resource type="RectangleShape2D" id=3]
extents = Vector2( 3, 4.9 )
[sub_resource type="RectangleShape2D" id=4]
extents = Vector2( 3, 3 )
[sub_resource type="RayShape2D" id=5]
length = 3.0
[sub_resource type="RectangleShape2D" id=6]
extents = Vector2( 10, 2 )
[node name="Test" type="Node2D"]
script = ExtResource( 1 )
_motion_speed = 30.0
_gravity_force = 2.0
_jump_force = 50.0
_snap_distance = 1.0
[node name="ViewportContainer" type="ViewportContainer" parent="."]
anchor_right = 1.0
anchor_bottom = 1.0
margin_right = 1024.0
margin_bottom = 600.0
size_flags_horizontal = 3
size_flags_vertical = 3
stretch = true
__meta__ = {
"_edit_use_anchors_": false
}
[node name="Viewport" type="Viewport" parent="ViewportContainer"]
size = Vector2( 128, 75 )
handle_input_locally = false
render_target_update_mode = 3
[node name="StaticSceneFlat" parent="ViewportContainer/Viewport" instance=ExtResource( 4 )]
position = Vector2( 0, -450 )
[node name="RigidBody2D" type="RigidBody2D" parent="ViewportContainer/Viewport"]
position = Vector2( 30, 40 )
collision_mask = 2147483649
mode = 2
physics_material_override = SubResource( 1 )
contacts_reported = 4
contact_monitor = true
script = ExtResource( 2 )
[node name="CollisionShape2D" type="CollisionShape2D" parent="ViewportContainer/Viewport/RigidBody2D"]
shape = SubResource( 2 )
[node name="KinematicBody2D" type="KinematicBody2D" parent="ViewportContainer/Viewport"]
position = Vector2( 30, 40 )
collision_mask = 2147483649
script = ExtResource( 7 )
[node name="CollisionShape2D" type="CollisionShape2D" parent="ViewportContainer/Viewport/KinematicBody2D"]
shape = SubResource( 3 )
[node name="KinematicBodyRay2D" type="KinematicBody2D" parent="ViewportContainer/Viewport"]
position = Vector2( 30, 40 )
collision_mask = 2147483649
script = ExtResource( 7 )
[node name="CollisionShape2D" type="CollisionShape2D" parent="ViewportContainer/Viewport/KinematicBodyRay2D"]
position = Vector2( 0, -2 )
shape = SubResource( 4 )
[node name="CollisionShapeRay2D" type="CollisionShape2D" parent="ViewportContainer/Viewport/KinematicBodyRay2D"]
position = Vector2( 0, -1 )
shape = SubResource( 5 )
[node name="Wall1" type="StaticBody2D" parent="ViewportContainer/Viewport"]
position = Vector2( 20, 40 )
[node name="CollisionShape2D" type="CollisionShape2D" parent="ViewportContainer/Viewport/Wall1"]
rotation = 1.5708
shape = SubResource( 6 )
[node name="Wall2" type="StaticBody2D" parent="ViewportContainer/Viewport"]
position = Vector2( 122, 40 )
[node name="CollisionShape2D" type="CollisionShape2D" parent="ViewportContainer/Viewport/Wall2"]
rotation = 1.5708
shape = SubResource( 6 )
[node name="Platform1" type="StaticBody2D" parent="ViewportContainer/Viewport"]
position = Vector2( 50, 44 )
[node name="CollisionShape2D" type="CollisionShape2D" parent="ViewportContainer/Viewport/Platform1"]
shape = SubResource( 6 )
one_way_collision = true
[node name="Platform2" type="StaticBody2D" parent="ViewportContainer/Viewport"]
position = Vector2( 80, 38 )
[node name="CollisionShape2D" type="CollisionShape2D" parent="ViewportContainer/Viewport/Platform2"]
shape = SubResource( 6 )
[node name="Slope" type="StaticBody2D" parent="ViewportContainer/Viewport"]
position = Vector2( 84, 36 )
[node name="CollisionShape2D" type="CollisionPolygon2D" parent="ViewportContainer/Viewport/Slope"]
polygon = PoolVector2Array( 0, 0, 6, 0, 22, 16, 16, 16 )
[node name="LabelTestType" type="Label" parent="."]
margin_left = 14.0
margin_top = 79.0
margin_right = 145.0
margin_bottom = 93.0
text = "Testing: "
__meta__ = {
"_edit_use_anchors_": false
}
[node name="Options" parent="." instance=ExtResource( 3 )]
[node name="LabelFloor" type="Label" parent="."]
margin_left = 14.0
margin_top = 237.929
margin_right = 145.0
margin_bottom = 251.929
text = "ON FLOOR"
__meta__ = {
"_edit_use_anchors_": false
}
[node name="LabelControls" type="Label" parent="."]
margin_left = 14.0
margin_top = 263.291
margin_right = 145.0
margin_bottom = 294.291
text = "LEFT/RIGHT - MOVE
UP - JUMP"
__meta__ = {
"_edit_use_anchors_": false
}

View File

@@ -0,0 +1,102 @@
[gd_scene load_steps=11 format=2]
[ext_resource path="res://tests/functional/test_character.gd" type="Script" id=1]
[ext_resource path="res://tests/test_options.tscn" type="PackedScene" id=3]
[ext_resource path="res://tests/static_scene_flat.tscn" type="PackedScene" id=4]
[ext_resource path="res://utils/rigidbody_controller.gd" type="Script" id=6]
[ext_resource path="res://utils/kinematicbody_controller.gd" type="Script" id=7]
[sub_resource type="PhysicsMaterial" id=1]
friction = 0.0
[sub_resource type="CapsuleShape2D" id=2]
radius = 32.0
height = 32.0
[sub_resource type="CapsuleShape2D" id=3]
radius = 32.0
height = 32.0
[sub_resource type="CircleShape2D" id=4]
radius = 32.0
[sub_resource type="RayShape2D" id=5]
length = 64.0
[node name="Test" type="Node2D"]
script = ExtResource( 1 )
_snap_distance = 32.0
[node name="LabelTestType" type="Label" parent="."]
margin_left = 14.0
margin_top = 79.0
margin_right = 145.0
margin_bottom = 93.0
text = "Testing: "
__meta__ = {
"_edit_use_anchors_": false
}
[node name="Options" parent="." instance=ExtResource( 3 )]
[node name="LabelFloor" type="Label" parent="."]
margin_left = 14.0
margin_top = 237.929
margin_right = 145.0
margin_bottom = 251.929
text = "ON FLOOR"
__meta__ = {
"_edit_use_anchors_": false
}
[node name="LabelControls" type="Label" parent="."]
margin_left = 14.0
margin_top = 263.291
margin_right = 145.0
margin_bottom = 294.291
text = "LEFT/RIGHT - MOVE
UP - JUMP"
__meta__ = {
"_edit_use_anchors_": false
}
[node name="RigidBody2D" type="RigidBody2D" parent="."]
position = Vector2( 100, 450 )
collision_mask = 2147483649
mode = 2
physics_material_override = SubResource( 1 )
contacts_reported = 4
contact_monitor = true
script = ExtResource( 6 )
[node name="CollisionShape2D" type="CollisionShape2D" parent="RigidBody2D"]
shape = SubResource( 2 )
[node name="KinematicBody2D" type="KinematicBody2D" parent="."]
position = Vector2( 100, 450 )
collision_mask = 2147483649
script = ExtResource( 7 )
[node name="CollisionShape2D" type="CollisionShape2D" parent="KinematicBody2D"]
shape = SubResource( 3 )
[node name="KinematicBodyRay2D" type="KinematicBody2D" parent="."]
position = Vector2( 100, 450 )
collision_mask = 2147483649
script = ExtResource( 7 )
[node name="CollisionShape2D" type="CollisionShape2D" parent="KinematicBodyRay2D"]
position = Vector2( 0, -16 )
shape = SubResource( 4 )
[node name="CollisionShapeRay2D" type="CollisionShape2D" parent="KinematicBodyRay2D"]
position = Vector2( 0, -16 )
shape = SubResource( 5 )
[node name="StaticSceneFlat" parent="." instance=ExtResource( 4 )]
position = Vector2( 0, 12 )
[node name="StaticBody2D" type="StaticBody2D" parent="."]
[node name="CollisionPolygon2D" type="CollisionPolygon2D" parent="StaticBody2D"]
polygon = PoolVector2Array( 171.04, 529.248, 379.275, 294.316, 506.084, 429.135, 648.26, 322.058, 868.746, 322.058, 985.282, 36.6919, 1242.91, 531.917 )

View File

@@ -0,0 +1,209 @@
extends TestCharacter
const OPTION_TEST_CASE_ALL = "Test Cases/TEST ALL (0)"
const OPTION_TEST_CASE_JUMP_ONE_WAY_RIGID = "Test Cases/Jump through one-way tiles (Rigid Body)"
const OPTION_TEST_CASE_JUMP_ONE_WAY_KINEMATIC = "Test Cases/Jump through one-way tiles (Kinematic Body)"
const OPTION_TEST_CASE_JUMP_ONE_WAY_CORNER_RIGID = "Test Cases/Jump through one-way corner (Rigid Body)"
const OPTION_TEST_CASE_JUMP_ONE_WAY_CORNER_KINEMATIC = "Test Cases/Jump through one-way corner (Kinematic Body)"
const OPTION_TEST_CASE_FALL_ONE_WAY_KINEMATIC = "Test Cases/Fall and pushed on one-way tiles (Kinematic Body)"
var _test_jump_one_way = false
var _test_jump_one_way_corner = false
var _test_fall_one_way = false
var _extra_body = null
var _failed_reason = ""
func _ready():
options.add_menu_item(OPTION_TEST_CASE_ALL)
options.add_menu_item(OPTION_TEST_CASE_JUMP_ONE_WAY_RIGID)
options.add_menu_item(OPTION_TEST_CASE_JUMP_ONE_WAY_KINEMATIC)
options.add_menu_item(OPTION_TEST_CASE_JUMP_ONE_WAY_CORNER_RIGID)
options.add_menu_item(OPTION_TEST_CASE_JUMP_ONE_WAY_CORNER_KINEMATIC)
options.add_menu_item(OPTION_TEST_CASE_FALL_ONE_WAY_KINEMATIC)
func _input(event):
var key_event = event as InputEventKey
if key_event and not key_event.pressed:
if key_event.scancode == KEY_0:
_on_option_selected(OPTION_TEST_CASE_ALL)
func _on_option_selected(option):
match option:
OPTION_TEST_CASE_ALL:
_test_all()
OPTION_TEST_CASE_JUMP_ONE_WAY_RIGID:
_start_test_case(option)
return
OPTION_TEST_CASE_JUMP_ONE_WAY_KINEMATIC:
_start_test_case(option)
return
OPTION_TEST_CASE_JUMP_ONE_WAY_CORNER_RIGID:
_start_test_case(option)
return
OPTION_TEST_CASE_JUMP_ONE_WAY_CORNER_KINEMATIC:
_start_test_case(option)
return
OPTION_TEST_CASE_FALL_ONE_WAY_KINEMATIC:
_start_test_case(option)
return
._on_option_selected(option)
func _start_test_case(option):
Log.print_log("* Starting " + option)
match option:
OPTION_TEST_CASE_JUMP_ONE_WAY_RIGID:
_body_type = E_BodyType.RIGID_BODY
_test_jump_one_way_corner = false
yield(_start_jump_one_way(), "completed")
OPTION_TEST_CASE_JUMP_ONE_WAY_KINEMATIC:
_body_type = E_BodyType.KINEMATIC_BODY
_test_jump_one_way_corner = false
yield(_start_jump_one_way(), "completed")
OPTION_TEST_CASE_JUMP_ONE_WAY_CORNER_RIGID:
_body_type = E_BodyType.RIGID_BODY
_test_jump_one_way_corner = true
yield(_start_jump_one_way(), "completed")
OPTION_TEST_CASE_JUMP_ONE_WAY_CORNER_KINEMATIC:
_body_type = E_BodyType.KINEMATIC_BODY
_test_jump_one_way_corner = true
yield(_start_jump_one_way(), "completed")
OPTION_TEST_CASE_FALL_ONE_WAY_KINEMATIC:
_body_type = E_BodyType.KINEMATIC_BODY
yield(_start_fall_one_way(), "completed")
_:
Log.print_error("Invalid test case.")
func _test_all():
Log.print_log("* TESTING ALL...")
# RigidBody tests.
yield(_start_test_case(OPTION_TEST_CASE_JUMP_ONE_WAY_RIGID), "completed")
if is_timer_canceled():
return
yield(_start_test_case(OPTION_TEST_CASE_JUMP_ONE_WAY_CORNER_RIGID), "completed")
if is_timer_canceled():
return
# KinematicBody tests.
yield(_start_test_case(OPTION_TEST_CASE_JUMP_ONE_WAY_KINEMATIC), "completed")
if is_timer_canceled():
return
yield(_start_test_case(OPTION_TEST_CASE_JUMP_ONE_WAY_CORNER_KINEMATIC), "completed")
if is_timer_canceled():
return
yield(_start_test_case(OPTION_TEST_CASE_FALL_ONE_WAY_KINEMATIC), "completed")
if is_timer_canceled():
return
Log.print_log("* Done.")
func _set_result(test_passed):
var result = ""
if test_passed:
result = "PASSED"
else:
result = "FAILED"
if not test_passed and not _failed_reason.empty():
result += _failed_reason
else:
result += "."
Log.print_log("Test %s" % result)
func _start_test():
if _extra_body:
_body_parent.remove_child(_extra_body)
_extra_body.queue_free()
_extra_body = null
._start_test()
if _test_jump_one_way:
_test_jump_one_way = false
_moving_body._initial_velocity = Vector2(600, -1000)
if _test_jump_one_way_corner:
_moving_body.position.x = 147.0
$JumpTargetArea2D.visible = true
$JumpTargetArea2D/CollisionShape2D.disabled = false
if _test_fall_one_way:
_test_fall_one_way = false
_moving_body.position.y = 350.0
_moving_body._gravity_force = 100.0
_moving_body._motion_speed = 0.0
_moving_body._jump_force = 0.0
_extra_body = _moving_body.duplicate()
_extra_body._gravity_force = 100.0
_extra_body._motion_speed = 0.0
_extra_body._jump_force = 0.0
_extra_body.position -= Vector2(0.0, 200.0)
_body_parent.add_child(_extra_body)
$FallTargetArea2D.visible = true
$FallTargetArea2D/CollisionShape2D.disabled = false
func _start_jump_one_way():
_test_jump_one_way = true
_start_test()
yield(start_timer(1.5), "timeout")
if is_timer_canceled():
return
_finalize_jump_one_way()
func _start_fall_one_way():
_test_fall_one_way = true
_start_test()
yield(start_timer(1.0), "timeout")
if is_timer_canceled():
return
_finalize_fall_one_way()
func _finalize_jump_one_way():
var passed = true
if not $JumpTargetArea2D.overlaps_body(_moving_body):
passed = false
_failed_reason = ": the body wasn't able to jump all the way through."
_set_result(passed)
$JumpTargetArea2D.visible = false
$JumpTargetArea2D/CollisionShape2D.disabled = true
func _finalize_fall_one_way():
var passed = true
if $FallTargetArea2D.overlaps_body(_moving_body):
passed = false
_failed_reason = ": the body was pushed through the one-way collision."
_set_result(passed)
$FallTargetArea2D.visible = false
$FallTargetArea2D/CollisionShape2D.disabled = true

View File

@@ -0,0 +1,125 @@
[gd_scene load_steps=12 format=2]
[ext_resource path="res://tests/functional/test_character_tilemap.gd" type="Script" id=1]
[ext_resource path="res://tests/test_options.tscn" type="PackedScene" id=3]
[ext_resource path="res://tests/static_scene_flat.tscn" type="PackedScene" id=4]
[ext_resource path="res://assets/tileset/tileset.tres" type="TileSet" id=5]
[ext_resource path="res://utils/rigidbody_controller.gd" type="Script" id=6]
[ext_resource path="res://utils/kinematicbody_controller.gd" type="Script" id=7]
[sub_resource type="PhysicsMaterial" id=1]
friction = 0.0
[sub_resource type="RectangleShape2D" id=2]
extents = Vector2( 16, 31.9 )
[sub_resource type="RectangleShape2D" id=3]
extents = Vector2( 16, 24 )
[sub_resource type="RayShape2D" id=4]
length = 24.0
[sub_resource type="CircleShape2D" id=5]
radius = 16.0
[node name="Test" type="Node2D"]
script = ExtResource( 1 )
[node name="LabelTestType" type="Label" parent="."]
margin_left = 14.0
margin_top = 79.0
margin_right = 145.0
margin_bottom = 93.0
text = "Testing: "
__meta__ = {
"_edit_use_anchors_": false
}
[node name="Options" parent="." instance=ExtResource( 3 )]
[node name="LabelFloor" type="Label" parent="."]
margin_left = 14.0
margin_top = 237.929
margin_right = 145.0
margin_bottom = 251.929
text = "ON FLOOR"
__meta__ = {
"_edit_use_anchors_": false
}
[node name="LabelControls" type="Label" parent="."]
margin_left = 14.0
margin_top = 263.291
margin_right = 145.0
margin_bottom = 277.291
text = "LEFT/RIGHT - MOVE
UP - JUMP"
__meta__ = {
"_edit_use_anchors_": false
}
[node name="RigidBody2D" type="RigidBody2D" parent="."]
position = Vector2( 250, 460 )
collision_mask = 2147483649
mode = 2
physics_material_override = SubResource( 1 )
contacts_reported = 4
contact_monitor = true
script = ExtResource( 6 )
[node name="CollisionShape2D" type="CollisionShape2D" parent="RigidBody2D"]
shape = SubResource( 2 )
[node name="KinematicBody2D" type="KinematicBody2D" parent="."]
position = Vector2( 250, 460 )
collision_mask = 2147483649
script = ExtResource( 7 )
[node name="CollisionShape2D" type="CollisionShape2D" parent="KinematicBody2D"]
shape = SubResource( 2 )
[node name="KinematicBodyRay2D" type="KinematicBody2D" parent="."]
position = Vector2( 250, 460 )
collision_mask = 2147483649
script = ExtResource( 7 )
[node name="CollisionShape2D" type="CollisionShape2D" parent="KinematicBodyRay2D"]
position = Vector2( 0, -8 )
shape = SubResource( 3 )
[node name="CollisionShapeRay2D" type="CollisionShape2D" parent="KinematicBodyRay2D"]
position = Vector2( 0, 8 )
shape = SubResource( 4 )
[node name="CollisionShapeRay2DLeft" type="CollisionShape2D" parent="KinematicBodyRay2D"]
position = Vector2( -16, 8 )
shape = SubResource( 4 )
[node name="CollisionShapeRay2DRight" type="CollisionShape2D" parent="KinematicBodyRay2D"]
position = Vector2( 16, 8 )
shape = SubResource( 4 )
[node name="JumpTargetArea2D" type="Area2D" parent="."]
visible = false
position = Vector2( 810, 390 )
[node name="CollisionShape2D" type="CollisionShape2D" parent="JumpTargetArea2D"]
shape = SubResource( 5 )
disabled = true
[node name="FallTargetArea2D" type="Area2D" parent="."]
visible = false
position = Vector2( 250, 480 )
[node name="CollisionShape2D" type="CollisionShape2D" parent="FallTargetArea2D"]
shape = SubResource( 5 )
disabled = true
[node name="StaticSceneFlat" parent="." instance=ExtResource( 4 )]
position = Vector2( 0, 12 )
[node name="TileMap" type="TileMap" parent="."]
tile_set = ExtResource( 5 )
cell_size = Vector2( 32, 32 )
format = 1
tile_data = PoolIntArray( 458764, 5, 0, 458765, 5, 0, 458766, 5, 0, 458767, 5, 0, 458768, 5, 0, 458769, 5, 0, 458770, 5, 0, 458771, 5, 0, 524300, 5, 0, 524301, 5, 0, 524302, 5, 0, 524303, 5, 0, 524304, 5, 0, 524305, 5, 0, 524306, 5, 0, 524307, 5, 0, 589836, 5, 0, 589837, 5, 0, 589838, 5, 0, 589839, 5, 0, 589840, 5, 0, 589841, 5, 0, 589842, 5, 0, 589843, 5, 0, 655372, 5, 0, 655373, 5, 0, 655374, 5, 0, 655375, 5, 0, 655376, 5, 0, 655377, 5, 0, 655378, 5, 0, 655379, 5, 0, 720908, 5, 0, 720909, 5, 0, 720910, 5, 0, 720911, 5, 0, 720912, 5, 0, 720913, 5, 0, 720914, 5, 0, 720915, 5, 0, 720922, 0, 0, 720923, 0, 0, 720924, 0, 0, 720925, 0, 0, 786438, 5, 0, 786439, 5, 0, 786440, 5, 0, 786441, 5, 0, 786444, 5, 0, 786445, 5, 0, 786446, 5, 0, 786447, 5, 0, 786448, 5, 0, 786449, 5, 0, 786450, 5, 0, 786451, 5, 0, 851980, 5, 0, 851981, 5, 0, 851982, 5, 0, 851983, 5, 0, 851984, 5, 0, 851985, 5, 0, 851986, 5, 0, 851987, 5, 0, 851992, 0, 0, 851993, 0, 0, 851994, 0, 0, 851995, 0, 0, 917516, 5, 0, 917517, 5, 0, 917518, 5, 0, 917519, 5, 0, 917520, 5, 0, 917521, 5, 0, 917522, 5, 0, 917523, 5, 0, 983052, 5, 0, 983053, 5, 0, 983054, 5, 0, 983055, 5, 0, 983056, 5, 0, 983057, 5, 0, 983058, 5, 0, 983059, 5, 0 )

View File

@@ -0,0 +1,208 @@
extends Test
const OPTION_TYPE_RECTANGLE = "Collision type/Rectangle (1)"
const OPTION_TYPE_SPHERE = "Collision type/Sphere (2)"
const OPTION_TYPE_CAPSULE = "Collision type/Capsule (3)"
const OPTION_TYPE_CONVEX_POLYGON = "Collision type/Convex Polygon (4)"
const OPTION_TYPE_CONCAVE_SEGMENTS = "Collision type/Concave Segments (5)"
const OPTION_SHAPE_RECTANGLE = "Shape type/Rectangle"
const OPTION_SHAPE_SPHERE = "Shape type/Sphere"
const OPTION_SHAPE_CAPSULE = "Shape type/Capsule"
const OPTION_SHAPE_CONVEX_POLYGON = "Shape type/Convex Polygon"
const OPTION_SHAPE_CONCAVE_POLYGON = "Shape type/Concave Polygon"
const OPTION_SHAPE_CONCAVE_SEGMENTS = "Shape type/Concave Segments"
const OFFSET_RANGE = 120.0
export(Vector2) var offset = Vector2.ZERO
onready var options = $Options
var _update_collision = false
var _collision_test_index = 0
var _current_offset = Vector2.ZERO
var _collision_shapes = []
func _ready():
_initialize_collision_shapes()
options.add_menu_item(OPTION_TYPE_RECTANGLE)
options.add_menu_item(OPTION_TYPE_SPHERE)
options.add_menu_item(OPTION_TYPE_CAPSULE)
options.add_menu_item(OPTION_TYPE_CONVEX_POLYGON)
options.add_menu_item(OPTION_TYPE_CONCAVE_SEGMENTS)
options.add_menu_item(OPTION_SHAPE_RECTANGLE, true, true)
options.add_menu_item(OPTION_SHAPE_SPHERE, true, true)
options.add_menu_item(OPTION_SHAPE_CAPSULE, true, true)
options.add_menu_item(OPTION_SHAPE_CONVEX_POLYGON, true, true)
options.add_menu_item(OPTION_SHAPE_CONCAVE_POLYGON, true, true)
options.add_menu_item(OPTION_SHAPE_CONCAVE_SEGMENTS, true, true)
options.connect("option_selected", self, "_on_option_selected")
options.connect("option_changed", self, "_on_option_changed")
yield(start_timer(0.5), "timeout")
if is_timer_canceled():
return
_update_collision = true
func _input(event):
var key_event = event as InputEventKey
if key_event and not key_event.pressed:
if key_event.scancode == KEY_1:
_on_option_selected(OPTION_TYPE_RECTANGLE)
elif key_event.scancode == KEY_2:
_on_option_selected(OPTION_TYPE_SPHERE)
elif key_event.scancode == KEY_3:
_on_option_selected(OPTION_TYPE_CAPSULE)
elif key_event.scancode == KEY_4:
_on_option_selected(OPTION_TYPE_CONVEX_POLYGON)
elif key_event.scancode == KEY_5:
_on_option_selected(OPTION_TYPE_CONCAVE_SEGMENTS)
func _physics_process(_delta):
if not _update_collision:
return
_update_collision = false
_do_collision_test()
func set_h_offset(value):
offset.x = value * OFFSET_RANGE
_update_collision = true
func set_v_offset(value):
offset.y = -value * OFFSET_RANGE
_update_collision = true
func _initialize_collision_shapes():
_collision_shapes.clear()
for node in $Shapes.get_children():
var body = node as PhysicsBody2D
var shape = body.shape_owner_get_shape(0, 0)
shape.resource_name = String(node.name).substr("RigidBody".length())
_collision_shapes.push_back(shape)
func _do_collision_test():
clear_drawn_nodes()
var shape = _collision_shapes[_collision_test_index]
Log.print_log("* Start %s collision tests..." % shape.resource_name)
var shape_query = Physics2DShapeQueryParameters.new()
shape_query.set_shape(shape)
var shape_scale = Vector2(0.5, 0.5)
shape_query.transform = Transform2D.IDENTITY.scaled(shape_scale)
for node in $Shapes.get_children():
if not node.visible:
continue
var body = node as PhysicsBody2D
var space_state = body.get_world_2d().direct_space_state
Log.print_log("* Testing: %s" % body.name)
var center = body.position
# Collision at the center inside.
var res = _add_collision(space_state, center, shape, shape_query)
Log.print_log("Collision center inside: %s" % ("NO HIT" if res.empty() else "HIT"))
Log.print_log("* Done.")
func _add_collision(space_state, pos, shape, shape_query):
shape_query.transform.origin = pos + offset
var results = space_state.collide_shape(shape_query)
var color
if results.empty():
color = Color.white.darkened(0.5)
else:
color = Color.green
# Draw collision query shape.
add_shape(shape, shape_query.transform, color)
# Draw contact positions.
for contact_pos in results:
add_circle(contact_pos, 1.0, Color.red)
return results
func _on_option_selected(option):
match option:
OPTION_TYPE_RECTANGLE:
_collision_test_index = _find_type_index("Rectangle")
_update_collision = true
OPTION_TYPE_SPHERE:
_collision_test_index = _find_type_index("Sphere")
_update_collision = true
OPTION_TYPE_CAPSULE:
_collision_test_index = _find_type_index("Capsule")
_update_collision = true
OPTION_TYPE_CONVEX_POLYGON:
_collision_test_index = _find_type_index("ConvexPolygon")
_update_collision = true
OPTION_TYPE_CONCAVE_SEGMENTS:
_collision_test_index = _find_type_index("ConcaveSegments")
_update_collision = true
func _find_type_index(type_name):
for type_index in range(_collision_shapes.size()):
var type_shape = _collision_shapes[type_index]
if type_shape.resource_name.find(type_name) > -1:
return type_index
Log.print_error("Invalid collision type: " + type_name)
return -1
func _on_option_changed(option, checked):
var node
match option:
OPTION_SHAPE_RECTANGLE:
node = _find_shape_node("Rectangle")
OPTION_SHAPE_SPHERE:
node = _find_shape_node("Sphere")
OPTION_SHAPE_CAPSULE:
node = _find_shape_node("Capsule")
OPTION_SHAPE_CONVEX_POLYGON:
node = _find_shape_node("ConvexPolygon")
OPTION_SHAPE_CONCAVE_POLYGON:
node = _find_shape_node("ConcavePolygon")
OPTION_SHAPE_CONCAVE_SEGMENTS:
node = _find_shape_node("ConcaveSegments")
if node:
node.visible = checked
node.get_child(0).disabled = not checked
_update_collision = true
func _find_shape_node(type_name):
var node = $Shapes.find_node("RigidBody%s" % type_name)
if not node:
Log.print_error("Invalid shape type: " + type_name)
return node

View File

@@ -0,0 +1,151 @@
[gd_scene load_steps=8 format=2]
[ext_resource path="res://tests/functional/test_collision_pairs.gd" type="Script" id=1]
[ext_resource path="res://assets/texture/godot-head.png" type="Texture" id=2]
[ext_resource path="res://tests/test_options.tscn" type="PackedScene" id=3]
[sub_resource type="RectangleShape2D" id=1]
extents = Vector2( 40, 60 )
[sub_resource type="CircleShape2D" id=2]
radius = 60.0
[sub_resource type="CapsuleShape2D" id=3]
radius = 30.0
height = 50.0
[sub_resource type="ConcavePolygonShape2D" id=4]
segments = PoolVector2Array( -5.93512, -43.2195, 6.44476, -42.9695, 6.44476, -42.9695, 11.127, -54.3941, 11.127, -54.3941, 26.9528, -49.4309, 26.9528, -49.4309, 26.2037, -36.508, 26.2037, -36.508, 37.5346, -28.1737, 37.5346, -28.1737, 47.6282, -34.3806, 47.6282, -34.3806, 58.0427, -20.9631, 58.0427, -20.9631, 51.113, -10.2876, 51.113, -10.2876, 50.9869, 35.2694, 50.9869, 35.2694, 38.8, 47.5, 38.8, 47.5, 15.9852, 54.3613, 15.9852, 54.3613, -14.9507, 54.1845, -14.9507, 54.1845, -36.5, 48.1, -36.5, 48.1, -50.4828, 36.33, -50.4828, 36.33, -51.3668, -9.98545, -51.3668, -9.98545, -57.8889, -20.5885, -57.8889, -20.5885, -46.9473, -34.7342, -46.9473, -34.7342, -37.4014, -28.547, -37.4014, -28.547, -26.0876, -37.0323, -26.0876, -37.0323, -26.9862, -49.15, -26.9862, -49.15, -11.4152, -54.5332, -11.4152, -54.5332, -5.93512, -43.2195 )
[node name="Test" type="Node2D"]
script = ExtResource( 1 )
[node name="Options" parent="." instance=ExtResource( 3 )]
[node name="Shapes" type="Node2D" parent="."]
z_index = -1
z_as_relative = false
[node name="RigidBodyRectangle" type="RigidBody2D" parent="Shapes"]
position = Vector2( 114.877, 248.76 )
mode = 1
[node name="CollisionShape2D" type="CollisionShape2D" parent="Shapes/RigidBodyRectangle"]
rotation = -1.19206
scale = Vector2( 1.2, 1.2 )
shape = SubResource( 1 )
[node name="RigidBodySphere" type="RigidBody2D" parent="Shapes"]
position = Vector2( 314.894, 257.658 )
mode = 1
[node name="CollisionShape2D" type="CollisionShape2D" parent="Shapes/RigidBodySphere"]
shape = SubResource( 2 )
[node name="RigidBodyCapsule" type="RigidBody2D" parent="Shapes"]
position = Vector2( 465.629, 261.204 )
mode = 1
[node name="CollisionShape2D" type="CollisionShape2D" parent="Shapes/RigidBodyCapsule"]
rotation = -0.202458
scale = Vector2( 1.2, 1.2 )
shape = SubResource( 3 )
[node name="RigidBodyConvexPolygon" type="RigidBody2D" parent="Shapes"]
position = Vector2( 613.385, 252.771 )
mode = 1
[node name="CollisionPolygon2D" type="CollisionPolygon2D" parent="Shapes/RigidBodyConvexPolygon"]
polygon = PoolVector2Array( 10.7, -54.5, 28.3596, -49.4067, 47.6282, -34.3806, 57.9717, -20.9447, 50.9869, 35.2694, 38.8, 47.5, 15.9852, 54.3613, -14.9507, 54.1845, -36.5, 48.1, -50.4828, 36.33, -58.0115, -20.515, -46.9473, -34.7342, -26.0876, -50.1138, -11.4152, -54.5332 )
[node name="GodotIcon" type="Sprite" parent="Shapes/RigidBodyConvexPolygon"]
modulate = Color( 1, 1, 1, 0.392157 )
texture = ExtResource( 2 )
[node name="RigidBodyConcavePolygon" type="RigidBody2D" parent="Shapes"]
position = Vector2( 771.159, 252.771 )
mode = 1
[node name="CollisionPolygon2D" type="CollisionPolygon2D" parent="Shapes/RigidBodyConcavePolygon"]
polygon = PoolVector2Array( -5.93512, -43.2195, 6.44476, -42.9695, 11.127, -54.3941, 26.9528, -49.4309, 26.2037, -36.508, 37.5346, -28.1737, 47.6282, -34.3806, 58.0427, -20.9631, 51.113, -10.2876, 50.9869, 35.2694, 38.8, 47.5, 15.9852, 54.3613, -14.9507, 54.1845, -36.5, 48.1, -50.4828, 36.33, -51.3668, -9.98545, -57.8889, -20.5885, -46.9473, -34.7342, -37.4014, -28.547, -26.0876, -37.0323, -26.9862, -49.15, -11.4152, -54.5332 )
[node name="GodotIcon" type="Sprite" parent="Shapes/RigidBodyConcavePolygon"]
modulate = Color( 1, 1, 1, 0.392157 )
texture = ExtResource( 2 )
[node name="RigidBodyConcaveSegments" type="RigidBody2D" parent="Shapes"]
position = Vector2( 930.097, 252.771 )
mode = 1
[node name="CollisionShape2D" type="CollisionShape2D" parent="Shapes/RigidBodyConcaveSegments"]
shape = SubResource( 4 )
[node name="GodotIcon" type="Sprite" parent="Shapes/RigidBodyConcaveSegments"]
modulate = Color( 1, 1, 1, 0.392157 )
texture = ExtResource( 2 )
[node name="Controls" type="VBoxContainer" parent="."]
pause_mode = 2
anchor_right = 1.0
anchor_bottom = 1.0
margin_left = 25.3619
margin_top = 416.765
margin_right = 218.362
margin_bottom = 458.765
custom_constants/separation = 10
__meta__ = {
"_edit_use_anchors_": false
}
[node name="OffsetH" type="HBoxContainer" parent="Controls"]
margin_right = 193.0
margin_bottom = 16.0
custom_constants/separation = 20
alignment = 2
__meta__ = {
"_edit_use_anchors_": false
}
[node name="Label" type="Label" parent="Controls/OffsetH"]
margin_top = 1.0
margin_right = 53.0
margin_bottom = 15.0
text = "Offset H"
[node name="HSlider" type="HSlider" parent="Controls/OffsetH"]
margin_left = 73.0
margin_right = 193.0
margin_bottom = 16.0
rect_min_size = Vector2( 120, 0 )
min_value = -1.0
max_value = 1.0
step = 0.01
[node name="OffsetV" type="HBoxContainer" parent="Controls"]
margin_top = 26.0
margin_right = 193.0
margin_bottom = 42.0
custom_constants/separation = 20
alignment = 2
__meta__ = {
"_edit_use_anchors_": false
}
[node name="Label" type="Label" parent="Controls/OffsetV"]
margin_left = 2.0
margin_top = 1.0
margin_right = 53.0
margin_bottom = 15.0
text = "Offset V"
[node name="HSlider" type="HSlider" parent="Controls/OffsetV"]
margin_left = 73.0
margin_right = 193.0
margin_bottom = 16.0
rect_min_size = Vector2( 120, 0 )
min_value = -1.0
max_value = 1.0
step = 0.01
[connection signal="value_changed" from="Controls/OffsetH/HSlider" to="." method="set_h_offset"]
[connection signal="value_changed" from="Controls/OffsetV/HSlider" to="." method="set_v_offset"]

View File

@@ -0,0 +1,143 @@
extends Test
const OPTION_JOINT_TYPE = "Joint Type/%s Joint (%d)"
const OPTION_TEST_CASE_BODIES_COLLIDE = "Test case/Attached bodies collide"
const OPTION_TEST_CASE_WORLD_ATTACHMENT = "Test case/No parent body"
const OPTION_TEST_CASE_DYNAMIC_ATTACHMENT = "Test case/Parent body is dynamic (no gravity)"
const OPTION_TEST_CASE_DESTROY_BODY = "Test case/Destroy attached body"
const OPTION_TEST_CASE_CHANGE_POSITIONS = "Test case/Set body positions after added to scene"
const BOX_SIZE = Vector2(64, 64)
var _update_joint = false
var _selected_joint = null
var _joint_type = PinJoint2D
var _bodies_collide = false
var _world_attachement = false
var _dynamic_attachement = false
var _destroy_body = false
var _change_positions = false
var _joint_types = {}
func _ready():
var options = $Options
var joints = $Joints
for joint_index in range(joints.get_child_count()):
var joint_node = joints.get_child(joint_index)
joint_node.visible = false
var joint_name = joint_node.name
var joint_short = joint_name.substr(0, joint_name.length() - 7)
var option_name = OPTION_JOINT_TYPE % [joint_short, joint_index + 1]
options.add_menu_item(option_name)
_joint_types[option_name] = joint_node
options.add_menu_item(OPTION_TEST_CASE_BODIES_COLLIDE, true, false)
options.add_menu_item(OPTION_TEST_CASE_WORLD_ATTACHMENT, true, false)
options.add_menu_item(OPTION_TEST_CASE_DYNAMIC_ATTACHMENT, true, false)
options.add_menu_item(OPTION_TEST_CASE_DESTROY_BODY, true, false)
options.add_menu_item(OPTION_TEST_CASE_CHANGE_POSITIONS, true, false)
options.connect("option_selected", self, "_on_option_selected")
options.connect("option_changed", self, "_on_option_changed")
_selected_joint = _joint_types.values()[0]
_update_joint = true
func _process(_delta):
if _update_joint:
_update_joint = false
_create_joint()
$LabelJointType.text = "Joint Type: " + _selected_joint.name
func _input(event):
var key_event = event as InputEventKey
if key_event and not key_event.pressed:
var joint_index = key_event.scancode - KEY_1
if joint_index >= 0 and joint_index < _joint_types.size():
_selected_joint = _joint_types.values()[joint_index]
_update_joint = true
func _on_option_selected(option):
if _joint_types.has(option):
_selected_joint = _joint_types[option]
_update_joint = true
func _on_option_changed(option, checked):
match option:
OPTION_TEST_CASE_BODIES_COLLIDE:
_bodies_collide = checked
_update_joint = true
OPTION_TEST_CASE_WORLD_ATTACHMENT:
_world_attachement = checked
_update_joint = true
OPTION_TEST_CASE_DYNAMIC_ATTACHMENT:
_dynamic_attachement = checked
_update_joint = true
OPTION_TEST_CASE_DESTROY_BODY:
_destroy_body = checked
_update_joint = true
OPTION_TEST_CASE_CHANGE_POSITIONS:
_change_positions = checked
_update_joint = true
func _create_joint():
cancel_timer()
var root = $Objects
while root.get_child_count():
var last_child_index = root.get_child_count() - 1
var last_child = root.get_child(last_child_index)
root.remove_child(last_child)
last_child.queue_free()
var child_body = create_rigidbody_box(BOX_SIZE, true, true)
child_body.mode = RigidBody2D.MODE_RIGID
if _change_positions:
root.add_child(child_body)
child_body.position = Vector2(0.0, 40)
else:
child_body.position = Vector2(0.0, 40)
root.add_child(child_body)
var parent_body = null
if not _world_attachement:
parent_body = create_rigidbody_box(BOX_SIZE, true, true)
if _dynamic_attachement:
parent_body.mode = RigidBody2D.MODE_RIGID
parent_body.gravity_scale = 0.0
child_body.gravity_scale = 0.0
else:
parent_body.mode = RigidBody2D.MODE_STATIC
if _change_positions:
root.add_child(parent_body)
parent_body.position = Vector2(0.0, -40)
else:
parent_body.position = Vector2(0.0, -40)
root.add_child(parent_body)
var joint = _selected_joint.duplicate()
joint.visible = true
joint.disable_collision = not _bodies_collide
if parent_body:
joint.node_a = parent_body.get_path()
joint.node_b = child_body.get_path()
root.add_child(joint)
if _destroy_body:
yield(start_timer(0.5), "timeout")
if is_timer_canceled():
return
child_body.queue_free()

View File

@@ -0,0 +1,31 @@
[gd_scene load_steps=3 format=2]
[ext_resource path="res://tests/functional/test_joints.gd" type="Script" id=2]
[ext_resource path="res://tests/test_options.tscn" type="PackedScene" id=4]
[node name="JointTest2D" type="Node2D"]
script = ExtResource( 2 )
[node name="LabelJointType" type="Label" parent="."]
margin_left = 14.0
margin_top = 79.0
margin_right = 145.0
margin_bottom = 93.0
text = "Joint Type: "
__meta__ = {
"_edit_use_anchors_": false
}
[node name="Options" parent="." instance=ExtResource( 4 )]
[node name="Joints" type="Node2D" parent="."]
position = Vector2( 512, 200 )
[node name="PinJoint2D" type="PinJoint2D" parent="Joints"]
[node name="DampedSpringJoint2D" type="DampedSpringJoint2D" parent="Joints"]
[node name="GrooveJoint2D" type="GrooveJoint2D" parent="Joints"]
[node name="Objects" type="Node2D" parent="."]
position = Vector2( 512, 200 )

View File

@@ -0,0 +1,497 @@
extends Test
tool
signal all_tests_done()
signal test_done()
const OPTION_OBJECT_TYPE_RIGIDBODY = "Object type/Rigid body (1)"
const OPTION_OBJECT_TYPE_KINEMATIC = "Object type/Kinematic body (2)"
const OPTION_TEST_CASE_ALL = "Test Cases/TEST ALL (0)"
const OPTION_TEST_CASE_ALL_RIGID = "Test Cases/All Rigid Body tests"
const OPTION_TEST_CASE_ALL_KINEMATIC = "Test Cases/All Kinematic Body tests"
const OPTION_TEST_CASE_ALL_ANGLES_RIGID = "Test Cases/Around the clock (Rigid Body)"
const OPTION_TEST_CASE_ALL_ANGLES_KINEMATIC = "Test Cases/Around the clock (Kinematic Body)"
const OPTION_TEST_CASE_MOVING_PLATFORM_RIGID = "Test Cases/Moving Platform (Rigid Body)"
const OPTION_TEST_CASE_MOVING_PLATFORM_KINEMATIC = "Test Cases/Moving Platform (Kinematic Body)"
const TEST_ALL_ANGLES_STEP = 15.0
const TEST_ALL_ANGLES_MAX = 344.0
export(float, 32, 128, 0.1) var _platform_size = 64.0 setget _set_platform_size
export(float, 0, 360, 0.1) var _platform_angle = 0.0 setget _set_platform_angle
export(float) var _platform_speed = 0.0
export(float, 0, 360, 0.1) var _body_angle = 0.0 setget _set_rigidbody_angle
export(Vector2) var _body_velocity = Vector2(400.0, 0.0)
export(bool) var _use_kinematic_body = false
onready var options = $Options
var _rigid_body_template = null
var _kinematic_body_template = null
var _moving_body = null
var _platform_template = null
var _platform_body = null
var _platform_velocity = Vector2.ZERO
var _contact_detected = false
var _target_entered = false
var _test_passed = false
var _test_step = 0
var _test_all_angles = false
var _lock_controls = false
var _test_canceled = false
func _ready():
if not Engine.editor_hint:
options.add_menu_item(OPTION_OBJECT_TYPE_RIGIDBODY, true, not _use_kinematic_body, true)
options.add_menu_item(OPTION_OBJECT_TYPE_KINEMATIC, true, _use_kinematic_body, true)
options.add_menu_item(OPTION_TEST_CASE_ALL)
options.add_menu_item(OPTION_TEST_CASE_ALL_RIGID)
options.add_menu_item(OPTION_TEST_CASE_ALL_KINEMATIC)
options.add_menu_item(OPTION_TEST_CASE_ALL_ANGLES_RIGID)
options.add_menu_item(OPTION_TEST_CASE_ALL_ANGLES_KINEMATIC)
options.add_menu_item(OPTION_TEST_CASE_MOVING_PLATFORM_RIGID)
options.add_menu_item(OPTION_TEST_CASE_MOVING_PLATFORM_KINEMATIC)
options.connect("option_selected", self, "_on_option_selected")
$Controls/PlatformSize/HSlider.value = _platform_size
$Controls/PlatformAngle/HSlider.value = _platform_angle
$Controls/BodyAngle/HSlider.value = _body_angle
$TargetArea2D.connect("body_entered", self, "_on_target_entered")
$Timer.connect("timeout", self, "_on_timeout")
_rigid_body_template = $RigidBody2D
remove_child(_rigid_body_template)
_kinematic_body_template = $KinematicBody2D
remove_child(_kinematic_body_template)
_platform_template = $OneWayKinematicBody2D
remove_child(_platform_template)
_start_test()
func _process(_delta):
if not Engine.editor_hint:
if Input.is_action_just_pressed("ui_accept"):
_reset_test(false)
func _physics_process(delta):
if not Engine.editor_hint:
if _moving_body and not _contact_detected:
if _use_kinematic_body:
var collision = _moving_body.move_and_collide(_body_velocity * delta, false)
if collision:
var colliding_body = collision.collider
_on_contact_detected(colliding_body)
if _platform_body and _platform_velocity != Vector2.ZERO:
var motion = _platform_velocity * delta
_platform_body.global_position += motion
func _input(event):
var key_event = event as InputEventKey
if key_event and not key_event.pressed:
if key_event.scancode == KEY_0:
_on_option_selected(OPTION_TEST_CASE_ALL)
if key_event.scancode == KEY_1:
_on_option_selected(OPTION_OBJECT_TYPE_RIGIDBODY)
elif key_event.scancode == KEY_2:
_on_option_selected(OPTION_OBJECT_TYPE_KINEMATIC)
func _exit_tree():
if not Engine.editor_hint:
_rigid_body_template.free()
_kinematic_body_template.free()
_platform_template.free()
func _set_platform_size(value, reset = true):
if _lock_controls:
return
if value == _platform_size:
return
_platform_size = value
if is_inside_tree():
if Engine.editor_hint:
$OneWayKinematicBody2D/CollisionShape2D.shape.extents.x = value
else:
var platform_collision = _platform_template.get_child(0)
platform_collision.shape.extents.x = value
if _platform_body:
# Bug: need to re-add when changing shape.
var child_index = _platform_body.get_index()
remove_child(_platform_body)
add_child(_platform_body)
move_child(_platform_body, child_index)
if reset:
_reset_test()
func _set_platform_angle(value, reset = true):
if _lock_controls:
return
if value == _platform_angle:
return
_platform_angle = value
if is_inside_tree():
if Engine.editor_hint:
$OneWayKinematicBody2D.rotation = deg2rad(value)
else:
if _platform_body:
_platform_body.rotation = deg2rad(value)
_platform_template.rotation = deg2rad(value)
if reset:
_reset_test()
func _set_rigidbody_angle(value, reset = true):
if _lock_controls:
return
if value == _body_angle:
return
_body_angle = value
if is_inside_tree():
if Engine.editor_hint:
$RigidBody2D.rotation = deg2rad(value)
$KinematicBody2D.rotation = deg2rad(value)
else:
if _moving_body:
_moving_body.rotation = deg2rad(value)
_rigid_body_template.rotation = deg2rad(value)
_kinematic_body_template.rotation = deg2rad(value)
if reset:
_reset_test()
func _on_option_selected(option):
match option:
OPTION_OBJECT_TYPE_KINEMATIC:
_use_kinematic_body = true
_reset_test()
OPTION_OBJECT_TYPE_RIGIDBODY:
_use_kinematic_body = false
_reset_test()
OPTION_TEST_CASE_ALL:
_test_all()
OPTION_TEST_CASE_ALL_RIGID:
_test_all_rigid_body()
OPTION_TEST_CASE_ALL_KINEMATIC:
_test_all_kinematic_body()
OPTION_TEST_CASE_ALL_ANGLES_RIGID:
_use_kinematic_body = false
_test_all_angles = true
_reset_test(false)
OPTION_TEST_CASE_ALL_ANGLES_KINEMATIC:
_use_kinematic_body = true
_test_all_angles = true
_reset_test(false)
OPTION_TEST_CASE_MOVING_PLATFORM_RIGID:
_use_kinematic_body = false
_test_moving_platform()
OPTION_TEST_CASE_MOVING_PLATFORM_KINEMATIC:
_use_kinematic_body = true
_test_moving_platform()
func _start_test_case(option):
Log.print_log("* Starting " + option)
_on_option_selected(option)
yield(self, "all_tests_done")
func _wait_for_test():
_reset_test()
yield(self, "test_done")
func _test_all_rigid_body():
Log.print_log("* All RigidBody test cases...")
_set_platform_size(64.0, false)
_set_rigidbody_angle(0.0, false)
yield(_start_test_case(OPTION_TEST_CASE_ALL_ANGLES_RIGID), "completed")
if _test_canceled:
return
_set_platform_size(64.0, false)
_set_rigidbody_angle(45.0, false)
yield(_start_test_case(OPTION_TEST_CASE_ALL_ANGLES_RIGID), "completed")
if _test_canceled:
return
_set_platform_size(32.0, false)
_set_rigidbody_angle(45.0, false)
yield(_start_test_case(OPTION_TEST_CASE_ALL_ANGLES_RIGID), "completed")
if _test_canceled:
return
yield(_start_test_case(OPTION_TEST_CASE_MOVING_PLATFORM_RIGID), "completed")
if _test_canceled:
return
func _test_all_kinematic_body():
Log.print_log("* All KinematicBody test cases...")
_set_platform_size(64.0, false)
_set_rigidbody_angle(0.0, false)
yield(_start_test_case(OPTION_TEST_CASE_ALL_ANGLES_KINEMATIC), "completed")
if _test_canceled:
return
_set_platform_size(64.0, false)
_set_rigidbody_angle(45.0, false)
yield(_start_test_case(OPTION_TEST_CASE_ALL_ANGLES_KINEMATIC), "completed")
if _test_canceled:
return
_set_platform_size(32.0, false)
_set_rigidbody_angle(45.0, false)
yield(_start_test_case(OPTION_TEST_CASE_ALL_ANGLES_KINEMATIC), "completed")
if _test_canceled:
return
yield(_start_test_case(OPTION_TEST_CASE_MOVING_PLATFORM_KINEMATIC), "completed")
if _test_canceled:
return
func _test_moving_platform():
Log.print_log("* Start moving platform tests")
Log.print_log("* Platform moving away from body...")
_set_platform_size(64.0, false)
_set_rigidbody_angle(0.0, false)
_platform_speed = 50.0
_set_platform_angle(90.0, false)
yield(_wait_for_test(), "completed")
if _test_canceled:
return
_set_platform_angle(-90.0, false)
yield(_wait_for_test(), "completed")
if _test_canceled:
return
Log.print_log("* Platform moving towards body...")
_set_platform_size(64.0, false)
_set_rigidbody_angle(0.0, false)
_platform_speed = -50.0
_set_platform_angle(90.0, false)
yield(_wait_for_test(), "completed")
if _test_canceled:
return
_set_platform_angle(-90.0, false)
yield(_wait_for_test(), "completed")
if _test_canceled:
return
_platform_speed = 0.0
emit_signal("all_tests_done")
func _test_all():
Log.print_log("* TESTING ALL...")
yield(_test_all_rigid_body(), "completed")
if _test_canceled:
return
yield(_test_all_kinematic_body(), "completed")
if _test_canceled:
return
Log.print_log("* Done.")
func _start_test():
var test_label = "Testing: "
var platform_angle = _platform_template.rotation
if _platform_body:
platform_angle = _platform_body.rotation
remove_child(_platform_body)
_platform_body.queue_free()
_platform_body = null
_platform_body = _platform_template.duplicate()
_platform_body.rotation = platform_angle
add_child(_platform_body)
if _use_kinematic_body:
test_label += _kinematic_body_template.name
_moving_body = _kinematic_body_template.duplicate()
else:
test_label += _rigid_body_template.name
_moving_body = _rigid_body_template.duplicate()
_moving_body.linear_velocity = _body_velocity
_moving_body.connect("body_entered", self, "_on_contact_detected")
add_child(_moving_body)
if _platform_speed != 0.0:
var platform_pos = _platform_body.global_position
var body_pos = _moving_body.global_position
var dir = (platform_pos - body_pos).normalized()
_platform_velocity = dir * _platform_speed
else:
_platform_velocity = Vector2.ZERO
if _test_all_angles:
test_label += " - All angles"
$LabelTestType.text = test_label
_contact_detected = false
_target_entered = false
_test_passed = false
_test_step += 1
$Timer.start()
$LabelResult.text = "..."
$LabelResult.self_modulate = Color.white
func _reset_test(cancel_test = true):
_test_canceled = true
_on_timeout()
_test_canceled = false
_test_step = 0
if _test_all_angles:
if cancel_test:
Log.print_log("*** Stop around the clock tests")
_test_all_angles = false
emit_signal("all_tests_done")
else:
Log.print_log("*** Start around the clock tests")
_platform_body.rotation = deg2rad(_platform_angle)
_lock_controls = true
$Controls/PlatformAngle/HSlider.value = _platform_angle
_lock_controls = false
_next_test(true)
func _next_test(force_start = false):
if _moving_body:
remove_child(_moving_body)
_moving_body.queue_free()
_moving_body = null
if _test_all_angles:
var angle = rad2deg(_platform_body.rotation)
if angle >= _platform_angle + TEST_ALL_ANGLES_MAX:
_platform_body.rotation = deg2rad(_platform_angle)
_lock_controls = true
$Controls/PlatformAngle/HSlider.value = _platform_angle
_lock_controls = false
_test_all_angles = false
Log.print_log("*** Done all angles")
else:
angle = _platform_angle + _test_step * TEST_ALL_ANGLES_STEP
_platform_body.rotation = deg2rad(angle)
_lock_controls = true
$Controls/PlatformAngle/HSlider.value = angle
_lock_controls = false
_start_test()
elif force_start:
_start_test()
func _on_contact_detected(_body):
if _contact_detected or _target_entered:
return
_contact_detected = true
_test_passed = _should_collide()
_set_result()
_on_timeout()
func _on_target_entered(_body):
if _contact_detected or _target_entered:
return
_target_entered = true
_test_passed = not _should_collide()
_set_result()
_on_timeout()
func _should_collide():
var platform_rotation = round(rad2deg(_platform_body.rotation))
var angle = fposmod(platform_rotation, 360)
return angle > 180
func _on_timeout():
cancel_timer()
if $Timer.is_stopped():
return
$Timer.stop()
if _test_canceled:
emit_signal("test_done")
emit_signal("all_tests_done")
return
if not _contact_detected and not _target_entered:
Log.print_log("Test TIMEOUT")
_set_result()
yield(start_timer(0.5), "timeout")
if _test_canceled:
emit_signal("test_done")
emit_signal("all_tests_done")
return
var was_all_angles = _test_all_angles
_next_test()
emit_signal("test_done")
if was_all_angles and not _test_all_angles:
emit_signal("all_tests_done")
func _set_result():
var result = ""
if _test_passed:
result = "PASSED"
$LabelResult.self_modulate = Color.green
else:
result = "FAILED"
$LabelResult.self_modulate = Color.red
$LabelResult.text = result
var platform_angle = rad2deg(_platform_body.rotation)
result += ": size=%.1f, angle=%.1f, body angle=%.1f" % [_platform_size, platform_angle, _body_angle]
Log.print_log("Test %s" % result)

View File

@@ -0,0 +1,244 @@
[gd_scene load_steps=9 format=2]
[ext_resource path="res://tests/functional/test_one_way_collision.gd" type="Script" id=1]
[ext_resource path="res://icon.png" type="Texture" id=2]
[ext_resource path="res://tests/test_options.tscn" type="PackedScene" id=3]
[ext_resource path="res://utils/label_slider_value.gd" type="Script" id=4]
[ext_resource path="res://utils/slider.gd" type="Script" id=5]
[sub_resource type="RectangleShape2D" id=1]
extents = Vector2( 32, 32 )
[sub_resource type="RectangleShape2D" id=2]
extents = Vector2( 64, 32 )
[sub_resource type="RectangleShape2D" id=3]
extents = Vector2( 32, 32 )
[node name="Test" type="Node2D"]
script = ExtResource( 1 )
[node name="LabelTestType" type="Label" parent="."]
margin_left = 14.0
margin_top = 79.0
margin_right = 145.0
margin_bottom = 93.0
text = "Testing: "
__meta__ = {
"_edit_use_anchors_": false
}
[node name="Options" parent="." instance=ExtResource( 3 )]
[node name="Controls" type="VBoxContainer" parent="."]
pause_mode = 2
anchor_right = 1.0
anchor_bottom = 1.0
margin_left = 25.3619
margin_top = 416.765
margin_right = 265.362
margin_bottom = 484.765
custom_constants/separation = 10
__meta__ = {
"_edit_use_anchors_": false
}
[node name="PlatformSize" type="HBoxContainer" parent="Controls"]
margin_right = 432.0
margin_bottom = 16.0
custom_constants/separation = 20
alignment = 2
__meta__ = {
"_edit_use_anchors_": false
}
[node name="Label" type="Label" parent="Controls/PlatformSize"]
margin_left = 8.0
margin_top = 1.0
margin_right = 92.0
margin_bottom = 15.0
text = "Platform size"
[node name="HSlider" type="HSlider" parent="Controls/PlatformSize"]
margin_left = 112.0
margin_right = 312.0
margin_bottom = 16.0
rect_min_size = Vector2( 200, 0 )
min_value = 32.0
max_value = 128.0
value = 64.0
script = ExtResource( 5 )
[node name="LabelValue" type="Label" parent="Controls/PlatformSize"]
margin_left = 332.0
margin_top = 1.0
margin_right = 432.0
margin_bottom = 15.0
rect_min_size = Vector2( 100, 0 )
text = "64.0"
script = ExtResource( 4 )
[node name="PlatformAngle" type="HBoxContainer" parent="Controls"]
margin_top = 26.0
margin_right = 432.0
margin_bottom = 42.0
custom_constants/separation = 20
alignment = 2
__meta__ = {
"_edit_use_anchors_": false
}
[node name="Label" type="Label" parent="Controls/PlatformAngle"]
margin_top = 1.0
margin_right = 92.0
margin_bottom = 15.0
text = "Platform angle"
[node name="HSlider" type="HSlider" parent="Controls/PlatformAngle"]
margin_left = 112.0
margin_right = 312.0
margin_bottom = 16.0
rect_min_size = Vector2( 200, 0 )
max_value = 360.0
script = ExtResource( 5 )
snap_step = 5.0
[node name="LabelValue" type="Label" parent="Controls/PlatformAngle"]
margin_left = 332.0
margin_top = 1.0
margin_right = 432.0
margin_bottom = 15.0
rect_min_size = Vector2( 100, 0 )
text = "0.0"
script = ExtResource( 4 )
[node name="BodyAngle" type="HBoxContainer" parent="Controls"]
margin_top = 52.0
margin_right = 432.0
margin_bottom = 68.0
custom_constants/separation = 20
alignment = 2
__meta__ = {
"_edit_use_anchors_": false
}
[node name="Label" type="Label" parent="Controls/BodyAngle"]
margin_left = 22.0
margin_top = 1.0
margin_right = 92.0
margin_bottom = 15.0
text = "Body angle"
[node name="HSlider" type="HSlider" parent="Controls/BodyAngle"]
margin_left = 112.0
margin_right = 312.0
margin_bottom = 16.0
rect_min_size = Vector2( 200, 0 )
max_value = 360.0
script = ExtResource( 5 )
snap_step = 5.0
[node name="LabelValue" type="Label" parent="Controls/BodyAngle"]
margin_left = 332.0
margin_top = 1.0
margin_right = 432.0
margin_bottom = 15.0
rect_min_size = Vector2( 100, 0 )
text = "0.0"
script = ExtResource( 4 )
[node name="LabelResultTitle" type="Label" parent="."]
anchor_left = 0.5
anchor_top = 0.5
anchor_right = 0.5
anchor_bottom = 0.5
margin_left = 34.1273
margin_top = 251.131
margin_right = 88.1273
margin_bottom = 265.131
text = "RESULT: "
align = 1
valign = 1
__meta__ = {
"_edit_use_anchors_": false
}
[node name="LabelResult" type="Label" parent="."]
anchor_left = 0.5
anchor_top = 0.5
anchor_right = 0.5
anchor_bottom = 0.5
margin_left = 34.1273
margin_top = 266.131
margin_right = 88.1273
margin_bottom = 280.131
text = "..."
align = 1
valign = 1
__meta__ = {
"_edit_use_anchors_": false
}
[node name="LabelRestart" type="Label" parent="."]
anchor_left = 0.5
anchor_top = 0.5
anchor_right = 0.5
anchor_bottom = 0.5
margin_left = 34.1273
margin_top = 304.841
margin_right = 139.127
margin_bottom = 318.841
text = "SPACE - RESTART"
align = 1
valign = 1
__meta__ = {
"_edit_use_anchors_": false
}
[node name="Timer" type="Timer" parent="."]
wait_time = 5.0
one_shot = true
[node name="TargetArea2D" type="Area2D" parent="."]
position = Vector2( 724, 300 )
[node name="CollisionShape2D" type="CollisionShape2D" parent="TargetArea2D"]
shape = SubResource( 1 )
[node name="OneWayKinematicBody2D" type="KinematicBody2D" parent="."]
position = Vector2( 512, 300 )
[node name="CollisionShape2D" type="CollisionShape2D" parent="OneWayKinematicBody2D"]
shape = SubResource( 2 )
one_way_collision = true
[node name="RigidBody2D" type="RigidBody2D" parent="."]
position = Vector2( 300, 300 )
collision_mask = 2147483649
gravity_scale = 0.0
contacts_reported = 1
contact_monitor = true
[node name="Sprite" type="Sprite" parent="RigidBody2D"]
self_modulate = Color( 1, 1, 1, 0.501961 )
scale = Vector2( 0.5, 0.5 )
texture = ExtResource( 2 )
[node name="CollisionShape2D" type="CollisionShape2D" parent="RigidBody2D"]
shape = SubResource( 3 )
[node name="KinematicBody2D" type="KinematicBody2D" parent="."]
position = Vector2( 300, 300 )
collision_mask = 2147483649
[node name="Sprite" type="Sprite" parent="KinematicBody2D"]
self_modulate = Color( 1, 1, 1, 0.501961 )
scale = Vector2( 0.5, 0.5 )
texture = ExtResource( 2 )
[node name="CollisionShape2D" type="CollisionShape2D" parent="KinematicBody2D"]
shape = SubResource( 3 )
[connection signal="value_changed" from="Controls/PlatformSize/HSlider" to="." method="_set_platform_size"]
[connection signal="value_changed" from="Controls/PlatformAngle/HSlider" to="." method="_set_platform_angle"]
[connection signal="value_changed" from="Controls/BodyAngle/HSlider" to="." method="_set_rigidbody_angle"]

View File

@@ -0,0 +1,41 @@
extends Test
export(int, 1, 100) var height = 10
export(Vector2) var box_size = Vector2(40.0, 40.0)
export(Vector2) var box_spacing = Vector2(0.0, 0.0)
func _ready():
_create_pyramid()
func _create_pyramid():
var root_node = $Pyramid
var template_body = create_rigidbody_box(box_size, true)
var pos_y = -0.5 * box_size.y - box_spacing.y
for level in height:
var level_index = height - level - 1
var num_boxes = 2 * level_index + 1
var row_node = Node2D.new()
row_node.position = Vector2(0.0, pos_y)
row_node.name = "Row%02d" % (level + 1)
root_node.add_child(row_node)
var pos_x = -0.5 * (num_boxes - 1) * (box_size.x + box_spacing.x)
for box_index in range(num_boxes):
var box = template_body.duplicate()
box.position = Vector2(pos_x, 0.0)
box.name = "Box%02d" % (box_index + 1)
row_node.add_child(box)
pos_x += box_size.x + box_spacing.x
pos_y -= box_size.y + box_spacing.y
template_body.queue_free()

View File

@@ -0,0 +1,12 @@
[gd_scene load_steps=3 format=2]
[ext_resource path="res://tests/functional/test_pyramid.gd" type="Script" id=1]
[ext_resource path="res://tests/static_scene_flat.tscn" type="PackedScene" id=2]
[node name="Test" type="Node2D"]
script = ExtResource( 1 )
[node name="Pyramid" type="Node2D" parent="."]
position = Vector2( 512, 500 )
[node name="StaticSceneFlat" parent="." instance=ExtResource( 2 )]

View File

@@ -0,0 +1,70 @@
extends Test
var _do_raycasts = false
func _ready():
yield(start_timer(0.5), "timeout")
if is_timer_canceled():
return
_do_raycasts = true
func _physics_process(_delta):
if not _do_raycasts:
return
_do_raycasts = false
Log.print_log("* Start Raycasting...")
clear_drawn_nodes()
for node in $Shapes.get_children():
var body = node as PhysicsBody2D
var space_state = body.get_world_2d().direct_space_state
var body_name = String(body.name).substr("RigidBody".length())
Log.print_log("* Testing: %s" % body_name)
var center = body.position
# Raycast entering from the top.
var res = _add_raycast(space_state, center - Vector2(0, 100), center)
Log.print_log("Raycast in: %s" % ("HIT" if res else "NO HIT"))
# Raycast exiting from inside.
center.x -= 20
res = _add_raycast(space_state, center, center + Vector2(0, 200))
Log.print_log("Raycast out: %s" % ("HIT" if res else "NO HIT"))
# Raycast all inside.
center.x += 40
res = _add_raycast(space_state, center, center + Vector2(0, 40))
Log.print_log("Raycast inside: %s" % ("HIT" if res else "NO HIT"))
if String(body.name).ends_with("ConcavePolygon"):
# Raycast inside an internal face.
center.x += 20
res = _add_raycast(space_state, center, center + Vector2(0, 40))
Log.print_log("Raycast inside face: %s" % ("HIT" if res else "NO HIT"))
func _add_raycast(space_state, pos_start, pos_end):
var result = space_state.intersect_ray(pos_start, pos_end)
var color
if result:
color = Color.green
else:
color = Color.red.darkened(0.5)
# Draw raycast line.
add_line(pos_start, pos_end, color)
# Draw raycast arrow.
add_line(pos_end, pos_end + Vector2(-5, -10), color)
add_line(pos_end, pos_end + Vector2(5, -10), color)
return result

View File

@@ -0,0 +1,82 @@
[gd_scene load_steps=7 format=2]
[ext_resource path="res://assets/texture/godot-head.png" type="Texture" id=1]
[ext_resource path="res://tests/functional/test_raycasting.gd" type="Script" id=2]
[sub_resource type="RectangleShape2D" id=1]
extents = Vector2( 40, 60 )
[sub_resource type="CircleShape2D" id=2]
radius = 60.0
[sub_resource type="CapsuleShape2D" id=3]
radius = 30.0
height = 50.0
[sub_resource type="ConcavePolygonShape2D" id=4]
segments = PoolVector2Array( -5.93512, -43.2195, 6.44476, -42.9695, 6.44476, -42.9695, 11.127, -54.3941, 11.127, -54.3941, 26.9528, -49.4309, 26.9528, -49.4309, 26.2037, -36.508, 26.2037, -36.508, 37.5346, -28.1737, 37.5346, -28.1737, 47.6282, -34.3806, 47.6282, -34.3806, 58.0427, -20.9631, 58.0427, -20.9631, 51.113, -10.2876, 51.113, -10.2876, 50.9869, 35.2694, 50.9869, 35.2694, 38.8, 47.5, 38.8, 47.5, 15.9852, 54.3613, 15.9852, 54.3613, -14.9507, 54.1845, -14.9507, 54.1845, -36.5, 48.1, -36.5, 48.1, -50.4828, 36.33, -50.4828, 36.33, -51.3668, -9.98545, -51.3668, -9.98545, -57.8889, -20.5885, -57.8889, -20.5885, -46.9473, -34.7342, -46.9473, -34.7342, -37.4014, -28.547, -37.4014, -28.547, -26.0876, -37.0323, -26.0876, -37.0323, -26.9862, -49.15, -26.9862, -49.15, -11.4152, -54.5332, -11.4152, -54.5332, -5.93512, -43.2195 )
[node name="Test" type="Node2D"]
script = ExtResource( 2 )
[node name="Shapes" type="Node2D" parent="."]
z_index = -1
z_as_relative = false
[node name="RigidBodyRectangle" type="RigidBody2D" parent="Shapes"]
position = Vector2( 114.877, 248.76 )
mode = 1
[node name="CollisionShape2D" type="CollisionShape2D" parent="Shapes/RigidBodyRectangle"]
rotation = -1.19206
scale = Vector2( 1.2, 1.2 )
shape = SubResource( 1 )
[node name="RigidBodySphere" type="RigidBody2D" parent="Shapes"]
position = Vector2( 314.894, 257.658 )
mode = 1
[node name="CollisionShape2D" type="CollisionShape2D" parent="Shapes/RigidBodySphere"]
shape = SubResource( 2 )
[node name="RigidBodyCapsule" type="RigidBody2D" parent="Shapes"]
position = Vector2( 465.629, 261.204 )
mode = 1
[node name="CollisionShape2D" type="CollisionShape2D" parent="Shapes/RigidBodyCapsule"]
rotation = -0.202458
scale = Vector2( 1.2, 1.2 )
shape = SubResource( 3 )
[node name="RigidBodyConvexPolygon" type="RigidBody2D" parent="Shapes"]
position = Vector2( 613.385, 252.771 )
mode = 1
[node name="CollisionPolygon2D" type="CollisionPolygon2D" parent="Shapes/RigidBodyConvexPolygon"]
polygon = PoolVector2Array( 10.7, -54.5, 28.3596, -49.4067, 47.6282, -34.3806, 57.9717, -20.9447, 50.9869, 35.2694, 38.8, 47.5, 15.9852, 54.3613, -14.9507, 54.1845, -36.5, 48.1, -50.4828, 36.33, -58.0115, -20.515, -46.9473, -34.7342, -26.0876, -50.1138, -11.4152, -54.5332 )
[node name="GodotIcon" type="Sprite" parent="Shapes/RigidBodyConvexPolygon"]
modulate = Color( 1, 1, 1, 0.392157 )
texture = ExtResource( 1 )
[node name="RigidBodyConcavePolygon" type="RigidBody2D" parent="Shapes"]
position = Vector2( 771.159, 252.771 )
mode = 1
[node name="CollisionPolygon2D" type="CollisionPolygon2D" parent="Shapes/RigidBodyConcavePolygon"]
polygon = PoolVector2Array( -5.93512, -43.2195, 6.44476, -42.9695, 11.127, -54.3941, 26.9528, -49.4309, 26.2037, -36.508, 37.5346, -28.1737, 47.6282, -34.3806, 58.0427, -20.9631, 51.113, -10.2876, 50.9869, 35.2694, 38.8, 47.5, 15.9852, 54.3613, -14.9507, 54.1845, -36.5, 48.1, -50.4828, 36.33, -51.3668, -9.98545, -57.8889, -20.5885, -46.9473, -34.7342, -37.4014, -28.547, -26.0876, -37.0323, -26.9862, -49.15, -11.4152, -54.5332 )
[node name="GodotIcon" type="Sprite" parent="Shapes/RigidBodyConcavePolygon"]
modulate = Color( 1, 1, 1, 0.392157 )
texture = ExtResource( 1 )
[node name="RigidBodyConcaveSegments" type="RigidBody2D" parent="Shapes"]
position = Vector2( 930.097, 252.771 )
mode = 1
[node name="CollisionShape2D" type="CollisionShape2D" parent="Shapes/RigidBodyConcaveSegments"]
shape = SubResource( 4 )
[node name="GodotIcon" type="Sprite" parent="Shapes/RigidBodyConcaveSegments"]
modulate = Color( 1, 1, 1, 0.392157 )
texture = ExtResource( 1 )

View File

@@ -0,0 +1,72 @@
[gd_scene load_steps=8 format=2]
[ext_resource path="res://assets/texture/godot-head.png" type="Texture" id=1]
[ext_resource path="res://test.gd" type="Script" id=2]
[ext_resource path="res://utils/rigidbody_pick.gd" type="Script" id=3]
[ext_resource path="res://tests/static_scene.tscn" type="PackedScene" id=6]
[sub_resource type="RectangleShape2D" id=1]
extents = Vector2( 20, 30 )
[sub_resource type="CapsuleShape2D" id=2]
radius = 20.0
height = 30.0
[sub_resource type="CircleShape2D" id=3]
radius = 30.0
[node name="Test" type="Node2D"]
script = ExtResource( 2 )
[node name="DynamicShapes" type="Node2D" parent="."]
[node name="RigidBodyRectangle" type="RigidBody2D" parent="DynamicShapes"]
position = Vector2( 96, 127 )
script = ExtResource( 3 )
[node name="CollisionShape2D" type="CollisionShape2D" parent="DynamicShapes/RigidBodyRectangle"]
rotation = 0.675442
shape = SubResource( 1 )
[node name="RigidBodyCapsule" type="RigidBody2D" parent="DynamicShapes"]
position = Vector2( 270.165, 139.444 )
script = ExtResource( 3 )
[node name="CollisionShape2D" type="CollisionShape2D" parent="DynamicShapes/RigidBodyCapsule"]
rotation = -0.202458
shape = SubResource( 2 )
[node name="RigidBodyConcavePolygon" type="RigidBody2D" parent="DynamicShapes"]
position = Vector2( 683.614, 132.749 )
script = ExtResource( 3 )
[node name="CollisionPolygon2D" type="CollisionPolygon2D" parent="DynamicShapes/RigidBodyConcavePolygon"]
scale = Vector2( 0.5, 0.5 )
polygon = PoolVector2Array( -5.93512, -43.2195, 6.44476, -42.9695, 11.127, -54.3941, 26.9528, -49.4309, 26.2037, -36.508, 37.5346, -28.1737, 47.6282, -34.3806, 58.0427, -20.9631, 51.113, -10.2876, 50.9869, 35.2694, 38.8, 47.5, 15.9852, 54.3613, -14.9507, 54.1845, -36.5, 48.1, -50.4828, 36.33, -51.3668, -9.98545, -57.8889, -20.5885, -46.9473, -34.7342, -37.4014, -28.547, -26.0876, -37.0323, -26.9862, -49.15, -11.4152, -54.5332 )
[node name="GodotIcon" type="Sprite" parent="DynamicShapes/RigidBodyConcavePolygon"]
self_modulate = Color( 1, 1, 1, 0.392157 )
scale = Vector2( 0.5, 0.5 )
texture = ExtResource( 1 )
[node name="RigidBodyConvexPolygon" type="RigidBody2D" parent="DynamicShapes"]
position = Vector2( 473.536, 134.336 )
script = ExtResource( 3 )
[node name="CollisionPolygon2D" type="CollisionPolygon2D" parent="DynamicShapes/RigidBodyConvexPolygon"]
scale = Vector2( 0.5, 0.5 )
polygon = PoolVector2Array( 10.7, -54.5, 28.3596, -49.4067, 47.6282, -34.3806, 57.9717, -20.9447, 50.9869, 35.2694, 38.8, 47.5, 15.9852, 54.3613, -14.9507, 54.1845, -36.5, 48.1, -50.4828, 36.33, -58.0115, -20.515, -46.9473, -34.7342, -26.0876, -50.1138, -11.4152, -54.5332 )
[node name="GodotIcon" type="Sprite" parent="DynamicShapes/RigidBodyConvexPolygon"]
self_modulate = Color( 1, 1, 1, 0.392157 )
scale = Vector2( 0.5, 0.5 )
texture = ExtResource( 1 )
[node name="RigidBodySphere" type="RigidBody2D" parent="DynamicShapes"]
position = Vector2( 919.968, 115.129 )
script = ExtResource( 3 )
[node name="CollisionShape2D" type="CollisionShape2D" parent="DynamicShapes/RigidBodySphere"]
shape = SubResource( 3 )
[node name="StaticScene" parent="." instance=ExtResource( 6 )]

View File

@@ -0,0 +1,39 @@
extends Test
export(int) var height = 10
export(int) var width = 1
export(Vector2) var box_size = Vector2(40.0, 40.0)
export(Vector2) var box_spacing = Vector2(0.0, 0.0)
func _ready():
_create_stack()
func _create_stack():
var root_node = $Stack
var template_body = create_rigidbody_box(box_size, true)
var pos_y = -0.5 * box_size.y - box_spacing.y
for level in height:
var row_node = Node2D.new()
row_node.position = Vector2(0.0, pos_y)
row_node.name = "Row%02d" % (level + 1)
root_node.add_child(row_node)
var pos_x = -0.5 * (width - 1) * (box_size.x + box_spacing.x)
for box_index in range(width):
var box = template_body.duplicate()
box.position = Vector2(pos_x, 0.0)
box.name = "Box%02d" % (box_index + 1)
row_node.add_child(box)
pos_x += box_size.x + box_spacing.x
pos_y -= box_size.y + box_spacing.y
template_body.queue_free()

View File

@@ -0,0 +1,12 @@
[gd_scene load_steps=3 format=2]
[ext_resource path="res://tests/functional/test_stack.gd" type="Script" id=1]
[ext_resource path="res://tests/static_scene_flat.tscn" type="PackedScene" id=2]
[node name="Test" type="Node2D"]
script = ExtResource( 1 )
[node name="Stack" type="Node2D" parent="."]
position = Vector2( 512, 500 )
[node name="StaticSceneFlat" parent="." instance=ExtResource( 2 )]

View File

@@ -0,0 +1,155 @@
extends Test
const BOX_SIZE = Vector2(40, 40)
const BOX_SPACE = Vector2(50, 50)
export(int, 1, 1000) var row_size = 100
export(int, 1, 1000) var column_size = 100
var _objects = []
var _log_physics = false
var _log_physics_time = 0
var _log_physics_time_start = 0
func _ready():
yield(start_timer(1.0), "timeout")
if is_timer_canceled():
return
_log_physics_start()
_create_objects()
yield(wait_for_physics_ticks(5), "wait_done")
_log_physics_stop()
yield(start_timer(1.0), "timeout")
if is_timer_canceled():
return
_log_physics_start()
_add_objects()
yield(wait_for_physics_ticks(5), "wait_done")
_log_physics_stop()
yield(start_timer(1.0), "timeout")
if is_timer_canceled():
return
_log_physics_start()
_move_objects()
yield(wait_for_physics_ticks(5), "wait_done")
_log_physics_stop()
yield(start_timer(1.0), "timeout")
if is_timer_canceled():
return
_log_physics_start()
_remove_objects()
yield(wait_for_physics_ticks(5), "wait_done")
_log_physics_stop()
yield(start_timer(1.0), "timeout")
if is_timer_canceled():
return
Log.print_log("* Done.")
func _exit_tree():
for object in _objects:
object.free()
func _physics_process(_delta):
if _log_physics:
var time = OS.get_ticks_usec()
var time_delta = time - _log_physics_time
var time_total = time - _log_physics_time_start
_log_physics_time = time
Log.print_log(" Physics Tick: %.3f ms (total = %.3f ms)" % [0.001 * time_delta, 0.001 * time_total])
func _log_physics_start():
_log_physics = true
_log_physics_time_start = OS.get_ticks_usec()
_log_physics_time = _log_physics_time_start
func _log_physics_stop():
_log_physics = false
func _create_objects():
_objects.clear()
Log.print_log("* Creating objects...")
var timer = OS.get_ticks_usec()
var pos_x = -0.5 * (row_size - 1) * BOX_SPACE.x
for row in row_size:
var pos_y = -0.5 * (column_size - 1) * BOX_SPACE.y
for column in column_size:
# Create a new object and shape every time to avoid the overhead of connecting many bodies to the same shape.
var box = create_rigidbody_box(BOX_SIZE)
box.gravity_scale = 0.0
box.position = Vector2(pos_x, pos_y)
_objects.push_back(box)
pos_y += BOX_SPACE.y
pos_x += BOX_SPACE.x
timer = OS.get_ticks_usec() - timer
Log.print_log(" Create Time: %.3f ms" % (0.001 * timer))
func _add_objects():
var root_node = $Objects
Log.print_log("* Adding objects...")
var timer = OS.get_ticks_usec()
for object in _objects:
root_node.add_child(object)
timer = OS.get_ticks_usec() - timer
Log.print_log(" Add Time: %.3f ms" % (0.001 * timer))
func _move_objects():
Log.print_log("* Moving objects...")
var timer = OS.get_ticks_usec()
for object in _objects:
object.position += BOX_SPACE
timer = OS.get_ticks_usec() - timer
Log.print_log(" Move Time: %.3f ms" % (0.001 * timer))
func _remove_objects():
var root_node = $Objects
Log.print_log("* Removing objects...")
var timer = OS.get_ticks_usec()
# Remove objects in reversed order to avoid the overhead of changing children index in parent.
var object_count = _objects.size()
for object_index in range(object_count):
root_node.remove_child(_objects[object_count - object_index - 1])
timer = OS.get_ticks_usec() - timer
Log.print_log(" Remove Time: %.3f ms" % (0.001 * timer))

View File

@@ -0,0 +1,12 @@
[gd_scene load_steps=2 format=2]
[ext_resource path="res://tests/performance/test_perf_broadphase.gd" type="Script" id=1]
[node name="Test" type="Node2D"]
script = ExtResource( 1 )
_enable_debug_collision = false
row_size = 300
column_size = 300
[node name="Objects" type="Node2D" parent="."]
position = Vector2( 512, 300 )

View File

@@ -0,0 +1,105 @@
[gd_scene load_steps=8 format=2]
[ext_resource path="res://tests/static_scene.tscn" type="PackedScene" id=1]
[ext_resource path="res://tests/performance/test_perf_contacts.gd" type="Script" id=2]
[ext_resource path="res://assets/texture/godot-head.png" type="Texture" id=3]
[ext_resource path="res://tests/test_options.tscn" type="PackedScene" id=4]
[sub_resource type="RectangleShape2D" id=1]
extents = Vector2( 5, 7 )
[sub_resource type="CircleShape2D" id=2]
radius = 5.0
[sub_resource type="CapsuleShape2D" id=3]
radius = 5.0
height = 7.0
[node name="Test" type="Node2D"]
script = ExtResource( 2 )
_enable_debug_collision = false
spawns = [ NodePath("SpawnTarget1"), NodePath("SpawnTarget2"), NodePath("SpawnTarget3"), NodePath("SpawnTarget4"), NodePath("SpawnTarget5"), NodePath("SpawnTarget6"), NodePath("SpawnTarget7"), NodePath("SpawnTarget8"), NodePath("SpawnTarget9") ]
spawn_count = 300
spawn_randomize = Vector2( 10, 10 )
[node name="Options" parent="." instance=ExtResource( 4 )]
[node name="SpawnTarget1" type="Node2D" parent="."]
position = Vector2( 145.646, 109.462 )
[node name="SpawnTarget2" type="Node2D" parent="."]
position = Vector2( 508.14, 109.113 )
[node name="SpawnTarget3" type="Node2D" parent="."]
position = Vector2( 873.995, 110.042 )
[node name="SpawnTarget4" type="Node2D" parent="."]
position = Vector2( 149.646, 301.462 )
[node name="SpawnTarget5" type="Node2D" parent="."]
position = Vector2( 512.14, 301.113 )
[node name="SpawnTarget6" type="Node2D" parent="."]
position = Vector2( 877.995, 302.042 )
[node name="SpawnTarget7" type="Node2D" parent="."]
position = Vector2( 165.646, 507.462 )
[node name="SpawnTarget8" type="Node2D" parent="."]
position = Vector2( 528.14, 507.113 )
[node name="SpawnTarget9" type="Node2D" parent="."]
position = Vector2( 893.995, 508.042 )
[node name="StaticScene" parent="." instance=ExtResource( 1 )]
visible = false
position = Vector2( 0, 125.017 )
[node name="DynamicShapes" type="Node2D" parent="."]
[node name="RigidBodyRectangle" type="RigidBody2D" parent="DynamicShapes"]
position = Vector2( 0, 1024 )
gravity_scale = 0.0
[node name="CollisionShape2D" type="CollisionShape2D" parent="DynamicShapes/RigidBodyRectangle"]
shape = SubResource( 1 )
[node name="RigidBodySphere" type="RigidBody2D" parent="DynamicShapes"]
position = Vector2( 100, 1024 )
gravity_scale = 0.0
[node name="CollisionShape2D" type="CollisionShape2D" parent="DynamicShapes/RigidBodySphere"]
shape = SubResource( 2 )
[node name="RigidBodyCapsule" type="RigidBody2D" parent="DynamicShapes"]
position = Vector2( 200, 1024 )
gravity_scale = 0.0
[node name="CollisionShape2D" type="CollisionShape2D" parent="DynamicShapes/RigidBodyCapsule"]
shape = SubResource( 3 )
[node name="RigidBodyConvexPolygon" type="RigidBody2D" parent="DynamicShapes"]
position = Vector2( 300, 1024 )
gravity_scale = 0.0
[node name="CollisionPolygon2D" type="CollisionPolygon2D" parent="DynamicShapes/RigidBodyConvexPolygon"]
scale = Vector2( 0.1, 0.1 )
polygon = PoolVector2Array( 10.7, -54.5, 28.3596, -49.4067, 47.6282, -34.3806, 57.9717, -20.9447, 50.9869, 35.2694, 38.8, 47.5, 15.9852, 54.3613, -14.9507, 54.1845, -36.5, 48.1, -50.4828, 36.33, -58.0115, -20.515, -46.9473, -34.7342, -26.0876, -50.1138, -11.4152, -54.5332 )
[node name="GodotIcon" type="Sprite" parent="DynamicShapes/RigidBodyConvexPolygon"]
self_modulate = Color( 1, 1, 1, 0.392157 )
scale = Vector2( 0.1, 0.1 )
texture = ExtResource( 3 )
[node name="RigidBodyConcavePolygon" type="RigidBody2D" parent="DynamicShapes"]
position = Vector2( 400, 1024 )
gravity_scale = 0.0
[node name="CollisionPolygon2D" type="CollisionPolygon2D" parent="DynamicShapes/RigidBodyConcavePolygon"]
scale = Vector2( 0.1, 0.1 )
polygon = PoolVector2Array( -5.93512, -43.2195, 6.44476, -42.9695, 11.127, -54.3941, 26.9528, -49.4309, 26.2037, -36.508, 37.5346, -28.1737, 47.6282, -34.3806, 58.0427, -20.9631, 51.113, -10.2876, 50.9869, 35.2694, 38.8, 47.5, 15.9852, 54.3613, -14.9507, 54.1845, -36.5, 48.1, -50.4828, 36.33, -51.3668, -9.98545, -57.8889, -20.5885, -46.9473, -34.7342, -37.4014, -28.547, -26.0876, -37.0323, -26.9862, -49.15, -11.4152, -54.5332 )
[node name="GodotIcon" type="Sprite" parent="DynamicShapes/RigidBodyConcavePolygon"]
self_modulate = Color( 1, 1, 1, 0.392157 )
scale = Vector2( 0.1, 0.1 )
texture = ExtResource( 3 )

View File

@@ -0,0 +1,205 @@
extends Test
const OPTION_TYPE_ALL = "Shape type/All"
const OPTION_TYPE_RECTANGLE = "Shape type/Rectangle"
const OPTION_TYPE_SPHERE = "Shape type/Sphere"
const OPTION_TYPE_CAPSULE = "Shape type/Capsule"
const OPTION_TYPE_CONVEX_POLYGON = "Shape type/Convex Polygon"
const OPTION_TYPE_CONCAVE_POLYGON = "Shape type/Concave Polygon"
export(Array, NodePath) var spawns = Array()
export(int) var spawn_count = 100
export(Vector2) var spawn_randomize
onready var options = $Options
var _object_templates = []
var _log_physics = false
var _log_physics_time = 0
var _log_physics_time_start = 0
func _ready():
yield(start_timer(0.5), "timeout")
if is_timer_canceled():
return
var dynamic_shapes = $DynamicShapes
while dynamic_shapes.get_child_count():
var type_node = dynamic_shapes.get_child(0)
type_node.position = Vector2.ZERO
_object_templates.push_back(type_node)
dynamic_shapes.remove_child(type_node)
options.add_menu_item(OPTION_TYPE_ALL)
options.add_menu_item(OPTION_TYPE_RECTANGLE)
options.add_menu_item(OPTION_TYPE_SPHERE)
options.add_menu_item(OPTION_TYPE_CAPSULE)
options.add_menu_item(OPTION_TYPE_CONVEX_POLYGON)
options.add_menu_item(OPTION_TYPE_CONCAVE_POLYGON)
options.connect("option_selected", self, "_on_option_selected")
_start_all_types()
func _physics_process(_delta):
if _log_physics:
var time = OS.get_ticks_usec()
var time_delta = time - _log_physics_time
var time_total = time - _log_physics_time_start
_log_physics_time = time
Log.print_log(" Physics Tick: %.3f ms (total = %.3f ms)" % [0.001 * time_delta, 0.001 * time_total])
func _log_physics_start():
_log_physics = true
_log_physics_time_start = OS.get_ticks_usec()
_log_physics_time = _log_physics_time_start
func _log_physics_stop():
_log_physics = false
func _exit_tree():
for object_template in _object_templates:
object_template.free()
func _on_option_selected(option):
cancel_timer()
_despawn_objects()
match option:
OPTION_TYPE_ALL:
_start_all_types()
OPTION_TYPE_RECTANGLE:
_start_type(_find_type_index("Rectangle"))
OPTION_TYPE_SPHERE:
_start_type(_find_type_index("Sphere"))
OPTION_TYPE_CAPSULE:
_start_type(_find_type_index("Capsule"))
OPTION_TYPE_CONVEX_POLYGON:
_start_type(_find_type_index("ConvexPolygon"))
OPTION_TYPE_CONCAVE_POLYGON:
_start_type(_find_type_index("ConcavePolygon"))
func _find_type_index(type_name):
for type_index in range(_object_templates.size()):
var type_node = _object_templates[type_index]
if String(type_node.name).find(type_name) > -1:
return type_index
Log.print_error("Invalid shape type: " + type_name)
return -1
func _start_type(type_index):
if type_index < 0:
return
if type_index >= _object_templates.size():
return
yield(start_timer(1.0), "timeout")
if is_timer_canceled():
return
_log_physics_start()
_spawn_objects(type_index)
yield(wait_for_physics_ticks(5), "wait_done")
_log_physics_stop()
yield(start_timer(1.0), "timeout")
if is_timer_canceled():
return
_log_physics_start()
_activate_objects()
yield(wait_for_physics_ticks(5), "wait_done")
_log_physics_stop()
yield(start_timer(5.0), "timeout")
if is_timer_canceled():
return
_log_physics_start()
_despawn_objects()
yield(wait_for_physics_ticks(5), "wait_done")
_log_physics_stop()
yield(start_timer(1.0), "timeout")
func _start_all_types():
Log.print_log("* Start all types.")
for type_index in range(_object_templates.size()):
yield(_start_type(type_index), "completed")
if is_timer_canceled():
return
Log.print_log("* Done all types.")
func _spawn_objects(type_index):
var template_node = _object_templates[type_index]
Log.print_log("* Spawning: " + template_node.name)
for spawn in spawns:
var spawn_parent = get_node(spawn)
for _node_index in range(spawn_count):
# Create a new object and shape every time to avoid the overhead of connecting many bodies to the same shape.
var collision = template_node.get_child(0).duplicate()
if collision is CollisionShape2D:
collision.shape = collision.shape.duplicate()
var body = template_node.duplicate()
body.transform = Transform.IDENTITY
if spawn_randomize != Vector2.ZERO:
body.position.x = randf() * spawn_randomize.x
body.position.y = randf() * spawn_randomize.y
var prev_collision = body.get_child(0)
body.remove_child(prev_collision)
prev_collision.queue_free()
body.add_child(collision)
body.set_sleeping(true)
spawn_parent.add_child(body)
func _activate_objects():
Log.print_log("* Activating")
for spawn in spawns:
var spawn_parent = get_node(spawn)
for node_index in range(spawn_parent.get_child_count()):
var node = spawn_parent.get_child(node_index) as RigidBody2D
node.set_sleeping(false)
func _despawn_objects():
Log.print_log("* Despawning")
for spawn in spawns:
var spawn_parent = get_node(spawn)
var object_count = spawn_parent.get_child_count()
if object_count == 0:
continue
# Remove objects in reversed order to avoid the overhead of changing children index in parent.
for object_index in range(object_count):
var node = spawn_parent.get_child(object_count - object_index - 1)
spawn_parent.remove_child(node)
node.queue_free()

Some files were not shown because too many files have changed in this diff Show More