Compare commits
146 Commits
3.2-5bd2bb
...
3.3
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bf94d62472 | ||
|
|
95d97d9001 | ||
|
|
53ea602c07 | ||
|
|
874d3bcc33 | ||
|
|
cbb5c94c6f | ||
|
|
44aefaecb6 | ||
|
|
7a7af4cf4e | ||
|
|
1916f87ac5 | ||
|
|
36e8b45bd4 | ||
|
|
89b64e33e2 | ||
|
|
2b10e6724e | ||
|
|
b9685cb369 | ||
|
|
d1f25ca4aa | ||
|
|
11a72411cc | ||
|
|
5057fcff50 | ||
|
|
d791cd9bda | ||
|
|
7d7c728227 | ||
|
|
5fb81434e7 | ||
|
|
c3c4fdf4fa | ||
|
|
9ea18370d3 | ||
|
|
f9333dce01 | ||
|
|
84a87a5128 | ||
|
|
7d64830cfe | ||
|
|
f08916c90f | ||
|
|
89978a7421 | ||
|
|
6ca2a45a21 | ||
|
|
57f8628b50 | ||
|
|
a4e8231f5a | ||
|
|
f71816ed31 | ||
|
|
ef069d49ae | ||
|
|
742ea87708 | ||
|
|
45f5417822 | ||
|
|
f28a09ea0d | ||
|
|
85c1805d33 | ||
|
|
7e129db12e | ||
|
|
7bfc57d1ae | ||
|
|
cd48c9a9cc | ||
|
|
244b759787 | ||
|
|
6875a21545 | ||
|
|
694ee7fa36 | ||
|
|
6e3db7c64d | ||
|
|
2d4d23302a | ||
|
|
4456027f91 | ||
|
|
19312b2899 | ||
|
|
ca17967de1 | ||
|
|
491fb265b1 | ||
|
|
08be1b7f03 | ||
|
|
4ef90a836a | ||
|
|
bfd903a933 | ||
|
|
e0db0b8f6d | ||
|
|
4d21951b71 | ||
|
|
7656c08454 | ||
|
|
e894e4655a | ||
|
|
2ce76ff4e5 | ||
|
|
e5d829eb8f | ||
|
|
7f025e000e | ||
|
|
5132941a84 | ||
|
|
ef265cca0a | ||
|
|
31bb09233b | ||
|
|
57f5e0835d | ||
|
|
814909538f | ||
|
|
94ec2ea5d9 | ||
|
|
40aec7c068 | ||
|
|
ead2777f48 | ||
|
|
0a0d44d4f1 | ||
|
|
4911866f3d | ||
|
|
d7e1052205 | ||
|
|
8e2dbf3f55 | ||
|
|
2ee9b47f6c | ||
|
|
d8dc94c1ff | ||
|
|
d989bf6209 | ||
|
|
021070215c | ||
|
|
ac61cba05b | ||
|
|
21e829416f | ||
|
|
cf7e4b31f4 | ||
|
|
dc5c1016ce | ||
|
|
8a0824a948 | ||
|
|
5c154dac25 | ||
|
|
7f095a6092 | ||
|
|
35687c3ead | ||
|
|
f91fe01f3e | ||
|
|
43d29bfbbb | ||
|
|
7dff4e748d | ||
|
|
4913cd868a | ||
|
|
973c12264c | ||
|
|
fecbed5fb2 | ||
|
|
82e68e378b | ||
|
|
bbf4cff5f7 | ||
|
|
3d6ba65cfc | ||
|
|
ca0f74ee44 | ||
|
|
aa65867e43 | ||
|
|
c2e7a30e42 | ||
|
|
4dbfd92e6f | ||
|
|
c0d9e483c2 | ||
|
|
36db05c3b9 | ||
|
|
fc032119ca | ||
|
|
98ed996780 | ||
|
|
fa83ee0277 | ||
|
|
7c137510e7 | ||
|
|
10a7e3d301 | ||
|
|
feaf406fee | ||
|
|
d90e401d2a | ||
|
|
99ad90bd0d | ||
|
|
4adaaa2eb2 | ||
|
|
b946d20762 | ||
|
|
2a13307276 | ||
|
|
0b3e046953 | ||
|
|
68e095c4d6 | ||
|
|
fe54ebbb3a | ||
|
|
cdf0ed3be9 | ||
|
|
da9e24dfa7 | ||
|
|
1c1ad17b43 | ||
|
|
5618c2b45a | ||
|
|
3878948300 | ||
|
|
ca4cde1c26 | ||
|
|
6a738c1ede | ||
|
|
04e9afb4cf | ||
|
|
e73af12f49 | ||
|
|
6bdbeafca2 | ||
|
|
21cbaafb2f | ||
|
|
35426410d5 | ||
|
|
54a8d37e6c | ||
|
|
d5dae1cbb7 | ||
|
|
06dc40ba65 | ||
|
|
7c604f336d | ||
|
|
e3a31afe40 | ||
|
|
289d658baa | ||
|
|
7a437d1d23 | ||
|
|
08e3f1efd0 | ||
|
|
0d9c0d15c6 | ||
|
|
96baaa09e3 | ||
|
|
e004d2564e | ||
|
|
651ef54920 | ||
|
|
4a60286512 | ||
|
|
1148a6bda0 | ||
|
|
9ad473c633 | ||
|
|
e38be6dec0 | ||
|
|
8241be5817 | ||
|
|
1c836ecde9 | ||
|
|
6dd09308fa | ||
|
|
555e43c896 | ||
|
|
2bd5b1c8ee | ||
|
|
14f2f1a713 | ||
|
|
3d9bcc6d97 | ||
|
|
3147c6c5bd | ||
|
|
20a515153f |
@@ -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
@@ -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
|
||||
|
||||
4
.github/ISSUE_TEMPLATE/bug-report.md
vendored
@@ -1,9 +1,9 @@
|
||||
---
|
||||
name: Bug Report
|
||||
about: Report a bug with one of the demo projects.
|
||||
title: ''
|
||||
title: ""
|
||||
labels: bug
|
||||
assignees: ''
|
||||
assignees: ""
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -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
23
.github/dist/export_presets.cfg
vendored
Normal 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
@@ -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
@@ -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. -->
|
||||
4
.github/workflows/static_checks.yml
vendored
@@ -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
@@ -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
|
||||
*~
|
||||
|
||||
20
2d/bullet_shower/README.md
Normal 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
|
||||
|
||||

