Compare commits

..

No commits in common. "e723e0c022299d777367b2373770090803ce5acb" and "1c5222fecf7b2580c850cfec4e4c53e778d0141e" have entirely different histories.

6 changed files with 65 additions and 120 deletions

View File

@ -341,16 +341,16 @@ transform = Transform3D(-0.734269, 0.305072, -0.606448, 0, 0.893336, 0.44939, 0.
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 129.404, -9.53674e-07, 309.4) transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 129.404, -9.53674e-07, 309.4)
[node name="ConcreteBuilding1" parent="CityBuildings" instance=ExtResource("10_lf15j")] [node name="ConcreteBuilding1" parent="CityBuildings" instance=ExtResource("10_lf15j")]
transform = Transform3D(-4.37114e-08, 0, 1, 0, 1, 0, -1, 0, -4.37114e-08, 0, -0.01, 0) transform = Transform3D(-4.37114e-08, 0, 1, 0, 1, 0, -1, 0, -4.37114e-08, 0, 0, 0)
[node name="KanaSignboard" parent="CityBuildings/ConcreteBuilding1" instance=ExtResource("11_evxup")] [node name="KanaSignboard" parent="CityBuildings/ConcreteBuilding1" instance=ExtResource("11_evxup")]
transform = Transform3D(-8.74228e-08, 0, -2, 0, 2, 0, 2, 0, -8.74228e-08, 10.8, 12, 7) transform = Transform3D(-8.74228e-08, 0, -2, 0, 2, 0, 2, 0, -8.74228e-08, 10.8, 12, 7)
[node name="ConcreteBuilding2" parent="CityBuildings" instance=ExtResource("10_lf15j")] [node name="ConcreteBuilding2" parent="CityBuildings" instance=ExtResource("10_lf15j")]
transform = Transform3D(-4.37114e-08, 0, -1, 0, 1, 0, 1, 0, -4.37114e-08, 0, -0.01, 20) transform = Transform3D(-4.37114e-08, 0, -1, 0, 1, 0, 1, 0, -4.37114e-08, 0, 0, 20)
[node name="ConcreteBuilding3" parent="CityBuildings" instance=ExtResource("10_lf15j")] [node name="ConcreteBuilding3" parent="CityBuildings" instance=ExtResource("10_lf15j")]
transform = Transform3D(-4.37114e-08, 0, -1, 0, 1, 0, 1, 0, -4.37114e-08, 0, -0.01, 40) transform = Transform3D(-4.37114e-08, 0, -1, 0, 1, 0, 1, 0, -4.37114e-08, 0, 0, 40)
[node name="PalmTree" parent="CityBuildings" instance=ExtResource("12_sswxf")] [node name="PalmTree" parent="CityBuildings" instance=ExtResource("12_sswxf")]
transform = Transform3D(-0.69799, 0, -0.716107, 0, 1, 0, 0.716107, 0, -0.69799, 11.468, 0, -12.468) transform = Transform3D(-0.69799, 0, -0.716107, 0, 1, 0, 0.716107, 0, -0.69799, 11.468, 0, -12.468)
@ -370,7 +370,7 @@ transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 137.181, -20, -7.285)
curve = SubResource("Curve3D_5n8tb") curve = SubResource("Curve3D_5n8tb")
[node name="ConcreteBuilding1" parent="MountainCurve" instance=ExtResource("10_lf15j")] [node name="ConcreteBuilding1" parent="MountainCurve" instance=ExtResource("10_lf15j")]
transform = Transform3D(-0.0979477, 0, 0.995192, 0, 1, 0, -0.995192, 0, -0.0979477, -10.074, -0.01, -32.347) transform = Transform3D(-0.0979477, 0, 0.995192, 0, 1, 0, -0.995192, 0, -0.0979477, -10.074, 0, -32.347)
[node name="GuardRail" parent="MountainCurve" instance=ExtResource("16_xtxyj")] [node name="GuardRail" parent="MountainCurve" instance=ExtResource("16_xtxyj")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 70.2122, 0, 116.269) transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 70.2122, 0, 116.269)

