Galaxy Shooter 2D — Laser Beam

I’m a’ firin’ mah lazer!!

Pablo Gómez Platón
Nerd For Tech

--

It’s time to bring in the big guns! Today, I want to showcase the newest addition in my game: Laser Beam! A mighty weapon of mass destruction that will quickly wipe any entity in its way (including lasers), and so optimized the game won’t even drop a frame!

There’s a lot to unpack here. Unfortunately, I will have to cut some excess content to keep this article somewhat simple. Nonetheless, here’s how I implemented this feature:

Laser Beam Design

Powerup

The laser beam is a powerup pickup with unlimited hold time (meaning that the player will keep that powerup unless the player starts using it or has picked up another weapon powerup).

Laser Beam Components

The beam is made of:

  • (PlayerBeam) A Sprite Renderer with a sliced sprite (you’ll need to install the 2D Sprites package to make one) where the Laser Beam script will be attached and where the next components will be parented to.
  • (FakedBeamAreaLight) A fake 2D light area sprite. Because I’m not using 2D lighting in my project, I’ll need to fake it. This what we, gamedevs, call cardboard tricks. As long as the players don’t notice them, you’ll be able to get away with it!
  • (BeamChargeUpPS) A particle system, which will add more impact or feel to the beam.
  • (BeamForceFieldPS) A particle system force field, to create an orbital effect with the particle system.

I’ve also added an animator to the PlayerBeam GameObject to make the sprite glow when the beam becomes visible, and an AudioSource to add sounds!

“No colliders”

I’ve read that resizing colliders causes performance hits, which is quite unfortunate as the beam will be constantly resizing, even when the beam has completely exited the screen. I could’ve ignored that and used a standard 2D Box Collider, but because I care about performance, I decided to use Physics2D.OverlapBoxNonAlloc to check for the enemies inside the beam volume.

The grey box is the Laser Beam collider detector, all entirely made with code. Also, to avoid spawn killing, the Beam sprite is constantly resized to avoid exceeding a Y value I’ve set.

Later on, it backfired on me as I realized that I couldn’t implement a specific type of enemy because the code collision queries can’t be detected by other queries (can’t detect an OverlapBox with another one). So, I ended up using a collider which I enable and disable only when the laser beam starts / stops resizing (another cardboard trick to allow other features to register the collider).

Beam States

Once the player decides to use it by pressing the “Fire” input, the laser beam will go through 3 states, handled by a Coroutine:

  • Charge (Stage 1): From the 0–25% laser beam charge, the FakedBeamAreaLight will slowly light up (by setting the alpha value to the max). After that percentage, the light will blink until the Windup state.
  • Charge (Stage 2): Up to the 50% charge, BeamChargeUpPS will start emitting particles.
  • Beam Fire: At 100%, the PlayerBeam will start growing, and once it was made contact with the max Y value, a beam duration countdown will start, and it will start checking for colliders (through a Coroutine).
  • Windup: The PlayerBeam will start regressing, the FakedBeamAreaLight will slowly fade out, and the BeamChargeUpPS will stop emitting particles. As soon as the PlayerBeam has completely regressed, the Laser Beam state will switch to the Inactive state and it will stop checking for colliders (stopping both Coroutines).

Laser Beam Code

There’s a great amount of code to examine. To keep everything simple, I will only show the most important fragments of it, and most of the descriptions / explanations will be commented in the code images below.

Beam Collider Detection Coroutine

Like my Heat Seeking Lasers, it will check for colliders every update frame (this can always be changed in any case).

Main Beam Coroutine

I’ve decided to make a small a Finite State Machine (FSM), where every state of the Laser Beam has a Start, Execute and Exit method. FSM is mostly used for developing AIs, but it can also be applied to other gameplay mechanics.

The only difference is that these states are hardcoded (not going to program a flexible FSM framework for a small little project, you know?) inside a Coroutine, all following a sequence.

This article has been quite long, and if I were to explain every single method and behaviour inside the LaserBeam script, this would drag on even longer. So, to conclude the article, here’s the commented code of the Charge and Beam Fire states.

  • Charge
  • Fire Beam

In-Game Result

--

--