|
||||
|
||||

|
||||
BIN
2d/bullet_shower/bullet.png
Normal file
|
After Width: | Height: | Size: 312 B |
@@ -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]
|
||||
|
||||
93
2d/bullet_shower/bullets.gd
Normal 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()
|
||||
BIN
2d/bullet_shower/face_happy.png
Normal file
|
After Width: | Height: | Size: 907 B |
@@ -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]
|
||||
|
||||
BIN
2d/bullet_shower/face_sad.png
Normal file
|
After Width: | Height: | Size: 846 B |
@@ -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
|
After Width: | Height: | Size: 1.9 KiB |
@@ -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]
|
||||
|
||||
33
2d/bullet_shower/player.gd
Normal 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
|
||||
41
2d/bullet_shower/project.godot
Normal 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 )
|
||||
0
2d/bullet_shower/screenshots/.gdignore
Normal file
BIN
2d/bullet_shower/screenshots/collision.png
Normal file
|
After Width: | Height: | Size: 152 KiB |
BIN
2d/bullet_shower/screenshots/no_collision.png
Normal file
|
After Width: | Height: | Size: 150 KiB |
34
2d/bullet_shower/shower.tscn
Normal 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"]
|
||||
@@ -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"]
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
|
||||
@@ -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"]
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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"]
|
||||
|
||||
@@ -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"]
|
||||
|
||||
@@ -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
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
## Copying
|
||||
|
||||
`art/House In a Forest Loop.ogg` Copyright © 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
|
||||
|
||||
@@ -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]
|
||||
|
||||
|
||||
0
2d/dodge_the_creeps/screenshots/.gdignore
Normal file
BIN
2d/dodge_the_creeps/screenshots/dodge.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"]
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -8,11 +8,6 @@
|
||||
|
||||
config_version=4
|
||||
|
||||
_global_script_classes=[ ]
|
||||
_global_script_class_icons={
|
||||
|
||||
}
|
||||
|
||||
[application]
|
||||
|
||||
config/name="HDR for 2D"
|
||||
|
||||
@@ -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 )
|
||||
|
||||
@@ -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 )
|
||||
|
||||
@@ -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 )
|
||||
|
||||
@@ -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 )
|
||||
|
||||
@@ -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"]
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 )
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -8,11 +8,6 @@
|
||||
|
||||
config_version=4
|
||||
|
||||
_global_script_classes=[ ]
|
||||
_global_script_class_icons={
|
||||
|
||||
}
|
||||
|
||||
[application]
|
||||
|
||||
config/name="2D Particles"
|
||||
|
||||
@@ -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"]
|
||||
|
||||
@@ -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"]
|
||||
|
||||
@@ -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 )
|
||||
|
||||
@@ -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]
|
||||
|
||||
|
||||
21
2d/physics_tests/README.md
Normal 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
|
||||
|
||||