View File

@ -12,7 +12,6 @@ enum Type {
} }
const TERRAIN_DAMPING_EPSILON := 1e-6 const TERRAIN_DAMPING_EPSILON := 1e-6
const MAGNUS_EPSILON := 1e-3
const IRON_DAMPING := 9999.0 const IRON_DAMPING := 9999.0
## Angular damping while in air ## Angular damping while in air
@ -22,16 +21,6 @@ const IRON_DAMPING := 9999.0
## Angular damping for iron balls ## Angular damping for iron balls
@export var iron_damping := 9999.0 @export var iron_damping := 9999.0
#@export var fluid_density := 1.225
#@export var lift_coefficient := 0.05
#@export var radius := 0.05
## Coefficient of angular velocity influence on linear velocity
## This is approximately 1/2 * rho * C_L * pi * r^2
## where `rho` is the fluid density of the medium, or 1.225 for air at sea level,
## and `C_L` is the lift coefficient which for our purposes is 0.05,
## and `r` is the radius of the ball, which is 5cm.
@export var magnus_coefficient := 0.00024
## Causes the ball to act more like a brick ## Causes the ball to act more like a brick
@export var iron_ball := false: @export var iron_ball := false:
set(value): set(value):
@ -70,31 +59,16 @@ func _total_terrain_angular_damping() -> float:
) )
func _magnus_force() -> Vector3:
return magnus_coefficient * angular_velocity.cross(linear_velocity)
func _integrate_forces(state: PhysicsDirectBodyState3D) -> void: func _integrate_forces(state: PhysicsDirectBodyState3D) -> void:
if not _awake: if not _awake:
# Triggered on first frame after waking # Triggered on first frame after waking
_awake = true _awake = true
_position_on_last_wake = global_position _position_on_last_wake = global_position
_last_contact_normal = Vector3.UP _last_contact_normal = Vector3.UP
# TODO something's fucky here... I think this gets called once after the ball sleeps
var damping := air_damping var damping := air_damping
if state.get_contact_count(): if state.get_contact_count():
constant_force = Vector3.ZERO _last_contact_normal = state.get_contact_local_normal(0)
# We want the contact normal which minimizes the angle to the up vector
var min_dot := -1.0
for i: int in range(state.get_contact_count()):
var norm := state.get_contact_local_normal(i)
var dot := norm.dot(Vector3.UP)
if dot > min_dot:
min_dot = dot
_last_contact_normal = norm
damping = _total_terrain_angular_damping() damping = _total_terrain_angular_damping()
if damping <= TERRAIN_DAMPING_EPSILON: if damping <= TERRAIN_DAMPING_EPSILON:
damping = rough_damping damping = rough_damping
@ -103,13 +77,6 @@ func _integrate_forces(state: PhysicsDirectBodyState3D) -> void:
angular_damp = damping angular_damp = damping
func _physics_process(_delta: float) -> void:
# Simulate magnus effect
var magnus := _magnus_force()
if magnus.length_squared() > MAGNUS_EPSILON:
apply_central_force(magnus)
func enter_zone(zone: BallZone) -> void: func enter_zone(zone: BallZone) -> void:
_zones.push_back(zone) _zones.push_back(zone)

View File

