character follow custom line drawn with mouse or touch

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By aadyainfotainment

I am stuck with this to create a 2d game similar to airline traffic.

similar to below image:

  1. If you touch the character, a line will be drawn from the touch/click point to the point where we release the touch/click.
  2. the airplanes follow the drawn path
  3. if you drag on the airplane again, the drawn path will get deleted and a new path will be drawn.
  4. When the airplane follows the line, it will erase the line.

Thanks in advance for your support

Which part are you having trouble with? Drawing the line or making the plane follow it?

Either way you need to use the PoolVector2Array type. If it’s drawing the path look at Line2D or if it’s making the plane follow it look at PathFollow2D.

Magso | 2020-04-09 17:42

I am trying to implement your given solution

My airplane script:

extends KinematicBody2D
var entered
var velocity = Vector2()
var speed = 20


# Called when the node enters the scene tree for the first time.
func _ready():
	set_process_input(true)
	#$planepath.global_position = Vector2(0,0)

func _physics_process(delta):
	velocity = move_and_slide(velocity)
	
func start(pos, dir, speedx, speedy):
	rotation = dir
	position = pos
	velocity = Vector2(speedx, speedy).rotated(rotation)

My Airport script

extends Node2D

var screen_size
var posArray = PoolVector2Array()
export (PackedScene) var bplane
var _dragging = false
var lineElement = Line2D.new()
var lineArray = PoolVector2Array()

# Called when the node enters the scene tree for the first time.
func _ready():
	$planeTimer.start()
	
func _physics_process(delta):
	if _dragging == false:
		lineArray.resize(0)


func _on_startTimer_timeout():
	$startTimer.stop()
	$planeTimer.start()


func _on_planeTimer_timeout():
	$planeTimer.stop()
	spawn_planes()
	
	$startTimer.start()

func spawn_planes():
	var my_group_members = get_tree().get_nodes_in_group("startPos")
	screen_size = get_viewport_rect().size
	randomize()
	var pl = bplane.instance()
	var speedx
	var speedy
	var start_pos = my_group_members[randi() % my_group_members.size()]
	if start_pos.is_in_group("leftG"):
		var left_deg = [0, 45, 90]
		speedx = 0
		speedy = -20
		pl.rotation = left_deg[randi() % left_deg.size()]
	elif start_pos.is_in_group("rightG"):
		var right_deg = [180, 225, 270]
		speedx = 0
		speedy = -20
		pl.rotation = right_deg[randi() % right_deg.size()]
	elif start_pos.is_in_group("topG"):
		var top_deg = [90, 135, 180]
		speedx = 0
		speedy = -20
		pl.rotation = top_deg[randi() % top_deg.size()]
	elif start_pos.is_in_group("bottomG"):
		var bot_deg = [315, 0, 45]
		speedx = 0
		speedy = -20
		pl.rotation = bot_deg[randi() % bot_deg.size()]
	
		
	pl.start(start_pos.global_position, pl.rotation, speedx, speedy)
	add_child(pl)

func _input(event):
	
	if event is InputEventMouseButton:
		if event.is_action_pressed("click"):
			print('mouse pressed')
			_dragging = true
		elif event.is_action_released("click"):
			print('mouse released')
			_dragging = false
	if event is InputEventMouseMotion:
		if _dragging:
			_createArray(lineElement)



func _createArray(lineElement):
			if lineArray.size() == 0:
				lineArray.append(get_global_mouse_position())
			else:
				lineArray.append(get_global_mouse_position())
			lineElement.set_points(lineArray)

It is spawning the planes but does not draw line when I click on the plane and drag.

I have also added Area2D named “detectTouch”
and
position2D in front of the plane named “directionStart”

I had earlier added the createArray function to the airplane script which was drawing a line but in weird places and also moved along with the plane so I decided to add line2D in the gameplay scene.

aadyainfotainment | 2020-04-10 16:50

:bust_in_silhouette: Reply From: Magso

I can’t quite grasp how you’re approaching it so here’s a working example. Create a scene with these nodes.

Node2D #Attach script here
> Path2D
   > PathFollow2D #disable loop and set lookahead to 20ish for smoothness
      > Sprite #position must be (0,0) or else it will be offset when following the path

The script.

onready var current_line2D = Line2D.new()
var curve2d : Curve2D
var last_position : Vector2
export var speed = 5
var started = false #stops the pathfollow setting off without a path

func _ready():
	add_child(current_line2D)

func _input(event: InputEvent) -> void:
	if Input.is_mouse_button_pressed(BUTTON_LEFT):
		started = true
		curve2d = null
		
		#start from the last position except for the first line
		if current_line2D.points.size() == 0 && last_position:
			current_line2D.add_point(last_position)
		
		#draw the points
		if event is InputEventMouseMotion:
			current_line2D.add_point(event.position)
	elif started:
		#curve2d is currently null
		if !curve2d:
			curve2d = Curve2D.new()
			
			#getting the last position as the start for the next path
			last_position = current_line2D.points[current_line2D.points.size()-1]
			
			#add all the points to curve2d
			for i in current_line2D.points.size():
				curve2d.add_point(current_line2D.points[i])
			
			#assign the curve
			$Path2D.curve = curve2d
			
			#set pathfollow to the beginning
			$Path2D/PathFollow2D.unit_offset = 0
			
			#follow the path
			while $Path2D/PathFollow2D.unit_offset < 1:
				$Path2D/PathFollow2D.offset += speed
				yield(get_tree(),"idle_frame")
			
			#clear for next path
			current_line2D.points = PoolVector2Array()

Thanks @Magso

That is a very beautiful script and it achieves some of the part. Thank you very much for taking time to resolve my issue.

I can’t figure out how to make the sprite go at a slow speed. I tried speed = 1, but it’s still 10 times faster than what I need.

Secondly, the plane is coming to an halt after travelling the path.

The basic idea is the plane is flying in the sky waiting for landing. The player routes the plane to the runway (the script you gave works fine here).

Now I want to know if we can add kinematic / rigid body instead of a sprite to the path which will have a speed of its own and will travel along the path if path is drawn?

Thirdly, if I instantiate the airplane at (0,0) position in the main scene, it works correctly. However, if it is placed at a different position, the path is drawn away from the mouse position (the same distance of the instantiated scene from origin)

aadyainfotainment | 2020-04-11 08:24

1 - I’m not sure why that is, as far as I knew it was working ok but I’ll have another look. I have a project that accelerates from a standing start and there’s no jolting.

2 - This would be another question regarding navigation of some sort, have a look around someone may have already solved this; enjoy the next stage of your project :slight_smile:

3 - I already mentioned this “#position must be (0,0) or else it will be offset when following the path” global_position has to be used to get the position because position stays at (0,0) even when it moves.

Magso | 2020-04-11 09:25