Skip to content

Commit

Permalink
working on 2 players throwing and catching to each other
Browse files Browse the repository at this point in the history
  • Loading branch information
samhattangady committed May 30, 2019
1 parent a9d8738 commit abf93ef
Show file tree
Hide file tree
Showing 11 changed files with 349 additions and 63 deletions.
35 changes: 21 additions & 14 deletions Disc.gd
Expand Up @@ -57,6 +57,7 @@ func _process(delta):
if DEBUG:
emit_signal('position_update', path_follow.translation)
if currently_thrown and playing:
print('disc ', self.path_follow.translation)
update_offset(delta)

func _input(event):
Expand All @@ -83,13 +84,15 @@ func execute_throw(throw):
start_throw(throw, curve)

func start_throw(throw, curve):
currently_thrown = true
# FIXME (15 May 2019 sam): !TranslationError. See bottom
if number_of_throws != 0:
translation = -path.translation
number_of_throws += 1
self.calculate_throw_speed(throw, curve)
self.emit_signal('throw_started', curve, {

func start_throw_animation():
self.currently_thrown = true
self.emit_signal('throw_started', self.path.curve, {
'time': self.total_throw_time,
'max_speed': self.current_max_speed,
'min_speed': self.current_min_speed
Expand Down Expand Up @@ -118,17 +121,20 @@ func update_offset(delta):
self.current_min_speed)
var offset = self.path_follow.unit_offset
if offset >= 1.0:
self.currently_thrown = false
# FIXME (15 May 2019 sam): !TranslationError. See bottom
# NOTE (22 May 2019 sam): Note that this logic will be adjusted once we have
# players catching the disc. At that point, we will just be using the players
# translation instead of bothering with path_follow etc.
self.path_follow.unit_offset = 0.999
self.path.translation = self.path_follow.translation
self.path_follow.unit_offset = 0.0
self.throw_time_elapsed = 0.0
self.emit_signal('throw_complete', self.path.translation)
var actual_time = (OS.get_ticks_msec()-self.throw_start_time) / 1000.0
self.throw_is_complete()

func throw_is_complete():
self.currently_thrown = false
# FIXME (15 May 2019 sam): !TranslationError. See bottom
# NOTE (22 May 2019 sam): Note that this logic will be adjusted once we have
# players catching the disc. At that point, we will just be using the players
# translation instead of bothering with path_follow etc.
self.path_follow.unit_offset = 0.999
self.path.translation = self.path_follow.translation
self.path_follow.unit_offset = 0.0
self.throw_time_elapsed = 0.0
self.emit_signal('throw_complete', self.path.translation)
var actual_time = (OS.get_ticks_msec()-self.throw_start_time) / 1000.0

func calculate_throw_curve(throw_data):
var end_point = get_point_in_world(throw_data['end'])
Expand Down Expand Up @@ -185,7 +191,8 @@ func get_point_in_world(position):
return point.position

func attach_to_wrist(global_transform):
self.transform = global_transform
self.translation = global_transform.basis[0]
print(self.translation)

# TODO (10 May 2019 sam): Deal with all the y_disp stuff in throw calculation
# That is what will allow the users to add height to their throws, for blades
Expand Down
4 changes: 2 additions & 2 deletions GameCamera.gd
Expand Up @@ -6,8 +6,8 @@ var start_origin = Vector3(0, 0, 0)

# FIXME (22 May 2019 sam): Currently these are hardcoded into the script. It should
# instead be taken from whatever values were set in the editor.
var camera_height = 3
var camera_z_offset = 1.5
var camera_height = 30
var camera_z_offset = 15
var camera_x_offset = 0

func _ready():
Expand Down
1 change: 1 addition & 0 deletions GameCamera.tscn
Expand Up @@ -3,4 +3,5 @@
[ext_resource path="res://GameCamera.gd" type="Script" id=1]

[node name="GameCamera" type="Camera"]
far = 500.0
script = ExtResource( 1 )
1 change: 0 additions & 1 deletion Ground.tscn
Expand Up @@ -3,7 +3,6 @@
[sub_resource type="CubeMesh" id=1]

[sub_resource type="SpatialMaterial" id=2]
flags_transparent = true
albedo_color = Color( 0.196078, 0.623529, 0.14902, 0.607843 )

[sub_resource type="ConvexPolygonShape" id=3]
Expand Down
55 changes: 31 additions & 24 deletions InputControls.gd
@@ -1,6 +1,7 @@
extends Node2D

var throw_path = []
var drag_path = []
var mouse_down = false
var is_throwing = false
var is_panning = false
Expand All @@ -11,6 +12,7 @@ signal throw(throw_data)
signal pan_start()
signal pan_camera(pan_start, pan_end, origin)
signal mark_point(point)
signal tap_location(point)

var disc_points = Vector2(0, 0)
var throw_radius = 100
Expand All @@ -23,40 +25,45 @@ func _ready():
func _input(event):
if event is InputEventMouseButton and event.get_button_index() == BUTTON_LEFT:
if event.is_pressed():
throw_path = []
mouse_down = true
self.throw_path = []
self.mouse_down = true
var distance = event.position.distance_to(disc_points)
if distance < throw_radius:
is_throwing = true
throw_start_time = OS.get_ticks_msec()
elif distance > throw_radius+throw_radius_buffer:
is_panning = true
emit_signal("pan_start")
pan_start = event.position
if distance < self.throw_radius:
self.is_throwing = true
self.throw_start_time = OS.get_ticks_msec()
elif distance > self.throw_radius+self.throw_radius_buffer:
self.is_panning = true
self.emit_signal("pan_start")
self.pan_start = event.position
else:
if is_throwing:
if len(drag_path) == 0:
# Player is tapping. Not dragging
self.emit_signal('tap_location', event.position)
if self.is_throwing:
# TODO (06 May 2019 sam): Make sure there are
# atleast 3-4 points. Or calculate length of
# the path. Or some other kind of verification
# We also ought to be checking if there is any
# cause for DivisionByZeroError to be cropping
# up here.
if len(throw_path) > 3:
var throw_data = identify_throw(throw_path)
throw_data['msecs'] = OS.get_ticks_msec() - throw_start_time
emit_signal("throw", throw_data)
mouse_down = false
is_throwing = false
is_panning = false
throw_path = []
if len(self.throw_path) > 3:
var throw_data = self.identify_throw(throw_path)
throw_data['msecs'] = OS.get_ticks_msec() - self.throw_start_time
self.emit_signal("throw", throw_data)
self.mouse_down = false
self.is_throwing = false
self.is_panning = false
self.throw_path = []
self.drag_path = []
if event is InputEventMouseButton and event.get_button_index() == BUTTON_RIGHT:
# DEBUG
emit_signal('mark_point', event.position)
self.emit_signal('mark_point', event.position)
if mouse_down and event is InputEventMouseMotion:
if is_throwing:
throw_path.append(event.position)
elif is_panning:
emit_signal("pan_camera", pan_start, event.position, disc_points)
self.drag_path.append(event.position)
if self.is_throwing:
self.throw_path.append(event.position)
elif self.is_panning:
self.emit_signal("pan_camera", pan_start, event.position, disc_points)
update()

func _draw():
Expand All @@ -80,7 +87,7 @@ func identify_throw(path):
func get_throw(path):
# Tells us whether a throw is a backhand or forehand etc
var start_point = path[0]
if start_point.x < disc_points.x:
if start_point.x > disc_points.x:
return 'Forehand'
else:
return 'Backhand'
Expand Down
1 change: 1 addition & 0 deletions Player.gd
Expand Up @@ -165,3 +165,4 @@ func get_point_in_world(position):
var point = get_world().direct_space_state.intersect_ray(start_point, end_point)
if not point: return
return point.position

184 changes: 178 additions & 6 deletions Player2.gd
@@ -1,19 +1,191 @@
extends Spatial
extends KinematicBody

export var max_speed = 8
export var acceleration = 10
export var deceleration = 10
export var MAX_ANGLE_WITHOUT_STOPPING = 60
export var AT_DESTINATION_DISTANCE = 0.1
export var DISC_CATCHING_DISTANCE = 5

var current_direction = Vector3(1, 0, 0)
var current_velocity = Vector3(-1, 0, 0)
var desired_direction = Vector3(0, 0, -1)
var desired_destination = Vector3(0, 0, -1)

enum PLAYER_STATE {
IDLE,
RUNNING,
WITH_DISC,
THROWING
}
var right_hand
var disc
var skeleton
var wrist_rest_position
var animation_player
var selected_marker
var has_disc
var is_selected
var disc_calculator
var current_state

var debug_starting_time

# Signal to attach the disc to the throwers arm
signal thrower_arm_position(transform)
# Signal to start throw
signal throw_animation_complete()

func _ready():
var animation_player = self.get_node('AnimationPlayer')
animation_player.get_animation('Forehand').set_loop(true)
animation_player.play('Forehand')
self.animation_player = self.get_node('AnimationPlayer')
self.selected_marker = self.get_node('SelectedMarker')
self.disc_calculator = load('DiscCalculator.gd').new()
self.animation_player.get_animation('Idle').set_loop(true)
self.animation_player.get_animation('ArmatureAction').set_loop(true)
self.animation_player.play('Idle')
self.skeleton = self.get_node('Armature').get_node('Skeleton')
self.right_hand = self.skeleton.find_bone('Wrist.R')
self.wrist_rest_position = self.skeleton.get_bone_transform(right_hand)
self.animation_player.connect('animation_finished', self, 'handle_animation_completion')
self.current_state = PLAYER_STATE.IDLE

func _physics_process(delta):
if self.current_state == PLAYER_STATE.RUNNING:
if self.check_if_at_destination():
pass
self.recalculate_current_velocity(delta)
self.move_and_slide(self.current_velocity, Vector3(0, -1, 0))
self.check_if_at_disc()
if self.current_velocity.length() > 1.0:
self.animation_player.play('ArmatureAction')

func set_disc(disc):
self.disc = disc

func check_if_at_destination():
return self.translation.distance_to(self.desired_destination) < self.AT_DESTINATION_DISTANCE

func check_if_at_disc():
print(self.translation.distance_to(self.disc.translation))
if self.translation.distance_to(self.disc.path_follow.translation) < self.AT_DESTINATION_DISTANCE:
print('at disc')
self.catch_disc()

func catch_disc():
self.disc.throw_is_complete()
self.disc.translation = self.translation
self.has_disc = true
self.current_velocity = Vector3(0, 0, 0)
self.current_state = PLAYER_STATE.WITH_DISC

func recalculate_current_velocity(delta):
# If we are running in desired direction, accelerate to max_speed
# Otherwise, depending on the angle change,
# 0-60: Maintain the component of speed along that direction.
# >60: decelerate to 0, and change to desired direction
var change_of_angle = abs(rad2deg(self.current_direction.angle_to(self.desired_direction)))
if change_of_angle < self.MAX_ANGLE_WITHOUT_STOPPING:
self.current_velocity = self.current_velocity.project(self.desired_direction)
self.current_direction = self.desired_direction
if self.current_velocity.length() < self.max_speed:
self.current_velocity += self.current_direction*self.acceleration*delta
if self.current_velocity.length() > self.max_speed:
self.current_velocity = self.current_direction*max_speed
else:
# !AnimationHook - Chopstop / sliding
self.current_velocity -= self.current_direction*self.deceleration * delta
if self.current_velocity.normalized() != self.current_direction:
self.current_velocity = Vector3(0, 0, 0)
self.run_to_world_point(self.desired_destination)
self.current_direction = self.desired_direction

func set_desired_direction(dir):
self.desired_direction = dir.normalized()
# TODO (22 May 2019 sam): Figure out where the rotation should be changed
rotation.y = atan2(desired_direction.x, desired_direction.z)

func _process(delta):
var global_transform = self.skeleton.get_bone_transform(right_hand)
func update_arm_position():
var global_transform = self.skeleton.get_bone_global_pose(right_hand)
self.emit_signal('thrower_arm_position', global_transform)

func start_throw_animation(throw_data):
# TODO (30 May 2019 sam): Don't like this very much. The signal shouldn't be
# directly connected to this method. See what the better way of doing this would be.
if self.has_disc:
self.animation_player.play(throw_data['throw'], -1, 3.0, false)
self.has_disc = false

func handle_animation_completion(anim_name):
if anim_name == 'Forehand' or anim_name == 'Backhand':
self.emit_signal('throw_animation_complete')
if anim_name != 'Idle':
self.animation_player.play('Idle')

func set_selected():
self.is_selected = true
self.selected_marker.visible = true

func set_deselected():
self.is_selected = false
self.selected_marker.visible = false

func run_to_world_point(destination):
self.desired_destination = destination
var dir = destination - self.translation
self.set_desired_direction(dir)
self.debug_starting_time = OS.get_ticks_msec()
self.current_state = PLAYER_STATE.RUNNING

func disc_is_thrown(curve, throw_details):
if self.current_state == PLAYER_STATE.RUNNING:
var attack_point = self.calculate_attack_point(curve, throw_details)
self.run_to_world_point(attack_point)

func calculate_attack_point(curve, throw_details):
# We take different points along the flight of the disc, and measure the
# time that the disc would take to get there, as well as the time that the
# player would take to get there. Whichever point has the least difference
# between the two, that is the attack point, and the player looks to catch
# the disc there.
# TODO (28 May 2019 sam): When calculating this point, we also need to see
# if it falls within some radius (is it really catchable at that point). This
# also requires us to constrain running to directions with y=0, and also figure
# out how to add jumping into this calculation, both with regards to skying and
# laying out.
var number_of_samples = 9
var best_point = -1
var best_time_difference = pow(10, 10)
for i in range(number_of_samples):
var time_sample = (i+1) * throw_details['time'] / number_of_samples
var offset_sample = self.disc_calculator.get_disc_offset(time_sample, throw_details['time'], throw_details['max_speed'], throw_details['min_speed'])
var sample_point = curve.interpolate_baked(offset_sample * curve.get_baked_length())
var time_to_point = self.get_time_to_point(sample_point, self.translation, self.current_direction, self.current_velocity)
if abs(time_to_point - time_sample) < best_time_difference:
best_time_difference = abs(time_to_point-time_sample)
best_point = sample_point
return best_point

func get_time_to_point(point, pos, dir, vel):
# Get the time it would take to move to a certain point
# For further details, refer to `recalculate_current_velocity`
# We use the pos, dir and vel here so that we can be a little recursive
var direction_to_point = (point - pos).normalized()
var change_of_angle = abs(rad2deg(dir.angle_to(direction_to_point)))
if change_of_angle < 1 and vel.length() != 0:
return point.distance_to(pos) / vel.length()
if change_of_angle < MAX_ANGLE_WITHOUT_STOPPING:
var initial_velocity = vel.project(direction_to_point)
if initial_velocity.length() < self.max_speed:
# calculate time to reach max speed, and position at that time
var time_to_max = (self.max_speed-initial_velocity.length()) / self.acceleration
var distance_to_max = (pow(self.max_speed, 2) - pow(vel.length(), 2)) / (2*self.acceleration)
var pos_at_max = pos + direction_to_point*(distance_to_max)
return time_to_max + self.get_time_to_point(point, pos_at_max, direction_to_point, self.max_speed*direction_to_point)
else:
# Chopstop / sliding
var time_to_stop = (vel.length()) / self.deceleration
var distance_to_stop = (-pow(vel.length(), 2)) / (2*self.deceleration)
var pos_at_stop = pos + dir*(distance_to_stop)
var new_dir = (point-pos_at_stop).normalized()
return time_to_stop + self.get_time_to_point(point, pos_at_stop, new_dir, Vector3(0, 0, 0))

0 comments on commit abf93ef

Please sign in to comment.