aboutsummaryrefslogtreecommitdiff
path: root/client/scripts/controllable_player.gd
blob: adf3f2c04202e4b62e4c0bea3e8e1d2f4f249638 (plain)
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
class_name ControllablePlayer
extends Player

@export var map: Node3D
@export var camera: FollowCamera

var facing = Vector2(1, 0)
var velocity = Vector2(0, 0)

func _ready():
	var timer = Timer.new()
	timer.one_shot = false
	timer.wait_time = 1. / 25.
	add_child(timer)
	timer.start()
	timer.connect("timeout", func():
		Multiplayer.send_position(Vector2(position.x, position.z), -rotation.y + .5 * PI)
	)

func _process(delta):
	var input = Vector2(Input.get_axis("left", "right"), Input.get_axis("forward", "backwards")).normalized()
	input = input.rotated(-camera.angle_target)

	if input.length() > 0.1:
		facing = lerp_vector2_exp(facing, input, delta * 10.)

	self.rotation.y = facing.angle()

	velocity.x += input.x * delta * SPEED
	velocity.y += input.y * delta * SPEED

	position = Vector3(
		position.x + (velocity.x * delta),
		0,
		position.z + (velocity.y * delta)
	)

	# collide
	collide(delta)

	velocity = lerp_vector2_exp(velocity, Vector2(0, 0), delta * 5.)

func collide(_delta: float):
	for i in map.get_children():
		if is_instance_of(i, FullTile):
			var tile: FullTile = i
			var d = aabb_circle_distance(
				tile.position.x,
				tile.position.z,
				tile.position.x + 1,
				tile.position.z + 1,
				position.x,
				position.z
			)

			if d > PLAYER_SIZE:
				continue

			var h = 0.01
			var d_sample_x = aabb_circle_distance(
				tile.position.x,
				tile.position.z,
				tile.position.x + 1,
				tile.position.z + 1,
				position.x + h,
				position.z
			)
			var d_sample_y = aabb_circle_distance(
				tile.position.x,
				tile.position.z,
				tile.position.x + 1,
				tile.position.z + 1,
				position.x,
				position.z + h
			)
			var grad_x = (d_sample_x - d) / h
			var grad_y = (d_sample_y - d) / h

			position.x += (PLAYER_SIZE - d) * grad_x
			position.z += (PLAYER_SIZE - d) * grad_y

			var vdotn = (grad_x * velocity.x) + (grad_y * velocity.y)

			velocity.x -= grad_x * vdotn
			velocity.y -= grad_y * vdotn
	# TODO: Player collisions

func lerp_vector2_exp(current: Vector2, target: Vector2, delta: float) -> Vector2:
	return Vector2(
		target.x + (current.x - target.x) * exp( - delta),
		target.y + (current.y - target.y) * exp( - delta)
	)

func aabb_circle_distance(
	min_x: float,
	min_y: float,
	max_x: float,
	max_y: float,
	px: float,
	py: float
) -> float:
	var dx = px - max(min_x, min(max_x, px))
	var dy = py - max(min_y, min(max_y, py))
	return sqrt(dx * dx + dy * dy)

func update_position(_new_position: Vector2, _new_rotation: float):
	pass