@ -34,13 +34,8 @@ script/source = "extends Control
const COLOR_X := Color(1, 0, 0) const COLOR_X := Color(1, 0, 0)
const COLOR_Y := Color(0, 1, 0) const COLOR_Y := Color(0, 1, 0)
const COLOR_Z := Color(0, 0, 1) const COLOR_Z := Color(0, 0, 1)
const COLOR_MAGNUS := Color.CYAN
const MAGNUS_SCALE := 3
const WIDTH := 4 const WIDTH := 4
@export var draw_reoriented_basis := true
@export var draw_magnus_effect := true
@onready var physics_ball: GameBall = $\"..\" @onready var physics_ball: GameBall = $\"..\"
@ -50,9 +45,9 @@ func _process(_delta: float) -> void:
func _draw() -> void: func _draw() -> void:
var camera := get_viewport().get_camera_3d() if physics_ball._last_contact_normal != null:
var start := camera.unproject_position(physics_ball.global_position) var camera := get_viewport().get_camera_3d()
if draw_reoriented_basis and physics_ball._last_contact_normal != null: var start := camera.unproject_position(physics_ball.global_position)
var basis := physics_ball.get_reoriented_basis() var basis := physics_ball.get_reoriented_basis()
var end_x := camera.unproject_position(physics_ball.global_position + basis.x) var end_x := camera.unproject_position(physics_ball.global_position + basis.x)
var end_y := camera.unproject_position(physics_ball.global_position + basis.y) var end_y := camera.unproject_position(physics_ball.global_position + basis.y)
@ -60,10 +55,6 @@ func _draw() -> void:
draw_line(start, end_x, COLOR_X, WIDTH) draw_line(start, end_x, COLOR_X, WIDTH)
draw_line(start, end_y, COLOR_Y, WIDTH) draw_line(start, end_y, COLOR_Y, WIDTH)
draw_line(start, end_z, COLOR_Z, WIDTH) draw_line(start, end_z, COLOR_Z, WIDTH)
if draw_magnus_effect:
var end := camera.unproject_position(physics_ball.global_position + physics_ball._magnus_force() * MAGNUS_SCALE)
draw_line(start, end, COLOR_MAGNUS, WIDTH)
" "
[node name="PhysicsBall" type="RigidBody3D"] [node name="PhysicsBall" type="RigidBody3D"]
@ -72,7 +63,7 @@ physics_material_override = ExtResource("1_l23pw")
freeze = true freeze = true
continuous_cd = true continuous_cd = true
contact_monitor = true contact_monitor = true
max_contacts_reported = 3 max_contacts_reported = 1
linear_damp_mode = 1 linear_damp_mode = 1
angular_damp_mode = 1 angular_damp_mode = 1
angular_damp = 8.0 angular_damp = 8.0
@ -95,6 +86,5 @@ anchor_bottom = 1.0
grow_horizontal = 2 grow_horizontal = 2
grow_vertical = 2 grow_vertical = 2
script = SubResource("GDScript_p4v7o") script = SubResource("GDScript_p4v7o")
draw_reoriented_basis = false
[connection signal="sleeping_state_changed" from="." to="." method="_on_sleeping_state_changed"] [connection signal="sleeping_state_changed" from="." to="." method="_on_sleeping_state_changed"]

View File

