Inspiration

We've always loved one-shot physics puzzles: aim, let go, and watch a small chain reaction play out. What bothered us was how often they could be beaten by luck. In many of these games, a clean bank shot through a tight course earns the same reward as a clumsy shot that happens to fall in.

We wanted a game where the course is the puzzle and there's no way around it. It should be calm and minimal on screen, but honest underneath: real physics, no hidden walls, no lucky skips. Pull back, let go, and bank it into the goal.

What it does

Ricochet: Trickshot is a minimalist physics puzzler for iOS where every shot banks into the goal.

  • One mechanic. Pull back the slingshot, release, and the ball ricochets through an obstacle course. It has to settle inside the goal to clear the level.
  • 60 hand-tuned levels across 8 chapters. Each one teaches, tests or remixes a mechanic, and the difficulty rises steadily.
  • 22 obstacle types: walls, breakables, spinners, moving platforms, fans, bumpers, switches and gates, buttons, portals, elevators, pendulums, magnets, gravity zones, conveyors, springboards and more.
  • No borders and no floor. Every surface was placed on purpose. Miss, and the ball is gone.
  • An honest aim guide. It shows the real path of your shot, but only far enough to aim, never far enough to give away the answer.
  • Community levels. Build a level, publish it, share it with a link, and browse, play and like what others make. There's no account and no sign-up.
  • Offline first. The core game has no backend. Progress saves on the device and follows you to your other devices through iCloud.

How we built it

The stack

  • Game: SwiftUI for every screen, and SpriteKit to draw the board.
  • Physics: our own deterministic 2D physics engine, which replaced SpriteKit's built-in physics.
  • Saving: SwiftData for progress, and iCloud for sync across devices.
  • Purchases: RevenueCat.
  • Community: one Cloudflare Worker, with D1 for level details, counters and likes, and R2 for level files and thumbnails.
  • Level editor: a web editor that reads and writes the game's real level files. Drag a wall and the file changes; edit a number and the board changes.

Every level is designed on the same fixed board size, and the camera fits it edge to edge on any screen, so nothing is letterboxed.

A physics engine we could trust

We wrote our own physics engine around three rules:

  • It's deterministic. The same shot always lands in the same place, on any device and at any frame rate. Moving obstacles follow the simulation clock, not the screen.
  • It never misses a collision. Instead of moving the ball and then checking whether it hit something, the engine finds the first surface along the ball's path and stops there. Even a full-power shot can't slip through a thin wall.
  • It uses real-world units. Gravity, mass and spring force are real measurements, so tuning means adjusting values we can explain rather than guessing at multipliers. A level can turn gravity down for low-gravity or zero-gravity boards.

The launch

A simple "pull further, go faster" launch felt twitchy at low power and too easy at full power. We modelled the slingshot as a spring that stiffens as you pull it back. Small pulls are forgiving and easy to aim, while full power is genuinely harder to place.

Bounces and settling

Each surface has its own material. Stone and metal bounce well, while grass, felt and sand absorb more of the hit. Light air resistance gives long shots a natural range instead of a hard cap. When the ball slows down enough, its bounce fades out, so it settles instead of jittering forever.

An aim guide that can't lie

The aim guide runs the real physics engine a few moments ahead, then rewinds it. There's no separate prediction that could disagree with the actual shot. To keep it from solving the level for you, it stops after a short distance and a few bounces.

Community levels without accounts

  • On first use, the app creates a random secret for the device and keeps it in the Keychain.
  • The server stores only a scrambled (hashed) version of that secret, so the database never holds anything worth stealing.
  • Share links open a small landing page with an "Open in app" button.
  • The same level rules run in the app, the web editor and the server, so the app never sends a level the server would refuse.

Challenges we ran into

The lucky shot

This was the defining problem. Our early levels looked busy but played empty: the goal could often be reached in one straight line, skipping the whole course.

We made "no shortcuts" a hard rule and had the computer enforce it. Our level tools fire straight lines from the launch pad toward the goal. If even one of them gets through without hitting anything, the level is rejected automatically.

Proving every level is solvable

Blocking shortcuts isn't enough on its own; a level also has to be possible. Every level is played by a simulator using the game's own physics. Our tools reject anything that:

  • has a straight line to the goal
  • can't be solved
  • is too easy or too hard for its place in the game
  • needs a pixel-perfect shot
  • is too similar to a level already in the game

A new obstacle never appears before the level that introduces it, and the same kind of level never appears twice within four levels.

Replacing the engine without breaking our levels

Swapping physics engines risked quietly breaking all 45 levels we had already tuned. Before removing SpriteKit's physics, we built a test rig to measure exactly how it behaved: how fast the ball fell, how quickly it slowed down, and how much it bounced.

The results surprised us. Every wall in the game bounced exactly the same, no matter what value we had set. The old engine always used the ball's bounciness instead of the wall's, so our careful per-wall tuning had never done anything. The new engine matches the old feel as a starting point and adds real differences between materials.

Taming a wild board

Playtesters found the board too lively: a missed shot could carry through three or four walls and end up anywhere. We turned bounciness down across the whole game, so a ricochet still carries but a miss dies sooner, and then re-ran every level through the simulator to confirm each one still worked.

Frame rate must never change the outcome

A dropped frame must never change where a shot lands. The physics engine always takes fixed-size steps. If the phone stutters, the game briefly plays in slow motion to catch up rather than jumping the ball forward.

Accomplishments that we're proud of

  • A truly deterministic physics engine. The same shot gives the same result on every device and at every frame rate.
  • No lucky shots, by design. Every level is checked automatically for shortcuts and solvability before it ships.
  • An aim guide that is the real simulation, limited just enough to help you aim without solving the puzzle.
  • A launch that feels right, thanks to a spring model built on real-world physics.
  • Community levels with no sign-up, where the server never stores a usable password or key.
  • One source of truth for levels. The game, the web editor and the server all read the same level files and follow the same rules.
  • A minimal look that stays out of the way, so the physics is the star.

What we learned

  • Determinism is a feature, not a detail. It made the honest aim guide, automated level checks and shareable community levels possible.
  • Measure before you replace. Our test rig turned "it feels different" into numbers we could match, and showed that most of our old tuning values did nothing.
  • Put rules in code. "No shortcuts" was just an idea until an automatic check made it a test.
  • Real units make tuning honest. Real-world measurements turned guesswork into values we could explain.
  • Restraint is a design tool. Limiting the aim guide, removing borders and keeping visuals minimal made the puzzles more interesting, not less.

What's next for Ricochet: Trickshot

  • Grow the campaign to 100 levels, each checked by the same simulator.
  • Curiosity levels: optional challenge boards such as pinball, zero-gravity and clockwork.
  • A bigger community: search, rankings and following creators, while keeping the no-account model.
  • Daily shot: one shared level per day, with everyone playing the same physics.

Built With

  • ball
  • game
  • goal
  • ios
  • mobile
  • physics
  • puzzle
  • score
  • shooting
  • trickshot
Share this project:

Updates

Submission history