1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
|
class_name PlayerStateHanging
extends PlayerState
var target: HookHanging
var t: float
var L: float
var theta0: float
var last_theta: float
var w: float
var tongue: Line2D
var travel_from: Vector2
var travel_to: Vector2
var T_mlem: float = 0.2
var T_travel: float = 0.1
var swing_force: float = 0.2
enum S { MLEMING, TRAVELING, HANGING }
var state: S = S.MLEMING
func _init(pl: Player, h_target: HookHanging, h_dist: float) -> void:
super(pl)
t = 0
L = h_dist
target = h_target
w = sqrt(p.gravity / L) * 0.7
var dx = target.global_position.x - pl.global_position.x
pl.anim_sp.flip_h = dx < 0
state = S.MLEMING
func _to_string() -> String:
return "PlayerStateHanging %s, θ₀ = %f, θ = %f" % [S.keys()[state], theta0, last_theta]
static func can_hang_from(pl: Player, c_target: HookHanging) -> bool:
var d = c_target.global_position - pl.global_position
var angle = atan2(d.y, d.x)
var revs = floor(angle / (2 * PI))
angle -= revs * 2 * PI
return angle > deg_to_rad(135) or angle < deg_to_rad(45)
func _handle(_delta: float):
if Input.is_action_just_pressed("move_left"):
p.anim_sp.flip_h = true
if Input.is_action_just_pressed("move_right"):
p.anim_sp.flip_h = false
func _handle_physics(delta: float):
match state:
S.MLEMING: _mlem(delta)
S.TRAVELING: _travel(delta)
S.HANGING: _hang(delta)
_: print_debug("_handle_physics: unknown state %s" % str(state))
func _mlem(delta: float):
t += delta
var d = target.global_position - p.global_position
# Add tongue line
if not tongue:
tongue = Line2D.new()
tongue.width = 2
tongue.add_point(-d)
tongue.add_point(-d)
target.add_child(tongue)
# Update one end to be at player
tongue.points[0] = -d
tongue.points[1] = (t / T_mlem - 1) * d
if t >= T_mlem:
tongue.points[1] = Vector2.ZERO
state = S.TRAVELING
travel_from = p.global_position
travel_to = target.global_position - d.normalized() * L
t = 0
func _travel(delta: float):
t += delta
p.global_position = travel_from + (t / T_travel) * (travel_to - travel_from)
var d = target.global_position - p.global_position
tongue.points[0] = -d
# If we're traveling in the right direction, then travel
if t >= T_travel:
p.global_position = travel_to
state = S.HANGING
theta0 = atan2(-d.y, -d.x) - PI / 2
if theta0 > PI: theta0 -= 2 * PI
if theta0 < -PI: theta0 += 2 * PI
last_theta = theta0
t = 0
func _hang(delta: float):
var d = target.global_position - p.global_position
tongue.points[0] = -d
t += delta
if Input.is_action_just_pressed("jump"):
p.velocity.y = -p.jump_strength
tongue.queue_free()
p.request_state_normal()
var theta = theta0 * cos(t * w)
# Allow player to add momentum by moving toward the swing direction
var dtheta = theta - last_theta
var momentum = Input.get_axis("move_right", "move_left")
var momentum_dir = sign(momentum) * sign(dtheta)
theta0 += momentum_dir * sign(theta0) * swing_force * delta
# Limit max swinging height to horizontal by
# lerping theta0 to 90deg at the bottom of the swing
if abs(theta0) > PI / 2 and abs(theta) < PI / 8:
theta0 = lerp(theta0, sign(theta0) * PI / 2, 0.8)
#if sign(theta) != sign(last_theta) and abs(theta0) > PI / 2:
# theta0 = sign(theta0) * PI / 2
p.global_position.x = target.global_position.x + L * cos(theta + PI / 2)
p.global_position.y = target.global_position.y + L * sin(theta + PI / 2)
last_theta = theta
|