This document is about: QUANTUM 2
SWITCH TO

Platform Shooter 2D

Level
INTERMEDIATE

Overview

The Platform Shooter 2D sample is provided with full source code and demonstrates how Quantum 2 can be used to create a fast and action-packed online 2D platform shooter.
The sample has been around since Quantum 1 and was originally called Blueless and developed by BitCake Studio for Photon Engine.

## Download
VersionRelease DateDownload
2.1.94月 22, 2025Quantum Platform Shooter 2D 2.1.9

Before You Start

To run the sample in online multiplayer mode, first create a Quantum AppId in the PhotonEngine Dashboard and paste it into the AppId field in PhotonServerSettings asset.
Then load the Menu scene in the Scenes menu and press Play.

Technical Info

  • Unity: 2020.3.20f1.
  • Platforms: PC (Windows / Mac), WebGL and Mobile (Android)

Highlights

Technical

Gameplay

  • Fast paced, 2D platform shooter.
  • Double jump.
  • Area damage.
  • Grenade.
  • Weapon reload time.
  • Change weapon using weapon inventory.

Controls

Use A S to movement, Space to jump, Q E to change weapon, F to use the granade, Left Mouse Button to shoot and use the mouse cursor to aim.

Useful Patterns

Raycast projectiles based on delta-movement

This is a good approach to prevent fast bullets from crossing walls. A raycast based on direction and speed is used to predict the next bullet movement and detect a hit, if any.

C#

Physics2D.HitCollection hits = frame.Physics2D.LinecastAll(bulletTransform->Position, futurePosition);
for (int i = 0; i < hits.Count; i++)
{
  var entity = hits[i].Entity;
  ...
  if (entity == EntityRef.None)
  {
    bulletTransform->Position = hits[i].Point;
    // Applies polymorphic behavior on the bullet action
    data.BulletAction(frame, bullet, EntityRef.None);
    return true;
  }
}

Disconnect System

Using the DeterministicInputFlags we check if the player is present. So, the entities of players who are not present for a while are removed from the simulation.

C#

public override void Update(Frame frame)
{
  frame.Global->DisconnectTime += frame.DeltaTime;

  var robotsFilter = frame.Filter<PlayerID, Status>();
  while (robotsFilter.NextUnsafe(out var robot, out var playerID, out var robotStatus))
  {
    DeterministicInputFlags flags = frame.GetPlayerInputFlags(playerID->PlayerRef);

    if ((flags & DeterministicInputFlags.PlayerNotPresent) == DeterministicInputFlags.PlayerNotPresent)
    {
      robotStatus->DisconnectedTicks++;
    }
    else
    {
      robotStatus->DisconnectedTicks = 0;
    }
    if (robotStatus->DisconnectedTicks >= 15)
    {
      frame.Destroy(robot);
    }
  }
}
Back to top