@ -35,12 +35,6 @@ const BIG_POWER_THRESHOLD := 0.7
## Amount of life lost when landing in water ## Amount of life lost when landing in water
const WATER_DAMAGE := 10.0 const WATER_DAMAGE := 10.0
## Angle of influence that shot curve has, in radians
const CURVE_INFLUENCE := PI / 8
## Maximum absolute curve for the "nice shot" animation to play
const NICE_THRESHOLD := 0.2
## In Driving Range mode, the ball can be retrieved in the shot phase. ## In Driving Range mode, the ball can be retrieved in the shot phase.
@export var driving_range := false @export var driving_range := false
@ -114,7 +108,7 @@ var shot_curve: float:
set(value): set(value):
hud.curve_bar.value = value hud.curve_bar.value = value
get: get:
return hud.curve_bar.value return hud.power_bar.value
var game_ball: GameBall: var game_ball: GameBall:
get: get:
@ -237,22 +231,12 @@ func take_shot() -> void:
print_debug("WHACK!\nPower: ", shot_power, "\nCurve: ", shot_curve) print_debug("WHACK!\nPower: ", shot_power, "\nCurve: ", shot_curve)
# Momentary impulse applied to the ball
var impulse := get_shot_impulse(shot_power) var impulse := get_shot_impulse(shot_power)
print_debug("Shot impulse: ", impulse, "; ", impulse.length(), " N*s") print_debug("Shot impulse: ", impulse, "; ", impulse.length(), " N*s")
var curve := shot_ref.global_basis.x.normalized() * shot_curve
# Position where the ball is hit (imparts spin)
var offset := curve * 0.001
print_debug("Shot offset: ", offset, "; ", offset.length(), " m")
# Rotate impulse
impulse = impulse.rotated(Vector3.UP, -shot_curve * CURVE_INFLUENCE)
if game_ball: if game_ball:
game_ball.iron_ball = club == Club.Type.IRON
game_ball.freeze = false game_ball.freeze = false
game_ball.apply_impulse(impulse, offset) game_ball.apply_central_impulse(impulse)
# Use a ball if a limited type is selected # Use a ball if a limited type is selected
if player.get_balls(ball_type) > 0: if player.get_balls(ball_type) > 0:
@ -370,6 +354,8 @@ func _on_club_change(new_club_type: Club.Type) -> void:
wedge_arrow.hide() wedge_arrow.hide()
iron_arrow.hide() iron_arrow.hide()
putt_arrow.hide() putt_arrow.hide()
if game_ball:
game_ball.iron_ball = false
hud.club_selector.value = new_club_type hud.club_selector.value = new_club_type
# TODO club change animation # TODO club change animation
character.hold_right(new_club.get_model()) character.hold_right(new_club.get_model())
@ -386,6 +372,8 @@ func _on_club_change(new_club_type: Club.Type) -> void:
Club.Type.IRON: Club.Type.IRON:
shot_ref = iron_ref shot_ref = iron_ref
iron_arrow.show() iron_arrow.show()
if game_ball:
game_ball.iron_ball = true
Club.Type.SPECIAL: Club.Type.SPECIAL:
# TODO figure this out # TODO figure this out
shot_ref = drive_ref shot_ref = drive_ref
@ -422,11 +410,7 @@ func _on_phase_change(new_phase: Phase) -> void:
hud.power_bar.hide() hud.power_bar.hide()
hud.curve_bar.hide() hud.curve_bar.hide()
if perfect_aim: hud.play_nice_animation()
shot_curve = 0.0
if abs(shot_curve) <= NICE_THRESHOLD:
hud.play_nice_animation()
if not driving_range: if not driving_range:
shot_animation.play("shoot") shot_animation.play("shoot")
@ -442,6 +426,7 @@ func _on_phase_change(new_phase: Phase) -> void:
func _on_game_ball_changed(ball: GameBall) -> void: func _on_game_ball_changed(ball: GameBall) -> void:
if ball: if ball:
ball.iron_ball = (club == Club.Type.IRON)
ball.entered_water.connect(_on_ball_entered_water) ball.entered_water.connect(_on_ball_entered_water)
ball.sleeping_state_changed.connect(_on_ball_sleeping_state_changed) ball.sleeping_state_changed.connect(_on_ball_sleeping_state_changed)

View File

@ -43,10 +43,14 @@ texture = SubResource("GradientTexture2D_tm61r")
[node name="BallList" type="VBoxContainer" parent="GradientMask"] [node name="BallList" type="VBoxContainer" parent="GradientMask"]
unique_name_in_owner = true unique_name_in_owner = true
custom_minimum_size = Vector2(120, 0) custom_minimum_size = Vector2(120, 0)
layout_mode = 0 layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
offset_top = 50.0 offset_top = 50.0
offset_right = 120.0 offset_bottom = 50.0
offset_bottom = 109.0 grow_horizontal = 2
grow_vertical = 2
theme_override_constants/separation = 5 theme_override_constants/separation = 5
[node name="BasicIcon" parent="GradientMask/BallList" instance=ExtResource("1_1v8xg")] [node name="BasicIcon" parent="GradientMask/BallList" instance=ExtResource("1_1v8xg")]

