0 votes

Thanks for any help, sorry if its too long I wanted to provide everything useful.
I am trying to incorporate a grapplehook into my game with a smooth swinging pendulum. I have code to shoot the grapplehook and have code for a pendulum, each of which are their own scenes for compartmentalization (brought together. So Player has a GrappleHook which has a Pendulum each with its own script).
My problem comes in with trying to move my parent based on code in its grand child's func process_velocity(delta).

To paint a picture of what Im wanting my code to do, the player should shoot the grapplehook (which is a child) and while hooked is affected by the pendulum physics (which is a child of the grapplehook). In my mind's eye I see calling a func and getting back a velocity which is applied to my players current velocity, but Im not sure how get that to work properly. The pendulum needs to know where the pivot and the pendulum are located

What I want is to have my player's script free of all of the coding for the grapplehook (except necessities like calling a shoot func and whatnot), and the grapplehook to be reasonably free of the pendulum code so it can be modular in how it functions.
Other grapplehook tutorials have the move code pretty much entirely in the player, but Im not fond of that since I figure it would dampen variety later on.

Here is the pendulum code. As a scene itself it shows what it does and works. _ready func and down is simply to make it work standalone as a test. (if you copy it, the script is attached to a position2d node which is a child of a node2d. make sure the position2d node is not on top of the node2d)

extends Position2D
class_name Pendulum

var pivot_point: Vector2                        #Point pedulum rotates around
export (Vector2) var end_position = Vector2()   #Pendulum itself
var arm_length: float
var angle                                       #Get angle between position + add godot angle offset

export (float) var gravity = 0.4 * 60
export (float) var damping = 0.995              #Arbitrary dampening force (slows down each swing)

var angular_velocity = 0.0                      #Speed of rotation
var angular_acceleration = 0.0                  #Causes speed to increase or decrease?

func set_start_position(start_pos:Vector2, end_pos:Vector2):
    pivot_point = start_pos
    end_position = end_pos
    arm_length = Vector2.ZERO.distance_to(end_position - pivot_point)
    angle = Vector2.ZERO.angle_to(end_position - pivot_point) - deg2rad(-90) #Angle of pivot point to end_position, corrected for Godot's default angle facing right
    angular_velocity = 0.0
    angular_acceleration = 0.0

func _ready()->void:
    set_start_position(global_position, end_position)

func process_velocity(delta:float)->void:
    angular_acceleration = ((-gravity*delta) / arm_length) * sin(angle) #Caluclate acceleration (see: http://www.myphysicslab.com/pendulum1.html)
    angular_velocity += angular_acceleration                            #Increment velocity
    angular_velocity *= damping                                         #Arbitrary damping
    angle += angular_velocity                                           #Increment angle
    end_position = pivot_point + Vector2(arm_length*sin(angle), arm_length*cos(angle))
    print(end_position)

func add_angular_velocity(force:float)->void:
    angular_velocity += force


func game_input()->void:
    var dir:float = 0
    if Input.is_action_just_pressed("ui_right"):
        dir += 1
    elif Input.is_action_just_pressed("ui_left"):
        dir -= 1
    add_angular_velocity(dir * 0.02)                    #give a kick to the swing

func _physics_process(delta)->void:
    game_input()

    process_velocity(delta)
    update()

func _draw()->void:
    draw_line(Vector2.ZERO, end_position - pivot_point, Color.white, 1.0, false)
    draw_circle(end_position - pivot_point, 3, Color.red)

Here is my grapplehook code, which is largely a mess since Ive been testing and following rabbitholes.

onready var links = $Links      # A slightly easier reference to the links
onready var hookTip = $Tip
onready var pendulum = $Pendulum/Position2D

var direction := Vector2(0,0)   # The direction in which the chain was shot
var tip := Vector2(0,0)         # The global position the tip should be in
                                # We use an extra var for this, because the chain is 
                                # connected to the player and thus all .position
                                # properties would get messed with when the player
                                # moves.

const SPEED = 10    # The speed with which the chain moves

var flying = false  # Whether the chain is moving through the air
var hooked = false  # Whether the chain has connected to a wall

# shoot() shoots the chain in a given direction
func shoot(dir: Vector2) -> void:
    direction = dir.normalized()    # Normalize the direction and save it
    flying = true                   # Keep track of our current scan
    tip = self.global_position      # reset the tip position to the player's position

# release() the chain
func release() -> void:
    flying = false  # Not flying anymore    
    hooked = false  # Not attached anymore

# Every graphics frame we update the visuals
func _process(_delta: float) -> void:
    self.visible = flying or hooked # Only visible if flying or attached to something
    if not self.visible:
        return  # Not visible -> nothing to draw
    var tip_loc = to_local(tip) # Easier to work in local coordinates
    # We rotate the links (= chain) and the tip to fit on the line between self.position (= origin = player.position) and the tip
    links.rotation = self.position.angle_to_point(tip_loc) - deg2rad(90)
    hookTip.rotation = self.position.angle_to_point(tip_loc) - deg2rad(90)
    links.position = tip_loc                        # The links are moved to start at the tip
    links.region_rect.size.y = tip_loc.length()     # and get extended for the distance between (0,0) and the tip


# Every physics frame we update the tip position
func _physics_process(_delta: float) -> void:
    hookTip.global_position = tip   # The player might have moved and thus updated the position of the tip -> reset it
    if flying:
        # `if move_and_collide()` always moves, but returns true if we did collide
        if hookTip.move_and_collide(direction * SPEED):
            hooked = true   # Got something!
            flying = false  # Not flying anymore
    tip = hookTip.global_position   # set `tip` as starting position for next frame
    pendulum.global_position = tip
    pendulum.end_position = self.position

TL:DR How do I access/run physics code from a (grand)child on the grandparent

Godot version 3.4.2
in Engine by (17 points)

Please log in or register to answer this question.

Welcome to Godot Engine Q&A, where you can ask questions and receive answers from other members of the community.

Please make sure to read Frequently asked questions and How to use this Q&A? before posting your first questions.
Social login is currently unavailable. If you've previously logged in with a Facebook or GitHub account, use the I forgot my password link in the login box to set a password for your account. If you still can't access your account, send an email to [email protected] with your username.