generated from krampus/template-godot4
	Compare commits
	
		
			No commits in common. "e723e0c022299d777367b2373770090803ce5acb" and "1c5222fecf7b2580c850cfec4e4c53e778d0141e" have entirely different histories.
		
	
	
		
			e723e0c022
			...
			1c5222fecf
		
	
		
| @ -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) | ||||
| 
 | ||||
| [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")] | ||||
| 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")] | ||||
| 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")] | ||||
| 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")] | ||||
| 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") | ||||
| 
 | ||||
| [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")] | ||||
| transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 70.2122, 0, 116.269) | ||||
|  | ||||
| @ -12,7 +12,6 @@ enum Type { | ||||
| } | ||||
| 
 | ||||
| const TERRAIN_DAMPING_EPSILON := 1e-6 | ||||
| const MAGNUS_EPSILON := 1e-3 | ||||
| const IRON_DAMPING := 9999.0 | ||||
| 
 | ||||
| ## Angular damping while in air | ||||
| @ -22,16 +21,6 @@ const IRON_DAMPING := 9999.0 | ||||
| ## Angular damping for iron balls | ||||
| @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 | ||||
| @export var iron_ball := false: | ||||
| 	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: | ||||
| 	if not _awake: | ||||
| 		# Triggered on first frame after waking | ||||
| 		_awake = true | ||||
| 		_position_on_last_wake = global_position | ||||
| 		_last_contact_normal = Vector3.UP | ||||
| 		# TODO something's fucky here... I think this gets called once after the ball sleeps | ||||
| 
 | ||||
| 	var damping := air_damping | ||||
| 	if state.get_contact_count(): | ||||
| 		constant_force = Vector3.ZERO | ||||
| 
 | ||||
| 		# 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 | ||||
| 
 | ||||
| 		_last_contact_normal = state.get_contact_local_normal(0) | ||||
| 		damping = _total_terrain_angular_damping() | ||||
| 		if damping <= TERRAIN_DAMPING_EPSILON: | ||||
| 			damping = rough_damping | ||||
| @ -103,13 +77,6 @@ func _integrate_forces(state: PhysicsDirectBodyState3D) -> void: | ||||
| 	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: | ||||
| 	_zones.push_back(zone) | ||||
| 
 | ||||
|  | ||||
| @ -34,13 +34,8 @@ script/source = "extends Control | ||||
| const COLOR_X := Color(1, 0, 0) | ||||
| const COLOR_Y := Color(0, 1, 0) | ||||
| const COLOR_Z := Color(0, 0, 1) | ||||
| const COLOR_MAGNUS := Color.CYAN | ||||
| const MAGNUS_SCALE := 3 | ||||
| const WIDTH := 4 | ||||
| 
 | ||||
| @export var draw_reoriented_basis := true | ||||
| @export var draw_magnus_effect := true | ||||
| 
 | ||||
| @onready var physics_ball: GameBall = $\"..\" | ||||
| 
 | ||||
| 
 | ||||
| @ -50,9 +45,9 @@ func _process(_delta: float) -> void: | ||||
| 
 | ||||
| 
 | ||||
| func _draw() -> void: | ||||
| 	var camera := get_viewport().get_camera_3d() | ||||
| 	var start := camera.unproject_position(physics_ball.global_position) | ||||
| 	if draw_reoriented_basis and physics_ball._last_contact_normal != null: | ||||
| 	if physics_ball._last_contact_normal != null: | ||||
| 		var camera := get_viewport().get_camera_3d() | ||||
| 		var start := camera.unproject_position(physics_ball.global_position) | ||||
| 		var basis := physics_ball.get_reoriented_basis() | ||||
| 		var end_x := camera.unproject_position(physics_ball.global_position + basis.x) | ||||
| 		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_y, COLOR_Y, 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"] | ||||
| @ -72,7 +63,7 @@ physics_material_override = ExtResource("1_l23pw") | ||||
| freeze = true | ||||
| continuous_cd = true | ||||
| contact_monitor = true | ||||
| max_contacts_reported = 3 | ||||
| max_contacts_reported = 1 | ||||
| linear_damp_mode = 1 | ||||
| angular_damp_mode = 1 | ||||
| angular_damp = 8.0 | ||||
| @ -95,6 +86,5 @@ anchor_bottom = 1.0 | ||||
| grow_horizontal = 2 | ||||
| grow_vertical = 2 | ||||
| script = SubResource("GDScript_p4v7o") | ||||
| draw_reoriented_basis = false | ||||
| 
 | ||||
| [connection signal="sleeping_state_changed" from="." to="." method="_on_sleeping_state_changed"] | ||||
|  | ||||
| @ -35,12 +35,6 @@ const BIG_POWER_THRESHOLD := 0.7 | ||||
| ## Amount of life lost when landing in water | ||||
| 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. | ||||
| @export var driving_range := false | ||||
| 
 | ||||
| @ -114,7 +108,7 @@ var shot_curve: float: | ||||
| 	set(value): | ||||
| 		hud.curve_bar.value = value | ||||
| 	get: | ||||
| 		return hud.curve_bar.value | ||||
| 		return hud.power_bar.value | ||||
| 
 | ||||
| var game_ball: GameBall: | ||||
| 	get: | ||||
| @ -237,22 +231,12 @@ func take_shot() -> void: | ||||
| 
 | ||||
| 	print_debug("WHACK!\nPower: ", shot_power, "\nCurve: ", shot_curve) | ||||
| 
 | ||||
| 	# Momentary impulse applied to the ball | ||||
| 	var impulse := get_shot_impulse(shot_power) | ||||
| 	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: | ||||
| 		game_ball.iron_ball = club == Club.Type.IRON | ||||
| 		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 | ||||
| 	if player.get_balls(ball_type) > 0: | ||||
| @ -370,6 +354,8 @@ func _on_club_change(new_club_type: Club.Type) -> void: | ||||
| 	wedge_arrow.hide() | ||||
| 	iron_arrow.hide() | ||||
| 	putt_arrow.hide() | ||||
| 	if game_ball: | ||||
| 		game_ball.iron_ball = false | ||||
| 	hud.club_selector.value = new_club_type | ||||
| 	# TODO club change animation | ||||
| 	character.hold_right(new_club.get_model()) | ||||
| @ -386,6 +372,8 @@ func _on_club_change(new_club_type: Club.Type) -> void: | ||||
| 		Club.Type.IRON: | ||||
| 			shot_ref = iron_ref | ||||
| 			iron_arrow.show() | ||||
| 			if game_ball: | ||||
| 				game_ball.iron_ball = true | ||||
| 		Club.Type.SPECIAL: | ||||
| 			# TODO figure this out | ||||
| 			shot_ref = drive_ref | ||||
| @ -422,11 +410,7 @@ func _on_phase_change(new_phase: Phase) -> void: | ||||
| 			hud.power_bar.hide() | ||||
| 			hud.curve_bar.hide() | ||||
| 
 | ||||
| 			if perfect_aim: | ||||
| 				shot_curve = 0.0 | ||||
| 
 | ||||
| 			if abs(shot_curve) <= NICE_THRESHOLD: | ||||
| 				hud.play_nice_animation() | ||||
| 			hud.play_nice_animation() | ||||
| 
 | ||||
| 			if not driving_range: | ||||
| 				shot_animation.play("shoot") | ||||
| @ -442,6 +426,7 @@ func _on_phase_change(new_phase: Phase) -> void: | ||||
| 
 | ||||
| func _on_game_ball_changed(ball: GameBall) -> void: | ||||
| 	if ball: | ||||
| 		ball.iron_ball = (club == Club.Type.IRON) | ||||
| 		ball.entered_water.connect(_on_ball_entered_water) | ||||
| 		ball.sleeping_state_changed.connect(_on_ball_sleeping_state_changed) | ||||
| 
 | ||||
|  | ||||
| @ -43,10 +43,14 @@ texture = SubResource("GradientTexture2D_tm61r") | ||||
| [node name="BallList" type="VBoxContainer" parent="GradientMask"] | ||||
| unique_name_in_owner = true | ||||
| 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_right = 120.0 | ||||
| offset_bottom = 109.0 | ||||
| offset_bottom = 50.0 | ||||
| grow_horizontal = 2 | ||||
| grow_vertical = 2 | ||||
| theme_override_constants/separation = 5 | ||||
| 
 | ||||
| [node name="BasicIcon" parent="GradientMask/BallList" instance=ExtResource("1_1v8xg")] | ||||
|  | ||||
| @ -441,26 +441,26 @@ length = 0.001 | ||||
| tracks/0/type = "value" | ||||
| tracks/0/imported = false | ||||
| tracks/0/enabled = true | ||||
| tracks/0/path = NodePath("SouthWest:visible") | ||||
| tracks/0/path = NodePath("SouthWest:position") | ||||
| tracks/0/interp = 1 | ||||
| tracks/0/loop_wrap = true | ||||
| tracks/0/keys = { | ||||
| "times": PackedFloat32Array(0), | ||||
| "transitions": PackedFloat32Array(1), | ||||
| "update": 1, | ||||
| "values": [true] | ||||
| "update": 0, | ||||
| "values": [Vector2(0, 982)] | ||||
| } | ||||
| tracks/1/type = "value" | ||||
| tracks/1/imported = false | ||||
| tracks/1/enabled = true | ||||
| tracks/1/path = NodePath("SouthWest:offset_top") | ||||
| tracks/1/interp = 2 | ||||
| tracks/1/path = NodePath("SouthWest:visible") | ||||
| tracks/1/interp = 1 | ||||
| tracks/1/loop_wrap = true | ||||
| tracks/1/keys = { | ||||
| "times": PackedFloat32Array(0), | ||||
| "transitions": PackedFloat32Array(1), | ||||
| "update": 0, | ||||
| "values": [-98.0] | ||||
| "update": 1, | ||||
| "values": [true] | ||||
| } | ||||
| 
 | ||||
| [sub_resource type="Animation" id="Animation_yis4x"] | ||||
| @ -470,26 +470,26 @@ step = 0.02 | ||||
| tracks/0/type = "value" | ||||
| tracks/0/imported = false | ||||
| tracks/0/enabled = true | ||||
| tracks/0/path = NodePath("SouthWest:visible") | ||||
| tracks/0/interp = 1 | ||||
| tracks/0/path = NodePath("SouthWest:position") | ||||
| tracks/0/interp = 2 | ||||
| tracks/0/loop_wrap = true | ||||
| tracks/0/keys = { | ||||
| "times": PackedFloat32Array(0.4), | ||||
| "transitions": PackedFloat32Array(1), | ||||
| "update": 1, | ||||
| "values": [false] | ||||
| "times": PackedFloat32Array(0, 0.1, 0.4), | ||||
| "transitions": PackedFloat32Array(1.618, 1.618, 1), | ||||
| "update": 0, | ||||
| "values": [Vector2(0, 982), Vector2(0, 960), Vector2(0, 1100)] | ||||
| } | ||||
| tracks/1/type = "value" | ||||
| tracks/1/imported = false | ||||
| tracks/1/enabled = true | ||||
| tracks/1/path = NodePath("SouthWest:offset_top") | ||||
| tracks/1/interp = 2 | ||||
| tracks/1/path = NodePath("SouthWest:visible") | ||||
| tracks/1/interp = 1 | ||||
| tracks/1/loop_wrap = true | ||||
| tracks/1/keys = { | ||||
| "times": PackedFloat32Array(0, 0.1, 0.4), | ||||
| "transitions": PackedFloat32Array(1.618, 1.618, 1), | ||||
| "update": 0, | ||||
| "values": [-98.0, -120.0, 20.0] | ||||
| "times": PackedFloat32Array(0.4), | ||||
| "transitions": PackedFloat32Array(1), | ||||
| "update": 1, | ||||
| "values": [false] | ||||
| } | ||||
| 
 | ||||
| [sub_resource type="Animation" id="Animation_jugqx"] | ||||
| @ -499,26 +499,26 @@ step = 0.02 | ||||
| tracks/0/type = "value" | ||||
| tracks/0/imported = false | ||||
| tracks/0/enabled = true | ||||
| tracks/0/path = NodePath("SouthWest:visible") | ||||
| tracks/0/path = NodePath("SouthWest:position") | ||||
| tracks/0/interp = 1 | ||||
| tracks/0/loop_wrap = true | ||||
| tracks/0/keys = { | ||||
| "times": PackedFloat32Array(0, 2.4), | ||||
| "transitions": PackedFloat32Array(1, 1), | ||||
| "update": 1, | ||||
| "values": [true, false] | ||||
| "times": PackedFloat32Array(0, 0.1, 2.3, 2.4), | ||||
| "transitions": PackedFloat32Array(1.618, 1, 1.618, 1), | ||||
| "update": 0, | ||||
| "values": [Vector2(0, 1100), Vector2(0, 982), Vector2(0, 982), Vector2(0, 1100)] | ||||
| } | ||||
| tracks/1/type = "value" | ||||
| tracks/1/imported = false | ||||
| tracks/1/enabled = true | ||||
| tracks/1/path = NodePath("SouthWest:offset_top") | ||||
| tracks/1/path = NodePath("SouthWest:visible") | ||||
| tracks/1/interp = 1 | ||||
| tracks/1/loop_wrap = true | ||||
| tracks/1/keys = { | ||||
| "times": PackedFloat32Array(0, 0.1, 2.3, 2.4), | ||||
| "transitions": PackedFloat32Array(1.618, 1, 1.618, 1), | ||||
| "update": 0, | ||||
| "values": [20.0, -98.0, -98.0, 20.0] | ||||
| "times": PackedFloat32Array(0, 2.4), | ||||
| "transitions": PackedFloat32Array(1, 1), | ||||
| "update": 1, | ||||
| "values": [true, false] | ||||
| } | ||||
| 
 | ||||
| [sub_resource type="Animation" id="Animation_nicro"] | ||||
| @ -528,26 +528,26 @@ step = 0.02 | ||||
| tracks/0/type = "value" | ||||
| tracks/0/imported = false | ||||
| tracks/0/enabled = true | ||||
| tracks/0/path = NodePath("SouthWest:visible") | ||||
| tracks/0/interp = 1 | ||||
| tracks/0/path = NodePath("SouthWest:position") | ||||
| tracks/0/interp = 2 | ||||
| tracks/0/loop_wrap = true | ||||
| tracks/0/keys = { | ||||
| "times": PackedFloat32Array(0), | ||||
| "transitions": PackedFloat32Array(1), | ||||
| "update": 1, | ||||
| "values": [true] | ||||
| "times": PackedFloat32Array(0, 0.34, 0.4), | ||||
| "transitions": PackedFloat32Array(1.618, 1.618, 1), | ||||
| "update": 0, | ||||
| "values": [Vector2(0, 1100), Vector2(0, 960), Vector2(0, 982)] | ||||
| } | ||||
| tracks/1/type = "value" | ||||
| tracks/1/imported = false | ||||
| tracks/1/enabled = true | ||||
| tracks/1/path = NodePath("SouthWest:offset_top") | ||||
| tracks/1/interp = 2 | ||||
| tracks/1/path = NodePath("SouthWest:visible") | ||||
| tracks/1/interp = 1 | ||||
| tracks/1/loop_wrap = true | ||||
| tracks/1/keys = { | ||||
| "times": PackedFloat32Array(0, 0.34, 0.4), | ||||
| "transitions": PackedFloat32Array(1.618, 1.618, 1), | ||||
| "update": 0, | ||||
| "values": [20.0, -120.0, -98.0] | ||||
| "times": PackedFloat32Array(0), | ||||
| "transitions": PackedFloat32Array(1), | ||||
| "update": 1, | ||||
| "values": [true] | ||||
| } | ||||
| 
 | ||||
| [sub_resource type="AnimationLibrary" id="AnimationLibrary_c3i4w"] | ||||
| @ -782,7 +782,6 @@ anchor_right = 0.333 | ||||
| anchor_bottom = 1.0 | ||||
| offset_top = -98.0 | ||||
| offset_right = 40.0 | ||||
| offset_bottom = 278.665 | ||||
| grow_vertical = 0 | ||||
| theme_override_constants/margin_left = 16 | ||||
| theme_override_constants/margin_bottom = 16 | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user