How to make a beam-style laser weapon? (2D)

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

Hi all, just had a question for my game. I have a ship-based weapon being used to fend off hordes of enemies, but the standard pulse-laser isn’t enough in some situations, and the starship gets overwhelmed. What I’d like is a charge-up, secondary fire for my gun that generates a laser beam that the player can use to wipe the screen clean, and have a cooldown time for the beam after about five seconds of use. What would be a good way to make this happen?

LazerGun.gd

extends KinematicBody2D

const LAZER = preload("res://player-side/EnergyShot.tscn")
const ROTATION_SPEED = 0.5

signal fire

var playing = false
var rotation_Direction
var gun_temp = 0.0
var max_temp = 10.0
var heat_per_shot = 2.0
var cooling_power = 1.5
var can_fire = true
var can_fire_beam = true

func _process(delta):
	gun_temp -= cooling_power * delta
	if gun_temp < 0:
		gun_temp = 0
		can_fire = true

func get_input():
	rotation_Direction = 0.0
	if playing == true:
		if Input.is_action_pressed('test_up'):
			rotation_Direction -= 1.25
		elif Input.is_action_pressed('test_down'):
			rotation_Direction += 1.25
	
		if Input.is_action_just_pressed('test_fire'):
			fire()
	
		if Input.is_action_pressed('test_fire'): # Supposed to hold for a couple seconds.
			beam_fire()


func fire():
	if can_fire and gun_temp < max_temp:
		var lazershot = LAZER.instance()
		gun_temp += heat_per_shot
		if gun_temp > max_temp:
			can_fire = false
		lazershot.start($LazerSpawn.global_position, rotation)
		get_parent().add_child(lazershot)

func beam_fire(): # This is where I want most of the laser beam's code to be.
	pass

func _physics_process(delta):
	get_input()
	rotation += rotation_Direction * ROTATION_SPEED * delta
	rotation = clamp(rotation, deg2rad(-60), deg2rad(60))


func _on_game_over():
	playing = false

func _on_HUD_play_game():
	playing = true
:bust_in_silhouette: Reply From: MysteryGM

Use a line2D for graphics and RayCast for collision.

Something like this:

func beam_fire(InDelta): # This is where I want most of the laser beam's code to be.
	
	$Line2D.position = $LazerSpawn.global_position
	
	$Line2D.points[0] = Vector2.ZERO
	#So it only sets the position once
	if ($Line2D.points[1] == Vector2.ZERO):
		$Line2D.points[1] = Vector2(self.get_viewport_rect().size.x +16, 0)
		$Line2D/RayCast2D.cast_to = $Line2D.points[1]
		
	$Line2D.rotate(1 * InDelta)
	
	
func _process(delta):

	beam_fire(delta)

This makes a laser that spins around the start point. Use lookAt or the offset to aim the laser

Thanks.

Though, I’m rather new to Godot, so how would I use lookAt in this?

System_Error | 2019-01-11 07:38

I was tired, when I posted that so my mind defaulted to the standard way. There is actually a easier way to aim at the mouse:

func beam_fire(InDelta): # This is where I want most of the laser beam’s code to be.

$Line2D.position = $LazerSpawn.global_position

$Line2D.points[0] = Vector2.ZERO
#Just get the mouse position and subtract our own position from it
$Line2D.points[1] = get_global_mouse_position() - self.global_position

$Line2D/RayCast2D.cast_to = $Line2D.points[1]

The more advanced way uses a distance calculation to impose a limit on the beam:

func beam_fire(): # This is where I want most of the laser beam's code to be.

$Line2D.global_position = $LazerSpawn.global_position
$Line2D.points[0] = Vector2.ZERO


var Offset = get_global_mouse_position() - $Line2D.global_position
var DistanceToMouse = Offset.length()
var Rotation = Offset / DistanceToMouse #Optimal same as Offset.normalized()

var LimitedLazer = 300

if DistanceToMouse > LimitedLazer:
	$Line2D.points[1] = Rotation* LimitedLazer
else:
	$Line2D.points[1] = Offset
	
$Line2D/RayCast2D.cast_to = $Line2D.points[1]

I recommend that if you have some time, learn the basis of linear algebra. It is fundamental to game design; or learn it as you go.

MysteryGM | 2019-01-11 15:59