Added engine force, air resistance, and rolling resistance

also added debug draw 3d addon
This commit is contained in:
Wheelbarrow
2025-07-26 10:16:43 -04:00
parent a28e7d6d13
commit 15547fce8d
40 changed files with 566 additions and 18 deletions

View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2024 DmitriySalnikov
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the Software), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, andor sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -0,0 +1,157 @@
![icon](/images/icon_3d_128.png)
# Debug drawing utility for Godot
This is an add-on for debug drawing in 3D and for some 2D overlays, which is written in `C++` and can be used with `GDScript` or `C#`.
Based on my previous addon, which was developed [only for C#](https://github.com/DmitriySalnikov/godot_debug_draw_cs), and which was inspired by [Zylann's GDScript addon](https://github.com/Zylann/godot_debug_draw)
## [Documentation](https://dd3d.dmitriysalnikov.ru/docs/)
## [Godot 3 version](https://github.com/DmitriySalnikov/godot_debug_draw_3d/tree/godot_3)
## Support me
Your support adds motivation to develop my public projects.
<a href="https://boosty.to/dmitriysalnikov/donate"><img src="/docs/images/boosty.png" alt="Boosty" width=150px/></a>
<a href="#"><img src="/docs/images/USDT-TRC20.png" alt="USDT-TRC20" width=150px/></a>
<b>USDT-TRC20 TEw934PrsffHsAn5M63SoHYRuZo984EF6v</b>
## Features
3D:
* Arrow
* Billboard opaque square
* Box
* Camera Frustum
* Cylinder
* Gizmo
* Grid
* Line
* Line Path
* Line with Arrow
* Plane
* Points
* Position 3D (3 crossing axes)
* Sphere
* 3D Text
2D:
* **[Work in progress]**
Overlay:
* Text (with grouping and coloring)
Precompiled for:
* Windows
* Linux (built on Ubuntu 22.04)
* macOS (10.15+)
* Android (5.0+)
* iOS
* Web (Firefox is supported by Godot 4.3+)
This addon supports working with several World3D and different Viewports.
There is also a no depth test mode and other settings that can be changed for each instance.
This library supports double-precision builds, for more information, [see the documentation](https://dd3d.dmitriysalnikov.ru/docs/?page=md_docs_2DoublePrecision.html).
## [Interactive Web Demo](https://dd3d.dmitriysalnikov.ru/demo/)
[![screenshot_web](/images/screenshot_web.png)](https://dd3d.dmitriysalnikov.ru/demo/)
## Download
To download, use the [Godot Asset Library](https://godotengine.org/asset-library/asset/1766) or use one of the stable versions from the [GitHub Releases](https://github.com/DmitriySalnikov/godot_debug_draw_3d/releases) page.
For versions prior to `1.4.5`, just download one of the `source codes` in the assets. For newer versions, download `debug-draw-3d_[version].zip`.
### Installation
* Close editor
* Copy `addons/debug_draw_3d` to your `addons` folder, create it if the folder doesn't exist
* Launch editor
## Examples
More examples can be found in the `examples_dd3d/` folder.
Simple test:
```gdscript
func _process(delta: float) -> void:
var _time = Time.get_ticks_msec() / 1000.0
var box_pos = Vector3(0, sin(_time * 4), 0)
var line_begin = Vector3(-1, sin(_time * 4), 0)
var line_end = Vector3(1, cos(_time * 4), 0)
DebugDraw3D.draw_box(box_pos, Quaternion.IDENTITY, Vector3(1, 2, 1), Color(0, 1, 0))
DebugDraw3D.draw_line(line_begin, line_end, Color(1, 1, 0))
DebugDraw2D.set_text("Time", _time)
DebugDraw2D.set_text("Frames drawn", Engine.get_frames_drawn())
DebugDraw2D.set_text("FPS", Engine.get_frames_per_second())
DebugDraw2D.set_text("delta", delta)
```
![screenshot_1](/images/screenshot_1.png)
An example of using scoped configs:
```gdscript
@tool
extends Node3D
func _ready():
# Set the base scoped_config.
# Each frame will be reset to these scoped values.
DebugDraw3D.scoped_config().set_thickness(0.1).set_center_brightness(0.6)
func _process(delta):
# Draw using the base scoped config.
DebugDraw3D.draw_box(Vector3.ZERO, Quaternion.IDENTITY, Vector3.ONE * 2, Color.CORNFLOWER_BLUE)
if true:
# Create a scoped config that will exist until exiting this if.
var _s = DebugDraw3D.new_scoped_config().set_thickness(0).set_center_brightness(0.1)
# Draw with a thickness of 0
DebugDraw3D.draw_box(Vector3.ZERO, Quaternion.IDENTITY, Vector3.ONE, Color.RED)
# If necessary, the values inside this scope can be changed
# even before each call to draw_*.
_s.set_thickness(0.05)
DebugDraw3D.draw_box(Vector3(1,0,1), Quaternion.IDENTITY, Vector3.ONE * 1, Color.BLUE_VIOLET)
```
![screenshot_5](/images/screenshot_5.png)
> [!TIP]
>
> If you want to use a non-standard Viewport for rendering a 3d scene, then do not forget to specify it in the scoped config!
## API
This project has a separate [documentation](https://dd3d.dmitriysalnikov.ru/docs/) page.
Also, a list of all functions is available in the documentation inside the editor (see `DebugDraw3D` and `DebugDraw2D`).
![screenshot_4](/images/screenshot_4.png)
## Known issues and limitations
The text in the keys and values of a text group cannot contain multi-line strings.
The entire text overlay can only be placed in one corner.
[Frustum of Camera3D does not take into account the window size from ProjectSettings](https://github.com/godotengine/godot/issues/70362).
## More screenshots
`DebugDrawDemoScene.tscn` in editor
![screenshot_2](/images/screenshot_2.png)
`DebugDrawDemoScene.tscn` in play mode
![screenshot_3](/images/screenshot_3.png)

View File

@@ -0,0 +1,153 @@
[configuration]
entry_symbol = "debug_draw_3d_library_init"
compatibility_minimum = "4.2.2"
reloadable = false
[dependencies]
; example.x86_64 = { "relative or absolute path to the dependency" : "the path relative to the exported project", }
; -------------------------------------
; debug
macos = { }
windows.x86_64 = { }
linux.x86_64 = { }
; by default godot is using threads
web.wasm32.nothreads = {}
web.wasm32 = {}
android.arm32 = { }
android.arm64 = { }
android.x86_32 = { }
android.x86_64 = { }
ios = {}
; -------------------------------------
; release no debug draw
macos.template_release = { }
windows.template_release.x86_64 = { }
linux.template_release.x86_64 = { }
web.template_release.wasm32.nothreads = { }
web.template_release.wasm32 = { }
android.template_release.arm32 = { }
android.template_release.arm64 = { }
android.template_release.x86_32 = { }
android.template_release.x86_64 = { }
ios.template_release = {}
; -------------------------------------
; release forced debug draw
macos.template_release.forced_dd3d = { }
windows.template_release.x86_64.forced_dd3d = { }
linux.template_release.x86_64.forced_dd3d = { }
web.template_release.wasm32.nothreads.forced_dd3d = { }
web.template_release.wasm32.forced_dd3d = { }
ios.template_release.forced_dd3d = {}
[libraries]
; -------------------------------------
; debug
macos = "libs/libdd3d.macos.editor.universal.framework"
windows.x86_64 = "libs/libdd3d.windows.editor.x86_64.dll"
linux.x86_64 = "libs/libdd3d.linux.editor.x86_64.so"
web.wasm32.nothreads = "libs/libdd3d.web.template_debug.wasm32.wasm"
web.wasm32 = "libs/libdd3d.web.template_debug.wasm32.threads.wasm"
android.arm32 = "libs/libdd3d.android.template_debug.arm32.so"
android.arm64 = "libs/libdd3d.android.template_debug.arm64.so"
android.x86_32 = "libs/libdd3d.android.template_debug.x86_32.so"
android.x86_64 = "libs/libdd3d.android.template_debug.x86_64.so"
ios = "libs/libdd3d.ios.template_debug.universal.dylib"
; -------------------------------------
; release no debug draw
macos.template_release = "libs/libdd3d.macos.template_release.universal.framework"
windows.template_release.x86_64 = "libs/libdd3d.windows.template_release.x86_64.dll"
linux.template_release.x86_64 = "libs/libdd3d.linux.template_release.x86_64.so"
web.template_release.wasm32.nothreads = "libs/libdd3d.web.template_release.wasm32.wasm"
web.template_release.wasm32 = "libs/libdd3d.web.template_release.wasm32.threads.wasm"
android.template_release.arm32 = "libs/libdd3d.android.template_release.arm32.so"
android.template_release.arm64 = "libs/libdd3d.android.template_release.arm64.so"
android.template_release.x86_32 = "libs/libdd3d.android.template_release.x86_32.so"
android.template_release.x86_64 = "libs/libdd3d.android.template_release.x86_64.so"
ios.template_release = "libs/libdd3d.ios.template_release.universal.dylib"
; -------------------------------------
; release forced debug draw
macos.template_release.forced_dd3d = "libs/libdd3d.macos.template_release.universal.enabled.framework"
windows.template_release.x86_64.forced_dd3d = "libs/libdd3d.windows.template_release.x86_64.enabled.dll"
linux.template_release.x86_64.forced_dd3d = "libs/libdd3d.linux.template_release.x86_64.enabled.so"
web.template_release.wasm32.nothreads.forced_dd3d = "libs/libdd3d.web.template_release.wasm32.enabled.wasm"
web.template_release.wasm32.forced_dd3d = "libs/libdd3d.web.template_release.wasm32.threads.enabled.wasm"
ios.template_release.forced_dd3d = "libs/libdd3d.ios.template_release.universal.enabled.dylib"
; -------------------------------------
; DOUBLE PRECISION
; -------------------------------------
; -------------------------------------
; debug
macos.double = "libs/libdd3d.macos.editor.universal.double.framework"
windows.x86_64.double = "libs/libdd3d.windows.editor.x86_64.double.dll"
linux.x86_64.double = "libs/libdd3d.linux.editor.x86_64.double.so"
web.wasm32.nothreads.double = "libs/libdd3d.web.template_debug.wasm32.double.wasm"
web.wasm32.double = "libs/libdd3d.web.template_debug.wasm32.threads.double.wasm"
android.arm32.double = "libs/libdd3d.android.template_debug.arm32.double.so"
android.arm64.double = "libs/libdd3d.android.template_debug.arm64.double.so"
android.x86_32.double = "libs/libdd3d.android.template_debug.x86_32.double.so"
android.x86_64.double = "libs/libdd3d.android.template_debug.x86_64.double.so"
ios.double = "libs/libdd3d.ios.template_debug.universal.dylib"
; -------------------------------------
; release no debug draw
macos.template_release.double = "libs/libdd3d.macos.template_release.universal.double.framework"
windows.template_release.x86_64.double = "libs/libdd3d.windows.template_release.x86_64.double.dll"
linux.template_release.x86_64.double = "libs/libdd3d.linux.template_release.x86_64.double.so"
web.template_release.wasm32.nothreads.double = "libs/libdd3d.web.template_release.wasm32.double.wasm"
web.template_release.wasm32.double = "libs/libdd3d.web.template_release.wasm32.threads.double.wasm"
android.template_release.arm32.double = "libs/libdd3d.android.template_release.arm32.double.so"
android.template_release.arm64.double = "libs/libdd3d.android.template_release.arm64.double.so"
android.template_release.x86_32.double = "libs/libdd3d.android.template_release.x86_32.double.so"
android.template_release.x86_64.double = "libs/libdd3d.android.template_release.x86_64.double.so"
ios.template_release.double = "libs/libdd3d.ios.template_release.universal.double.dylib"
; -------------------------------------
; release forced debug draw
macos.template_release.forced_dd3d.double = "libs/libdd3d.macos.template_release.universal.enabled.double.framework"
windows.template_release.x86_64.forced_dd3d.double = "libs/libdd3d.windows.template_release.x86_64.enabled.double.dll"
linux.template_release.x86_64.forced_dd3d.double = "libs/libdd3d.linux.template_release.x86_64.enabled.double.so"
web.template_release.wasm32.nothreads.forced_dd3d.double = "libs/libdd3d.web.template_release.wasm32.enabled.double.wasm"
web.template_release.wasm32.forced_dd3d.double = "libs/libdd3d.web.template_release.wasm32.threads.enabled.double.wasm"
ios.template_release.forced_dd3d.double = "libs/libdd3d.ios.template_release.universal.enabled.double.dylib"

View File

@@ -0,0 +1 @@
uid://svqaxfp5kyrl

View File

View File

@@ -0,0 +1,37 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>libdd3d.macos.editor.universal.dylib</string>
<key>CFBundleName</key>
<string>Debug Draw 3D</string>
<key>CFBundleDisplayName</key>
<string>Debug Draw 3D</string>
<key>CFBundleIdentifier</key>
<string>ru.dmitriysalnikov.dd3d</string>
<key>NSHumanReadableCopyright</key>
<string>Copyright (c) Dmitriy Salnikov.</string>
<key>CFBundleVersion</key>
<string>1.5.1</string>
<key>CFBundleShortVersionString</key>
<string>1.5.1</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CSResourcesFileMapped</key>
<true/>
<key>DTPlatformName</key>
<string>macosx</string>
<key>LSMinimumSystemVersion</key>
<string>10.14</string>
<key>CFBundleSupportedPlatforms</key>
<array>
<string>MacOSX</string>
</array>
</dict>
</plist>

View File

@@ -0,0 +1,37 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>libdd3d.macos.template_release.universal.enabled.dylib</string>
<key>CFBundleName</key>
<string>Debug Draw 3D</string>
<key>CFBundleDisplayName</key>
<string>Debug Draw 3D</string>
<key>CFBundleIdentifier</key>
<string>ru.dmitriysalnikov.dd3d</string>
<key>NSHumanReadableCopyright</key>
<string>Copyright (c) Dmitriy Salnikov.</string>
<key>CFBundleVersion</key>
<string>1.5.1</string>
<key>CFBundleShortVersionString</key>
<string>1.5.1</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CSResourcesFileMapped</key>
<true/>
<key>DTPlatformName</key>
<string>macosx</string>
<key>LSMinimumSystemVersion</key>
<string>10.14</string>
<key>CFBundleSupportedPlatforms</key>
<array>
<string>MacOSX</string>
</array>
</dict>
</plist>

View File

@@ -0,0 +1,37 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>libdd3d.macos.template_release.universal.dylib</string>
<key>CFBundleName</key>
<string>Debug Draw 3D</string>
<key>CFBundleDisplayName</key>
<string>Debug Draw 3D</string>
<key>CFBundleIdentifier</key>
<string>ru.dmitriysalnikov.dd3d</string>
<key>NSHumanReadableCopyright</key>
<string>Copyright (c) Dmitriy Salnikov.</string>
<key>CFBundleVersion</key>
<string>1.5.1</string>
<key>CFBundleShortVersionString</key>
<string>1.5.1</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CSResourcesFileMapped</key>
<true/>
<key>DTPlatformName</key>
<string>macosx</string>
<key>LSMinimumSystemVersion</key>
<string>10.14</string>
<key>CFBundleSupportedPlatforms</key>
<array>
<string>MacOSX</string>
</array>
</dict>
</plist>

35
car.gd
View File

@@ -1,6 +1,10 @@
class_name Car
extends RigidBody3D
## X axis is RPM, Y axis is torque in NM
@export var torque_curve: Curve
@export var air_resistance: float = .3
@export_group("Steering")
## Maximum angle of imaginary wheel at center front of the car
@export var max_steer_angle: float = 30
@@ -18,11 +22,15 @@ extends RigidBody3D
@onready var track: float = front_right.position.distance_to(front_left.position)
var current_steer_angle: float = 0
var rpm: float = 0
func _ready() -> void:
for wheel: Wheel in wheels:
wheel.set_new_car(self)
func _physics_process(delta: float) -> void:
steer(delta)
for wheel: Wheel in wheels:
wheel.apply_forces(self)
apply_air_resistance()
func steer(delta: float) -> void:
var steer_input = Input.get_axis("Steer Right", "Steer Left")
@@ -44,6 +52,25 @@ func steer(delta: float) -> void:
front_right.rotation.y = -inner_angle
front_left.rotation.y = -outer_angle
##Point argument is in local space
func apply_air_resistance() -> void:
var force: Vector3 = air_resistance * linear_velocity * linear_velocity.length()
apply_force(force, center_of_mass)
DebugDraw3D.draw_arrow(
to_global(center_of_mass),
to_global(center_of_mass) + force,
Color.YELLOW,
.2
)
##Point argument is in global space
func get_velocity_at_point(point: Vector3) -> Vector3:
return linear_velocity + angular_velocity.cross(point - center_of_mass)
return linear_velocity + angular_velocity.cross(to_local(point) - center_of_mass)
## Returns torque in NM, per wheel on the drive train
func get_torque_per_wheel() -> float:
var is_powered: Callable = func (wheel: Wheel) -> bool: return wheel.on_drivetrain
var powered_wheel_count: int = wheels.filter(is_powered).size()
if 0 < powered_wheel_count:
var engine_torque: float = Input.get_action_strength("Accelerate") * torque_curve.sample_baked(rpm)
return engine_torque / powered_wheel_count
return 0.0

View File

@@ -1,15 +1,21 @@
[gd_scene load_steps=5 format=3 uid="uid://dklnyvh2pawj1"]
[gd_scene load_steps=6 format=3 uid="uid://dklnyvh2pawj1"]
[ext_resource type="PackedScene" uid="uid://b4q25yxjds0hu" path="res://RX-Car.glb" id="1_7822p"]
[ext_resource type="Script" uid="uid://brdagffuckrxo" path="res://car.gd" id="1_uoj53"]
[ext_resource type="PackedScene" uid="uid://cqcmml6o1x724" path="res://wheel.tscn" id="3_k61xc"]
[sub_resource type="Curve" id="Curve_k61xc"]
_limits = [0.0, 500.0, 0.0, 10000.0]
_data = [Vector2(0, 303.40942), 0.0, 0.0, 0, 0, Vector2(4272.152, 489.27692), 0.0, 0.0, 0, 0, Vector2(8554.853, 31.756958), 0.0, 0.0, 0, 0]
point_count = 3
[sub_resource type="ConvexPolygonShape3D" id="ConvexPolygonShape3D_7822p"]
points = PackedVector3Array(2.639865, -0.93180054, 2.1575794, 2.5861135, 1.1470379, -1.4858942, 2.3804116, 0.5341828, 5.2797356, 2.3804116, 0.18806255, 5.32922, 2.3804116, -0.8661753, 4.864291, 2.3804116, -1.0148906, 4.0564213, 2.6011019, -0.9791671, 0.85025597, 2.590765, -0.8667045, -2.7230182, 2.590765, -0.28533888, -2.7966702, 1.4661236, 1.6421381, -0.30746174, 1.4661236, 1.6421381, 1.965394, 2.2072706, 0.77604365, 5.2682266, 2.4093547, -0.27607727, -5.989025, 2.3804116, 0.40134466, -4.392848, 2.2186413, 0.11079419, -5.824459, 1.82481, 0.6985105, -5.445842, 2.3230424, -0.08025998, 5.6525984, 2.212439, -0.45231283, 5.6169233, 0.3802452, -0.5354029, 5.61232, -2.3812249, -0.8661753, 4.864291, -2.3812249, -1.0148906, 4.0564213, 2.3804116, -1.0148906, -4.7944813, 2.3804116, -0.9804902, -5.7243385, 0.8805454, 1.6670123, -0.30746174, 1.7379808, 0.72020924, -5.445842, 1.0908988, 0.8818908, -5.445842, 0.8805454, 1.6670123, 1.965394, 0.9823625, 1.0935851, 5.340728, 1.5581212, 1.056274, 5.295847, 2.2506852, -0.2766065, -5.998232, 1.3152068, -0.28031117, -6.0511694, 0.3802452, -0.28401583, -6.102956, 0.3802452, -0.05273974, 5.649146, -2.310418, -0.08025998, 5.6537495, -0.38105845, -0.5354029, 5.61232, -2.1574335, -0.42452794, 5.6169233, -2.3812249, 0.18806255, 5.32922, -2.640161, -0.93180054, 2.1575794, -2.601915, -0.9791671, 0.85025597, -2.3812249, -1.0148906, -4.7944813, -2.3812249, -0.9804902, -5.7243385, 0.3802452, -0.4711007, -6.001684, 0.3802452, 1.6881818, -0.30746174, -1.0917118, 0.8818908, -5.445842, -0.38105845, 1.6884462, -0.30746174, 0.3802452, 1.6881818, 1.965394, -0.98317564, 1.0935851, 5.340728, -0.38105845, 1.6884462, 1.965394, -0.38105845, -0.28401583, -6.102956, -0.38105845, -0.05273974, 5.649146, -2.3812249, 0.5341828, 5.2797356, -2.3812249, 0.4148401, 5.296997, -1.559451, 1.056274, 5.295847, -2.2086005, 0.77604365, 5.2682266, -2.5869267, 1.1470379, -1.4858942, -2.5920951, -0.28533888, -2.7966702, -2.5920951, -0.8667045, -2.7230182, -2.415853, -0.28401583, -6.0488677, -2.390011, -0.7981685, -5.8094983, -1.3129189, -0.28401583, -6.0787888, -0.38105845, -0.4711007, -6.001684, -2.3176537, -0.08661085, -5.9372387, -2.2194543, 0.11079419, -5.824459, -1.739311, 0.72020924, -5.445842, -1.4669368, 1.6421381, -0.30746174, -1.4669368, 1.6421381, 1.965394, -1.825623, 0.6985105, -5.445842, -2.3812249, 0.40134466, -4.392848)
[node name="Car" type="RigidBody3D" node_paths=PackedStringArray("front_right", "front_left", "back_right", "back_left")]
mass = 1000.0
script = ExtResource("1_uoj53")
torque_curve = SubResource("Curve_k61xc")
front_right = NodePath("WheelFR")
front_left = NodePath("WheelFL")
back_right = NodePath("WheelRR")
@@ -25,6 +31,7 @@ transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.5505377, 0.29083502, -2.04
[node name="WheelRR" parent="." instance=ExtResource("3_k61xc")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.883119, -0.15691829, 0.9406)
flipped = true
on_drivetrain = true
[node name="WheelFR" parent="." instance=ExtResource("3_k61xc")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.883119, -0.13746506, -1.6053799)
@@ -35,3 +42,7 @@ transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.9021299, -0.15691829, -1.6
[node name="WheelRL" parent="." instance=ExtResource("3_k61xc")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.9021299, -0.13746506, 0.9405999)
on_drivetrain = true
[node name="Camera3D" type="Camera3D" parent="."]
transform = Transform3D(1, 0, 0, 0, 0.9641093, 0.26550564, 0, -0.26550564, 0.9641093, 0, 1.8623276, 4.216471)

3
default_bus_layout.tres Normal file
View File

@@ -0,0 +1,3 @@
[gd_resource type="AudioBusLayout" format=3 uid="uid://di20fp68vrg8a"]
[resource]

View File

@@ -31,9 +31,6 @@ shadow_enabled = true
[node name="WorldEnvironment" type="WorldEnvironment" parent="."]
environment = SubResource("Environment_0xm2m")
[node name="Camera3D" type="Camera3D" parent="."]
transform = Transform3D(0.96653086, -0.21564756, -0.1389759, 0.12064472, -0.09602227, 0.98804075, -0.22641337, -0.97173876, -0.06679173, -2.64523, 9.843718, -35.668438)
[node name="CSGBox3D2" type="CSGBox3D" parent="."]
transform = Transform3D(-1.0000001, 0, 0, 0, -1.0000001, 0, 0, 0, 1, -5.7605286, 1.5558312, -35.098152)
material_override = SubResource("StandardMaterial3D_0xm2m")

View File

@@ -15,6 +15,10 @@ run/main_scene="res://main.tscn"
config/features=PackedStringArray("4.5", "Forward Plus")
config/icon="res://icon.svg"
[debug_draw_3d]
settings/addon_root_folder="res://addons/debug_draw_3d"
[display]
window/stretch/mode="viewport"
@@ -31,6 +35,11 @@ window/stretch/mode="viewport"
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":65,"key_label":0,"unicode":97,"location":0,"echo":false,"script":null)
]
}
Accelerate={
"deadzone": 0.2,
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":87,"key_label":0,"unicode":119,"location":0,"echo":false,"script":null)
]
}
[physics]

View File

@@ -3,40 +3,98 @@ extends RayCast3D
@export var wheel_radius: float = 0.316
@export var flipped: bool = false
@export var on_drivetrain: bool = false
@export var rolling_resistance: float = 2
@export_group("Suspension")
@export var suspension_rest_length: float = 0.1
@export var suspension_stiffness: float = 30_000
@export var suspension_damping: float = 2000
var car: Car
var _last_velocity: Vector3
func _ready() -> void:
target_position *= suspension_rest_length + wheel_radius
$"RX-Wheel".rotate_y(PI if flipped else 0.0)
func apply_forces(car: Car) -> void:
func set_new_car(new_car: Car) -> void:
car = new_car
# Little bit freaky but we put up with it
_last_velocity = car.get_velocity_at_point(get_collision_point())
func _physics_process(_delta: float) -> void:
force_raycast_update()
var force: Vector3 = get_suspension_force(car)
car.apply_force(force, car.to_local(get_collision_point()))
apply_suspension_force()
apply_rolling_resistance()
apply_engine_force()
_last_velocity = car.get_velocity_at_point(get_collision_point())
func get_suspension_force(car: Car) -> Vector3:
func apply_suspension_force() -> void:
var up: Vector3 = global_basis.y
if not is_colliding():
$"RX-Wheel".position = -up * suspension_rest_length
return Vector3.ZERO
return
var collision_point: Vector3 = to_local(get_collision_point())
var wheel_center: Vector3 = collision_point + (up * wheel_radius)
var wheel_center: Vector3 = get_wheel_center()
$"RX-Wheel".position = wheel_center
var suspension_length: float = -up.dot(wheel_center)
var suspension_displacement: float = suspension_rest_length - suspension_length
#https://en.wikipedia.org/wiki/Hookes_law
var hookes_force_scalar: float = suspension_stiffness * suspension_displacement
var wheel_velocity: Vector3 = car.get_velocity_at_point(car.to_local(to_global(wheel_center)))
var wheel_velocity: Vector3 = car.get_velocity_at_point(to_global(wheel_center))
var wheel_up_velocity: float = up.dot(wheel_velocity)
var damping_force_scalar: float = suspension_damping * wheel_up_velocity
var y_force_scalar: float = hookes_force_scalar - damping_force_scalar
var force: Vector3 = Vector3.UP * y_force_scalar
var force: Vector3 = up * y_force_scalar
return force
DebugDraw3D.draw_arrow(
to_global(wheel_center),
to_global(wheel_center + force / 1000),
Color.RED,
.2
)
car.apply_force(force, car.to_local(to_global(wheel_center)))
func apply_rolling_resistance() -> void:
if not is_colliding(): return
var normal: Vector3 = get_collision_normal()
var velocity: Vector3 = car.get_velocity_at_point(get_collision_point())
velocity -= normal * normal.dot(velocity)
var force: Vector3 = -rolling_resistance * velocity
var arrow_tail: Vector3 = to_global(get_wheel_center())
car.apply_force(force, car.to_local(get_collision_point()))
DebugDraw3D.draw_arrow(
arrow_tail,
arrow_tail + force,
Color.ORANGE,
.2
)
func apply_engine_force() -> void:
if not on_drivetrain: return
if not is_colliding(): return
var forwards: Vector3 = -global_basis.z
var torque: float = car.get_torque_per_wheel()
var force: Vector3 = forwards * torque / wheel_radius
var arrow_tail: Vector3 = to_global(get_wheel_center())
car.apply_force(force, car.to_local(get_collision_point()))
DebugDraw3D.draw_arrow(
arrow_tail,
arrow_tail + force / 250,
Color.BLUE,
.2
)
func get_wheel_center() -> Vector3:
var up: Vector3 = global_basis.y
var collision_point: Vector3 = to_local(get_collision_point())
return collision_point + (up * wheel_radius)