Godot Version
4.3
Question


[I’m a coding noob and more of a designer so please excuse any ridiculous code]
I am attempting to transfer an arc targeting feature, in which my player (a boat) uses the target to launch cannonballs at enemies and crates. Originally, the arc existed in the scene, but I want to transition the game to multiplayer, meaning that multiple players need their own arcs, and the node should instead be attached to the player. In my attempt to transfer, the arc has gotten distorted (before and after shown in photos), and since I had a friend of mine write the original arcing logic, I don’t have a great idea of how to fix it. I’ll include the relevant code blocks and be responsive with answering questions/ providing more if needed, thanks!
main_camera.gd
extends Camera3D
## The boat to follow (assign this in the editor or through code)
#@export var boat: Node3D
#
## Fixed height and distance from the boat
#@export var CAMERA_HEIGHT = 5.0 # Height above the boat
#@export var CAMERA_DISTANCE = 10.0 # Distance behind the boat
#
## Smooth following speed
#@export var FOLLOW_SPEED = 5.0 # Adjust this to make the camera follow faster or slower
#
##func _process(delta):
##if boat:
### Get the boat's current position
##var boat_position = boat.global_transform.origin
##
### Calculate the desired camera position
##var target_camera_position = boat_position + Vector3(-CAMERA_DISTANCE, CAMERA_HEIGHT, 0)
##
### Smoothly interpolate the camera position towards the target position
##global_transform.origin = global_transform.origin.lerp(target_camera_position, FOLLOW_SPEED * delta)
##
### Optionally, make the camera look at the boat
###look_at(boat_position, Vector3.UP)
@onready var player = get_node("/root/Main/NewBoat") # Assign your player in the editor or dynamically
var margin: float = 400.0 # Distance from the screen edge to start moving the camera
var camera_speed: float = 8.0 # Speed at which the camera moves
func _process(delta):
if not player:
return
# Get player's position in screen space (2D coordinates)
var player_screen_pos = unproject_position(player.global_transform.origin)
# Check if the player is near the left or right edges of the screen
if player_screen_pos.x < margin:
# Move camera left if player is near the left edge
global_transform.origin.x -= camera_speed * delta
elif player_screen_pos.x > (get_viewport().size.x - margin):
# Move camera right if player is near the right edge
global_transform.origin.x += camera_speed * delta
global_transform.origin.z = player.global_transform.origin.z + 5```
cannonballfire.gd
extends Node3D
@onready var projectile_scene = preload(“res://Cannonball/Projectile.tscn”)
@onready var camera = get_node(“…/Camera_Controller/Camera_Target/MainCamera”)
@onready var reticle = $Reticle
@onready var arc_mesh_instance = $Arc # Reference to the PathMeshInstance node
@onready var hit_ball = $HitBall
var fixed_y = 1
var projectile_y_offset = 1
Circular plane properties
var circle_radius = 5.0
var circle_segments = 32
var target_position = Vector3()
var launch_speed = 20.0 # Declare launch_speed as a class variable
var time_of_flight = 0.0
var gravity = ProjectSettings.get_setting(“physics/3d/default_gravity”)
var arc_height = 5
var immediate_mesh : ImmediateMesh
@onready var arc_shader: Shader = load(“res://Shaders/arc.gdshader”)
@onready var ui: Crew = get_node(“/root/Main/Crew”)
@export var boat: Boat
var cooldown_timer: Timer
var can_fire := true
func _ready():
immediate_mesh = ImmediateMesh.new()
arc_mesh_instance.mesh = immediate_mesh
arc_mesh_instance.cast_shadow = false
#cooldown_timer = Timer.new()
#cooldown_timer.set_wait_time(1.0/ui.fire_rate)
#cooldown_timer.autostart = false
#cooldown_timer.one_shot = true
#add_child(cooldown_timer) # must be added to tree for timer to work
# Signals
InputController.controller_status_changed.connect(self._on_controller_status_changed)
func _on_controller_status_changed(is_using_controller: bool):
if is_using_controller:
reticle.global_transform.origin = boat.global_transform.origin
reticle.global_transform.origin.y = fixed_y
func _process(delta):
if boat == null:
boat = get_node_or_null(“/root/Main/NewBoat”) # Adjust the path to match your scene tree
if boat == null:
print(“Error: Could not find the Boat node! Stopping execution.”)
return # Stop execution if boat is still null
print("Boat position:", boat.global_transform.origin, "Target:", target_position)
#cooldown_timer.set_wait_time(1.0/ui.fire_rate)
# Update the plane's position continuously to follow the mouse position
if InputController.is_using_controller:
reticle.global_transform.origin = InputController.apply_inputs_to_vector(reticle.global_transform.origin, 10*delta)
else:
var mouse_pos = get_viewport().get_mouse_position()
reticle.global_transform.origin = get_position_on_y_plane(
camera.project_ray_origin(mouse_pos),
camera.project_ray_normal(mouse_pos),
fixed_y
)
# Draw the arc from the projectile origin to the target plane
target_position = reticle.global_transform.origin
adjust_launch_speed(boat.global_transform.origin, target_position)
draw_arc(boat.global_transform.origin, target_position)
# Check for mouse click to launch the projectile
if Input.is_action_just_pressed("mouse_click"):
#and cooldown_timer.is_stopped() and ui.cannon_amount > 0:
#cooldown_timer.start()
#ui._add_cannon(-1)
launch_object(target_position)
Function to calculate the intersection of a ray with a horizontal plane at fixed_y
func get_position_on_y_plane(origin: Vector3, direction: Vector3, fixed_y: float) → Vector3:
if direction.y == 0:
return origin
var t = (fixed_y - origin.y) / direction.y
return origin + direction * t
Function to adjust the launch speed based on distance to the target
func adjust_launch_speed(start_pos: Vector3, end_pos: Vector3):
var horizontal_distance = Vector3(start_pos.x - end_pos.x, 0, start_pos.z - end_pos.z).length()
# Calculate time of flight using the vertical motion equation
var initial_vertical_velocity = arc_height # Vertical velocity
time_of_flight = (initial_vertical_velocity + sqrt(initial_vertical_velocity**2 + 2 * gravity * (start_pos.y + projectile_y_offset - fixed_y))) / gravity
# Adjust launch_speed to ensure the projectile lands on the plane
launch_speed = horizontal_distance / time_of_flight
func launch_object(target: Vector3):
var modified_boat = boat.global_transform.origin
modified_boat.y += projectile_y_offset
var direction = (target - modified_boat).normalized()
var projectile = projectile_scene.instantiate() as RigidBody3D
projectile.global_transform.origin = modified_boat
add_child(projectile)
var velocity_xz = direction * launch_speed
var velocity_y = arc_height
var velocity = Vector3(velocity_xz.x, velocity_y, velocity_xz.z)
projectile.launch(velocity)
Input.start_joy_vibration(0, 0.15, 0, 0.25)
Function to draw the arc from the origin to the target
func draw_arc(origin: Vector3, target: Vector3):
immediate_mesh.clear_surfaces()
immediate_mesh.surface_begin(Mesh.PRIMITIVE_POINTS)
var boat_y = boat.global_transform.origin.y
var horizontal_distance = Vector3(origin.x - target.x, 0, origin.z - target.z).length()
var num_segments = horizontal_distance * 3
hit_ball.visible = false
for i in range(num_segments + 1):
var t = float(i) / num_segments
var arc_point = lerp(origin, target, t)
var lt = lerp(0.0, time_of_flight, t)
if t > 0.0 and t < 1.0:
arc_point.y = boat_y + projectile_y_offset + arc_height*lt - (gravity*(lt**2))/2
immediate_mesh.surface_add_vertex(arc_point)
var collider = _check_arc_point_collision(arc_point)
if collider != null:
print(collider)
hit_ball.global_transform.origin = arc_point
hit_ball.visible = true
break
immediate_mesh.surface_end()
func _check_arc_point_collision(point: Vector3):
var layer_mask = 1 << 0
var space_state = get_world_3d().direct_space_state
var params = PhysicsPointQueryParameters3D.new() # Create new parameters
params.position = point # Set the position to check for collisions
params.collision_mask = layer_mask # Set the layer mask
var results = space_state.intersect_point(params)
if results.size():
for result in results:
var collider = result["collider"]
if collider.name == "NewBoat" || collider is Cannonball:
continue
return result["collider"]
return null```