|
||||
BIN
2d/physics_tests/assets/texture/godot-head.png
Normal file
|
After Width: | Height: | Size: 5.4 KiB |
34
2d/physics_tests/assets/texture/godot-head.png.import
Normal 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
|
||||
BIN
2d/physics_tests/assets/tileset/tiles_demo.png
Normal file
|
After Width: | Height: | Size: 2.5 KiB |
34
2d/physics_tests/assets/tileset/tiles_demo.png.import
Normal 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
|
||||
335
2d/physics_tests/assets/tileset/tileset.tres
Normal 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
|
After Width: | Height: | Size: 4.3 KiB |
34
2d/physics_tests/icon.png.import
Normal 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
@@ -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"]
|
||||
132
2d/physics_tests/project.godot
Normal 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
|
||||
0
2d/physics_tests/screenshots/.gdignore
Normal file
BIN
2d/physics_tests/screenshots/screenshot.png
Normal file
|
After Width: | Height: | Size: 162 KiB |
134
2d/physics_tests/test.gd
Normal 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
@@ -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)
|
||||
10
2d/physics_tests/tests/dynamic_box.tscn
Normal 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 )
|
||||
165
2d/physics_tests/tests/functional/test_character.gd
Normal 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
|
||||
151
2d/physics_tests/tests/functional/test_character_pixels.gd
Normal 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
|
||||
151
2d/physics_tests/tests/functional/test_character_pixels.tscn
Normal 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
|
||||
}
|
||||
102
2d/physics_tests/tests/functional/test_character_slopes.tscn
Normal 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 )
|
||||
209
2d/physics_tests/tests/functional/test_character_tilemap.gd
Normal 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
|
||||
125
2d/physics_tests/tests/functional/test_character_tilemap.tscn
Normal 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 )
|
||||
208
2d/physics_tests/tests/functional/test_collision_pairs.gd
Normal 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
|
||||
151
2d/physics_tests/tests/functional/test_collision_pairs.tscn
Normal 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"]
|
||||
143
2d/physics_tests/tests/functional/test_joints.gd
Normal 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()
|
||||
31
2d/physics_tests/tests/functional/test_joints.tscn
Normal 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 )
|
||||
497
2d/physics_tests/tests/functional/test_one_way_collision.gd
Normal 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)
|
||||
244
2d/physics_tests/tests/functional/test_one_way_collision.tscn
Normal 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"]
|
||||
41
2d/physics_tests/tests/functional/test_pyramid.gd
Normal 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()
|
||||
12
2d/physics_tests/tests/functional/test_pyramid.tscn
Normal 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 )]
|
||||
70
2d/physics_tests/tests/functional/test_raycasting.gd
Normal 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
|
||||
82
2d/physics_tests/tests/functional/test_raycasting.tscn
Normal 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 )
|
||||
72
2d/physics_tests/tests/functional/test_shapes.tscn
Normal 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 )]
|
||||
39
2d/physics_tests/tests/functional/test_stack.gd
Normal 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()
|
||||
12
2d/physics_tests/tests/functional/test_stack.tscn
Normal 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 )]
|
||||
155
2d/physics_tests/tests/performance/test_perf_broadphase.gd
Normal 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))
|
||||
12
2d/physics_tests/tests/performance/test_perf_broadphase.tscn
Normal 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 )
|
||||
@@ -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 )
|
||||
205
2d/physics_tests/tests/performance/test_perf_contacts.gd
Normal 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()
|
||||