View File

@ -441,26 +441,26 @@ length = 0.001
tracks/0/type = "value" tracks/0/type = "value"
tracks/0/imported = false tracks/0/imported = false
tracks/0/enabled = true tracks/0/enabled = true
tracks/0/path = NodePath("SouthWest:visible") tracks/0/path = NodePath("SouthWest:position")
tracks/0/interp = 1 tracks/0/interp = 1
tracks/0/loop_wrap = true tracks/0/loop_wrap = true
tracks/0/keys = { tracks/0/keys = {
"times": PackedFloat32Array(0), "times": PackedFloat32Array(0),
"transitions": PackedFloat32Array(1), "transitions": PackedFloat32Array(1),
"update": 1, "update": 0,
"values": [true] "values": [Vector2(0, 982)]
} }
tracks/1/type = "value" tracks/1/type = "value"
tracks/1/imported = false tracks/1/imported = false
tracks/1/enabled = true tracks/1/enabled = true
tracks/1/path = NodePath("SouthWest:offset_top") tracks/1/path = NodePath("SouthWest:visible")
tracks/1/interp = 2 tracks/1/interp = 1
tracks/1/loop_wrap = true tracks/1/loop_wrap = true
tracks/1/keys = { tracks/1/keys = {
"times": PackedFloat32Array(0), "times": PackedFloat32Array(0),
"transitions": PackedFloat32Array(1), "transitions": PackedFloat32Array(1),
"update": 0, "update": 1,
"values": [-98.0] "values": [true]
} }
[sub_resource type="Animation" id="Animation_yis4x"] [sub_resource type="Animation" id="Animation_yis4x"]
@ -470,26 +470,26 @@ step = 0.02
tracks/0/type = "value" tracks/0/type = "value"
tracks/0/imported = false tracks/0/imported = false
tracks/0/enabled = true tracks/0/enabled = true
tracks/0/path = NodePath("SouthWest:visible") tracks/0/path = NodePath("SouthWest:position")
tracks/0/interp = 1 tracks/0/interp = 2
tracks/0/loop_wrap = true tracks/0/loop_wrap = true
tracks/0/keys = { tracks/0/keys = {
"times": PackedFloat32Array(0.4), "times": PackedFloat32Array(0, 0.1, 0.4),
"transitions": PackedFloat32Array(1), "transitions": PackedFloat32Array(1.618, 1.618, 1),
"update": 1, "update": 0,
"values": [false] "values": [Vector2(0, 982), Vector2(0, 960), Vector2(0, 1100)]
} }
tracks/1/type = "value" tracks/1/type = "value"
tracks/1/imported = false tracks/1/imported = false
tracks/1/enabled = true tracks/1/enabled = true
tracks/1/path = NodePath("SouthWest:offset_top") tracks/1/path = NodePath("SouthWest:visible")
tracks/1/interp = 2 tracks/1/interp = 1
tracks/1/loop_wrap = true tracks/1/loop_wrap = true
tracks/1/keys = { tracks/1/keys = {
"times": PackedFloat32Array(0, 0.1, 0.4), "times": PackedFloat32Array(0.4),
"transitions": PackedFloat32Array(1.618, 1.618, 1), "transitions": PackedFloat32Array(1),
"update": 0, "update": 1,
"values": [-98.0, -120.0, 20.0] "values": [false]
} }
[sub_resource type="Animation" id="Animation_jugqx"] [sub_resource type="Animation" id="Animation_jugqx"]
@ -499,26 +499,26 @@ step = 0.02
tracks/0/type = "value" tracks/0/type = "value"
tracks/0/imported = false tracks/0/imported = false
tracks/0/enabled = true tracks/0/enabled = true
tracks/0/path = NodePath("SouthWest:visible") tracks/0/path = NodePath("SouthWest:position")
tracks/0/interp = 1 tracks/0/interp = 1
tracks/0/loop_wrap = true tracks/0/loop_wrap = true
tracks/0/keys = { tracks/0/keys = {
"times": PackedFloat32Array(0, 2.4), "times": PackedFloat32Array(0, 0.1, 2.3, 2.4),
"transitions": PackedFloat32Array(1, 1), "transitions": PackedFloat32Array(1.618, 1, 1.618, 1),
"update": 1, "update": 0,
"values": [true, false] "values": [Vector2(0, 1100), Vector2(0, 982), Vector2(0, 982), Vector2(0, 1100)]
} }
tracks/1/type = "value" tracks/1/type = "value"
tracks/1/imported = false tracks/1/imported = false
tracks/1/enabled = true tracks/1/enabled = true
tracks/1/path = NodePath("SouthWest:offset_top") tracks/1/path = NodePath("SouthWest:visible")
tracks/1/interp = 1 tracks/1/interp = 1
tracks/1/loop_wrap = true tracks/1/loop_wrap = true
tracks/1/keys = { tracks/1/keys = {
"times": PackedFloat32Array(0, 0.1, 2.3, 2.4), "times": PackedFloat32Array(0, 2.4),
"transitions": PackedFloat32Array(1.618, 1, 1.618, 1), "transitions": PackedFloat32Array(1, 1),
"update": 0, "update": 1,
"values": [20.0, -98.0, -98.0, 20.0] "values": [true, false]
} }
[sub_resource type="Animation" id="Animation_nicro"] [sub_resource type="Animation" id="Animation_nicro"]
@ -528,26 +528,26 @@ step = 0.02
tracks/0/type = "value" tracks/0/type = "value"
tracks/0/imported = false tracks/0/imported = false
tracks/0/enabled = true tracks/0/enabled = true
tracks/0/path = NodePath("SouthWest:visible") tracks/0/path = NodePath("SouthWest:position")
tracks/0/interp = 1 tracks/0/interp = 2
tracks/0/loop_wrap = true tracks/0/loop_wrap = true
tracks/0/keys = { tracks/0/keys = {
"times": PackedFloat32Array(0), "times": PackedFloat32Array(0, 0.34, 0.4),
"transitions": PackedFloat32Array(1), "transitions": PackedFloat32Array(1.618, 1.618, 1),
"update": 1, "update": 0,
"values": [true] "values": [Vector2(0, 1100), Vector2(0, 960), Vector2(0, 982)]
} }
tracks/1/type = "value" tracks/1/type = "value"
tracks/1/imported = false tracks/1/imported = false
tracks/1/enabled = true tracks/1/enabled = true
tracks/1/path = NodePath("SouthWest:offset_top") tracks/1/path = NodePath("SouthWest:visible")
tracks/1/interp = 2 tracks/1/interp = 1
tracks/1/loop_wrap = true tracks/1/loop_wrap = true
tracks/1/keys = { tracks/1/keys = {
"times": PackedFloat32Array(0, 0.34, 0.4), "times": PackedFloat32Array(0),
"transitions": PackedFloat32Array(1.618, 1.618, 1), "transitions": PackedFloat32Array(1),
"update": 0, "update": 1,
"values": [20.0, -120.0, -98.0] "values": [true]
} }
[sub_resource type="AnimationLibrary" id="AnimationLibrary_c3i4w"] [sub_resource type="AnimationLibrary" id="AnimationLibrary_c3i4w"]
@ -782,7 +782,6 @@ anchor_right = 0.333
anchor_bottom = 1.0 anchor_bottom = 1.0
offset_top = -98.0 offset_top = -98.0
offset_right = 40.0 offset_right = 40.0
offset_bottom = 278.665
grow_vertical = 0 grow_vertical = 0
theme_override_constants/margin_left = 16 theme_override_constants/margin_left = 16
theme_override_constants/margin_bottom = 16 theme_override_constants/margin_bottom = 16