Platform Shooter 2D
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
| Version | Release Date | Download | 
|---|---|---|
| 2.1.9 | 4月 22, 2025 | Quantum 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
- Character Controller 3D with custom steering implementation.
 - Raycast projectiles based on delta-movement.
 - Data-Driven Polymorphism.
 - Respawn Points with Entity Prototypes.
 - Disconnect System for inactive players.
 
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