The best roguelikes do not just kill you. They make you want to die.
That sounds strange, but anyone who has lost a run at midnight and started another at 12:03 knows the feeling. Death stings. Your health drops to zero. The screen floods with failure. Yet your finger is already hovering over the play button. Something about the last twenty minutes mattered enough that you cannot leave the game where it ended.
This is the "one more run" loop, and it is not accidental. It is designed. If you are building a roguelike or any game with permadeath, your entire job is to balance two opposing forces. The player must lose enough to feel tension. They must keep enough to feel hope.
The Currency of Failure
In my latest project, Neon Survivor, I wanted that exact tension. When the player dies, everything gathered during the run disappears except for one thing: gold. That gold gets banked automatically. Back at the menu, they spend it on permanent upgrades. Then they jump in again, slightly stronger than before.
This simple loop carries the whole game. Without it, death is a full stop. The player walks away because the last run got them nothing. With it, death is a comma. The run became a farming trip. The loss hurts, but it also paid for tomorrow.
The trick is simple. You keep something even when you lose everything else. The difficulty is making sure the thing you keep matters without destroying the challenge. If the upgrades are too weak, the player stops caring. If they are too strong, the game plays itself. The loop collapses either way.
Two Clocks, Zero Confusion
To build this properly, I had to manage two separate timelines.
The Run Clock resets every time you hit play. It tracks health, current score, enemy wave count, and any temporary power-ups picked up during the session. When the character dies, this clock winds back to zero.
The Meta Clock never resets. It holds total gold earned across every attempt, the highest wave ever reached, and every permanent upgrade purchased. This clock keeps ticking no matter how many times the browser refreshes.
Mix these two together and you get bugs that are hard to track and painful to fix. I have seen developers accidentally wipe player progress during a routine scene reset because a cleanup function touched the wrong data store. The Meta Clock data evaporates. The player returns to zero gold and zero upgrades. At that point, the relationship between you and your player is broken. They are not starting a new run; they are starting a new grudge.
Keeping the clocks separate is not just a style choice. It is a survival strategy.
How Phaser v4 Handles the Split
I built Neon Survivor in Phaser v4, which offers two specific tools for this problem.
The Registry holds live data in memory for the current session. It is fast. It is simple. It also evaporates the moment the player refreshes the page.
LocalStorage saves data to the browser itself. It survives tab closures, browser restarts, and power outages. It is also slower and less reliable. Browsers can block it, throttle it, or wipe it if storage quotas fill up.
My design choice was strict. The Registry is the only source of truth during gameplay. The game reads from it, writes to it, and trusts it completely. LocalStorage does not act as a co-author. It acts as a mirror.
Here is how the flow works. The game writes an upgrade purchase to the Registry. A single manager class watches the Registry. When appropriate, that manager mirrors the Registry data to LocalStorage. If the browser blocks the write, the game does not stutter. If storage fails, the current session still runs perfectly. The player might lose progress only if they close the tab in the exact same second, but the session itself never crashes.
This pattern prevents a subtle disaster. If you let every system write directly to LocalStorage, you create dependencies on a fragile API. A player with privacy settings cranked up or a device low on storage could see the game slow down or freeze during combat because some background function tried to save stats. By making the Registry the sole source of truth, you keep the action fast and the risk contained.
Let the Code Breathe
I also used events to decouple the systems. When a run ends, the GameScene does not handle its own funeral. It does not call a save function. It does not import a storage utility. It simply emits a "run-ended" event with a payload of the relevant data.
ఒక ప్రత్యేకమైన లిజనర్ (listener) లెక్కల నిర్వహణను చూసుకుంటుంది. ఇది ఈవెంట్ను స్వీకరించి, Meta Clockను అప్డేట్ చేస్తుంది మరియు కొత్త మొత్తాలను LocalStorageకి ప్రతిబింబించమని మేనేజర్కు చెబుతుంది.
ఈ విభజన వల్ల వెంటనే ప్రయోజనం లభిస్తుంది. సేవ్ సిస్టమ్ను తాకకుండానే నేను మొత్తం GameSceneను తిరిగి వ్రాయవచ్చు, ప్లేయర్ క్యారెక్టర్ను మార్చవచ్చు, కెమెరా యాంగిల్ను మార్చవచ్చు, లేదా జానర్ను సర్వైవల్ నుండి బుల్లెట్ హెల్కు కూడా మార్చవచ్చు. ఈ వ్యవస్థలు స్వతంత్రంగా ఉంటాయి. అవి నేరుగా ఫంక్షన్ కాల్స్ ద్వారా కాకుండా, ఈవెంట్ల ద్వారా మాట్లాడుకుంటాయి. అంటే తక్కువ మెర్జ్ కాన్ఫ్లిక్ట్స్, తక్కువ బగ్స్ మరియు ఆరు నెలల తర్వాత కూడా గందరగోళంగా మారని కోడ్బేస్ లభిస్తుంది.
ఆటను మార్చే అప్గ్రేడ్లు
రివార్డులు ఒక స్ప్రెడ్షీట్లా అనిపిస్తే, సాంకేతిక వెన్నెముక ఉండటం వల్ల ఉపయోగం లేదు. అప్గ్రేడ్లు ఆడేటప్పుడు ఎలా అనిపిస్తాయి అనే అంశంపై నేను చాలా సమయం వెచ్చించాను.
కొన్ని అప్గ్రేడ్లు సురక్షితమైనవి. అదనపు మూవ్మెంట్ స్పీడ్, బోనస్ హెల్త్, వేగవంతమైన రీలోడ్ వంటివి. ఇవి ప్లేయర్కు తప్పులు చేయడానికి మరికొంత అవకాశం ఇస్తాయి. ఇవి ఓదార్పునిస్తాయి. ఇవి ఆట నియమాలను మార్చకుండానే ఆట యొక్క కఠినత్వాన్ని తగ్గిస్తాయి.
ఇతర అప్గ్రేడ్లు నియమాలను పూర్తిగా మారుస్తాయి. Neon Survivorలో, నేను "Piercing Rounds"ను జోడించాను. ఈ అప్గ్రేడ్కు ముందు, ఒక బుల్లెట్ తగిలిన మొదటి శత్రువు వద్దే ఆగిపోయేది. అప్గ్రేడ్ తర్వాత, అది శత్రువుల గుండా దూసుకుపోతుంది, తద్వారా ఒకే షాట్తో మొత్తం వరుసలను క్లియర్ చేయగలదు.
ఈ తేడా చాలా స్పష్టంగా ఉంటుంది. వేగం మరియు ఆరోగ్యం మిమ్మల్ని ఎక్కువ కాలం బ్రతికి ఉండేలా చేయవచ్చు, కానీ Piercing Rounds మీరు శత్రువులను ఎలా ఎదుర్కోవాలో మారుస్తుంది. మీరు శత్రువులను ఒక వరుసలో నిలబెట్టడం ప్రారంభిస్తారు. మీరు అంచులలో తిరగడం మానేసి, మధ్య నుండి దూసుకుపోవడం ప్రారంభిస్తారు. ఆట యొక్క నిర్ణయ సామర్థ్యం (decision space) విస్తరిస్తుంది.
మంచి ప్రోగ్రెషన్ అనేది ప్లేయర్ యొక్క సంఖ్యలను పెంచడమే కాకుండా, వారి నిర్ణయాలను కూడా మార్చాలి. ప్రతి అప్గ్రేడ్ కేవలం శాతంలో పెరుగుదల మాత్రమే అయితే, ప్లేయర్ వివరణలను చదవడం మానేస్తారు. వారు క్లిక్ చేస్తారు, అప్గ్రేడ్ చేస్తారు, మర్చిపోతారు. ఒక అప్గ్రేడ్ వారి వ్యూహాన్ని మళ్ళీ ఆలోచించేలా చేస్తే, వారు దానిని గుర్తుంచుకుంటారు. దాని గురించి మాట్లాడుకుంటారు. ఆటను మళ్ళీ ఎలా మార్చవచ్చో చూడటానికి వారు తిరిగి వస్తారు.
అసలైన ఫలితం
"one more run" లూప్ అనేది ఒకే ఒక వ్యవస్థ కాదు. ఇది క్లీన్ ఆర్కిటెక్చర్ మరియు అర్థవంతమైన రివార్డులపై ఆధారపడిన నష్టానికి మరియు లాభానికి మధ్య ఉన్న సంబంధం.
రెండు విభిన్న టైమ్లైన్లను నిర్మించండి మరియు Meta Clock మీ ప్లేయర్ల నమ్మకాన్ని కలిగి ఉన్నట్లుగా దానిని రక్షించండి, ఎందుకంటే అది నిజంగానే వారి నమ్మకాన్ని కలిగి ఉంటుంది. లైవ్ డేటాను వేగంగా మరియు పర్సిస్టెంట్ డేటాను సురక్షితంగా ఉంచడానికి మీ ఇంజిన్ టూల్స్ను ఉపయోగించండి. మీరు భయం లేకుండా ఇటరేట్ చేయడానికి మీ సీన్లను మీ స్టోరేజ్ నుండి వేరు చేయండి (decouple). మరియు మీరు అప్గ్రేడ్లను రూపొందించినప్పుడు, అవి ప్లేయర్కు ఎక్కువ సమయాన్ని ఇస్తున్నాయా లేదా మరింత ఆసక్తికరమైన ఎంపికలను ఇస్తున్నాయా అని ప్రశ్నించుకోండి.
దీన్ని సరిగ్గా చేస్తే, మీ ప్లేయర్లు మరణాన్ని కేవలం భరించడమే కాదు, దానిపై ఆధారపడతారు. ప్రతి రన్ తదుపరి రన్కు ఒక పునాది అవుతుంది. ఆట కేవలం వరుసగా రీస్టార్ట్ అయ్యే ప్రక్రియగా కాకుండా, ఒకే ఒక నిరంతర ప్రయాణంలా మారుతుంది.
