summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authordusoleil <howcansocksbereal@gmail.com>2022-10-09 04:45:45 -0400
committerdusoleil <howcansocksbereal@gmail.com>2022-10-09 04:46:01 -0400
commitf7ec57998a1c3d0cf91c1fb017fd5a91bb1e0b96 (patch)
treece0fbf5ed79731da5b216327a2e5cdc59df39fc6
parent4c9b0fdd23eda730abdc35f935bc011a3aea0765 (diff)
downloadgodot_wildjam_49-duso-water-touchups.tar.gz
godot_wildjam_49-duso-water-touchups.zip
Rework Buoyancy physicsduso-water-touchups
Simplify creating a buoyant object to just extending a class and setting the water plane. Implement a new buoyancy estimation that should be a bit more accurate.
-rw-r--r--Float.gd15
-rw-r--r--Float.tscn18
-rw-r--r--Main.tscn56
-rw-r--r--Ship.gd4
-rw-r--r--project.godot6
-rw-r--r--water/BuoyantBody.gd120
6 files changed, 139 insertions, 80 deletions
diff --git a/Float.gd b/Float.gd
deleted file mode 100644
index 77ffa95..0000000
--- a/Float.gd
+++ /dev/null
@@ -1,15 +0,0 @@
-extends Spatial
-
-onready var inv_gravity = -ProjectSettings.get_setting("physics/3d/default_gravity_vector") * ProjectSettings.get_setting("physics/3d/default_gravity")
-
-func _physics_process(_delta):
- var parent = get_parent()
- var water = get_node("/root/Main/Water")
- var height = self.global_transform.origin.y
- var wave_height = water.height(self.global_transform.origin)
- if height < wave_height:
- var pos = self.global_transform.origin-parent.global_transform.origin
- #buoyancy force is weight of the displaced water
- #we can estimate it by how deep we are in the water
- var buoyancy = inv_gravity * clamp(wave_height-height,0.0,1.0)
- parent.add_force(buoyancy, pos)
diff --git a/Float.tscn b/Float.tscn
deleted file mode 100644
index 6d1ba7e..0000000
--- a/Float.tscn
+++ /dev/null
@@ -1,18 +0,0 @@
-[gd_scene load_steps=4 format=2]
-
-[ext_resource path="res://Float.gd" type="Script" id=1]
-
-[sub_resource type="SpatialMaterial" id=1]
-albedo_color = Color( 0.823529, 0.796078, 0.0588235, 1 )
-
-[sub_resource type="SphereMesh" id=2]
-material = SubResource( 1 )
-radius = 0.5
-height = 1.0
-
-[node name="Float" type="Spatial"]
-script = ExtResource( 1 )
-
-[node name="MeshInstance" type="MeshInstance" parent="."]
-visible = false
-mesh = SubResource( 2 )
diff --git a/Main.tscn b/Main.tscn
index 42f64d4..24c21f5 100644
--- a/Main.tscn
+++ b/Main.tscn
@@ -1,10 +1,8 @@
-[gd_scene load_steps=15 format=2]
+[gd_scene load_steps=14 format=2]
[ext_resource path="res://character/fps_controller/fps_controller.tscn" type="PackedScene" id=1]
[ext_resource path="res://ship/ship/ship.tscn" type="PackedScene" id=2]
[ext_resource path="res://water/Water.tscn" type="PackedScene" id=3]
-[ext_resource path="res://Float.tscn" type="PackedScene" id=4]
-[ext_resource path="res://ship/ship/crate.tscn" type="PackedScene" id=5]
[ext_resource path="res://world/World.tscn" type="PackedScene" id=6]
[ext_resource path="res://Ship.gd" type="Script" id=7]
[ext_resource path="res://FPS.gd" type="Script" id=8]
@@ -18,6 +16,9 @@
[sub_resource type="SpatialMaterial" id=21]
albedo_color = Color( 0.941176, 0.658824, 0.215686, 1 )
+[sub_resource type="BoxShape" id=23]
+extents = Vector3( 10, 5, 55 )
+
[sub_resource type="CapsuleShape" id=22]
radius = 11.4853
height = 97.7559
@@ -72,12 +73,19 @@ acceleration = 10.0
[node name="ShipRigidBody" type="RigidBody" parent="."]
collision_layer = 2
collision_mask = 8
+mass = 10000.0
can_sleep = false
axis_lock_linear_x = true
axis_lock_linear_z = true
linear_damp = 2.0
angular_damp = 2.0
script = ExtResource( 7 )
+water = NodePath("../Water")
+
+[node name="BuoyancyBounds" type="CollisionShape" parent="ShipRigidBody"]
+transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -3, 0 )
+shape = SubResource( 23 )
+disabled = true
[node name="CollisionShape" type="CollisionShape" parent="ShipRigidBody"]
transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 2.78898, 0 )
@@ -85,48 +93,6 @@ shape = SubResource( 22 )
[node name="ship" parent="ShipRigidBody" instance=ExtResource( 2 )]
-[node name="Float" parent="ShipRigidBody" instance=ExtResource( 4 )]
-transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, -9.77011, -3.30323, 53.0825 )
-
-[node name="Float2" parent="ShipRigidBody" instance=ExtResource( 4 )]
-transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, -9.77011, -3.30323, 33.0751 )
-
-[node name="Float3" parent="ShipRigidBody" instance=ExtResource( 4 )]
-transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, -9.77011, -3.30323, 15.7992 )
-
-[node name="Float4" parent="ShipRigidBody" instance=ExtResource( 4 )]
-transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, -9.77011, -3.30323, 0 )
-
-[node name="Float5" parent="ShipRigidBody" instance=ExtResource( 4 )]
-transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, -9.77011, -3.30323, -13.8797 )
-
-[node name="Float6" parent="ShipRigidBody" instance=ExtResource( 4 )]
-transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, -9.77011, -3.30323, -28.8669 )
-
-[node name="Float7" parent="ShipRigidBody" instance=ExtResource( 4 )]
-transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, -9.77011, -3.30323, -48.8743 )
-
-[node name="Float8" parent="ShipRigidBody" instance=ExtResource( 4 )]
-transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 9.77011, -3.30323, 52.7872 )
-
-[node name="Float9" parent="ShipRigidBody" instance=ExtResource( 4 )]
-transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 9.77011, -3.30323, 33.2966 )
-
-[node name="Float10" parent="ShipRigidBody" instance=ExtResource( 4 )]
-transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 9.77011, -3.30323, 16.0946 )
-
-[node name="Float11" parent="ShipRigidBody" instance=ExtResource( 4 )]
-transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 9.77011, -3.30323, 0 )
-
-[node name="Float12" parent="ShipRigidBody" instance=ExtResource( 4 )]
-transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 9.77011, -3.30323, -14.1012 )
-
-[node name="Float13" parent="ShipRigidBody" instance=ExtResource( 4 )]
-transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 9.77011, -3.30323, -29.0883 )
-
-[node name="Float14" parent="ShipRigidBody" instance=ExtResource( 4 )]
-transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 9.77011, -3.30323, -49.022 )
-
[node name="fps_controller" parent="ShipRigidBody" instance=ExtResource( 1 )]
transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 17, 44 )
diff --git a/Ship.gd b/Ship.gd
index feb5ad2..db200bd 100644
--- a/Ship.gd
+++ b/Ship.gd
@@ -1,4 +1,4 @@
-extends RigidBody
+extends BuoyantBody
export var ang_acceleration = 240.0
@@ -29,4 +29,4 @@ func _input(event):
func _integrate_forces(_state):
var stick = Input.get_axis("ship_right","ship_left")
if stick != 0.0:
- self.add_torque(Vector3.UP*stick*ang_acceleration)
+ self.add_torque(Vector3.UP*stick*ang_acceleration*self.mass)
diff --git a/project.godot b/project.godot
index 42f0e5f..1f86ed2 100644
--- a/project.godot
+++ b/project.godot
@@ -9,6 +9,11 @@
config_version=4
_global_script_classes=[ {
+"base": "RigidBody",
+"class": "BuoyantBody",
+"language": "GDScript",
+"path": "res://water/BuoyantBody.gd"
+}, {
"base": "Monument",
"class": "DockMonument",
"language": "GDScript",
@@ -30,6 +35,7 @@ _global_script_classes=[ {
"path": "res://world/monuments/lighthouse/lighthouseMonument.gd"
} ]
_global_script_class_icons={
+"BuoyantBody": "",
"DockMonument": "",
"Monument": "",
"Wave": "",
diff --git a/water/BuoyantBody.gd b/water/BuoyantBody.gd
new file mode 100644
index 0000000..4a9dc78
--- /dev/null
+++ b/water/BuoyantBody.gd
@@ -0,0 +1,120 @@
+extends RigidBody
+class_name BuoyantBody
+
+export(NodePath) var water = NodePath("/root/Main/Water")
+onready var _water = get_node(water)
+
+var volume_half = 0.0
+var volume = 0.0
+var bounding_box = []
+var center_of_mass = Vector3.ZERO
+var volume_up = Vector3.UP
+
+onready var inv_gravity = -ProjectSettings.get_setting("physics/3d/default_gravity_vector") * ProjectSettings.get_setting("physics/3d/default_gravity")
+const POINT_VOLUME_WEIGHT = 0.125
+
+func _ready():
+ for c in get_children():
+ if c is CollisionShape:
+ if c.shape is SphereShape:
+ _init_buoyancy(c.shape.radius,c.shape.radius,c.shape.radius,c.transform)
+ elif c.shape is CapsuleShape:
+ _init_buoyancy(c.shape.radius,c.shape.radius,c.shape.height/2.0,c.transform)
+ elif c.shape is BoxShape:
+ _init_buoyancy(c.shape.extents.x,c.shape.extents.y,c.shape.extents.z,c.transform)
+ else:
+ assert(false,"this collision shape isn't supported for buoyancy")
+ break
+
+func _init_buoyancy(x_rad,y_rad,z_rad,xform):
+ self.volume_half = x_rad * y_rad * z_rad * 4.0
+ self.volume = volume_half * 2.0
+ var aabb = [
+ Vector3(-x_rad,-y_rad,-z_rad),
+ Vector3(-x_rad,-y_rad, z_rad),
+ Vector3(-x_rad, y_rad,-z_rad),
+ Vector3(-x_rad, y_rad, z_rad),
+ Vector3( x_rad,-y_rad,-z_rad),
+ Vector3( x_rad,-y_rad, z_rad),
+ Vector3( x_rad, y_rad,-z_rad),
+ Vector3( x_rad, y_rad, z_rad)
+ ]
+ for p in aabb:
+ self.bounding_box.push_back(xform * p)
+ self.center_of_mass = xform * center_of_mass
+ self.volume_up = (xform.basis * Vector3.UP).normalized()
+
+func _physics_process(_delta):
+ #check if points are submerged
+ #also weight them based on how deep they are to help get a weighted average center point later
+ var submerged = []
+ var sub_weight = []
+ var sub_total = 0.0
+ for p in bounding_box:
+ var g_p = self.global_transform * p
+ var wave_height = _water.height(g_p)
+ var diff = g_p.y - wave_height
+ if diff < 0.0:
+ submerged.push_back(p)
+ sub_weight.push_back(diff)
+ sub_total += diff
+ #if no points are submerged, the whole thing is likely above water
+ #therefore, no buoyant force is applied
+ if submerged.size() == 0:
+ return
+ #if all points are submerged, the whole thing is likely below water
+ #so the buoyant force would be the weight of the water displaced by the entire volume
+ elif submerged.size() == 8:
+ add_central_force(inv_gravity * volume)
+ #if only some points are submerged, we need to estimate the amount of the volume displacing water
+ #the weight of that water is the buoyant force
+ else:
+ #we want to apply the buoyant force to the center of mass of the submerged part of the volume
+ #we can estimate it with a weighted average of the submerged points
+ var force_pnt = Vector3.ZERO
+ for p in range(submerged.size()):
+ force_pnt += submerged[p] * sub_weight[p]
+ force_pnt /= sub_total
+ #apply_force uses global rotation but local origin...
+ force_pnt = self.global_transform.basis * force_pnt
+ #to estimate the submerged part of the volume,
+ #we can see how deep into the water the bottom of an axis-aligned bounding box is
+ #and do an easing and lerp over the volume
+ var lowest = (self.global_transform * bounding_box[0]).y
+ for p in bounding_box:
+ var p_h = (self.global_transform * p).y
+ if p_h < lowest:
+ lowest = p_h
+ var center = self.global_transform * center_of_mass
+ var depth = _water.height(center) - lowest
+ #the water isn't a flat plane
+ #it's possible that some points are submerged,
+ #but the lowest point of the axis-aligned bounding box isn't actually under water
+ #in that case, for simplicity,
+ #just fall back to the old method of applying a small, constant force
+ #proportional to the number of submerged points
+ if depth <= 0.0:
+ add_force(inv_gravity * volume * POINT_VOLUME_WEIGHT * submerged.size(), force_pnt)
+ #lerp the volume against the depth of the axis-aligned bounding box
+ #but that lerp is only linear when the actual bounding box is axis-aligned
+ #for simplicity, we can lerp an easing curve based on how aligned the bounding box is
+ #on one end, it's linear and on the other it uses a basic exponential easing
+ #we want to do an inverse exponential ease for the upper half of the volume if it is also submerged
+ else:
+ var up = self.global_transform.basis * volume_up
+ var aligned = up.dot(Vector3.UP)
+ aligned = abs(aligned)
+ aligned -= 0.5
+ aligned = abs(aligned)
+ aligned *= 2.0
+ var easing_curve = lerp(4.8,1.0,aligned)
+ var breadth = (center.y - lowest)
+ depth = clamp(depth,0.0,breadth*2.0)
+ depth /= breadth
+ var v = clamp(depth,0.0,1.0)
+ v = ease(v,easing_curve)
+ var v2 = clamp(depth-1.0,0.0,1.0)
+ v2 = 1.0 - ease(1.0 - v2,easing_curve)
+ v += v2
+ v = lerp(0.0,volume_half,v)
+ add_force(inv_gravity * v, force_pnt)