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.

Một listener riêng biệt đảm nhận việc quản lý dữ liệu. Nó nhận sự kiện, cập nhật Meta Clock, và yêu cầu manager sao chép các tổng số mới vào LocalStorage.

Sự tách biệt này mang lại hiệu quả ngay lập tức. Tôi có thể viết lại toàn bộ GameScene, thay đổi nhân vật người chơi, thay đổi góc camera, hoặc thậm chí chuyển đổi thể loại từ survival sang bullet hell mà không cần chạm vào hệ thống lưu trữ. Các hệ thống hoạt động độc lập. Chúng giao tiếp thông qua các sự kiện, chứ không phải qua các lời gọi hàm trực tiếp. Điều đó có nghĩa là ít xung đột khi merge hơn, ít lỗi hơn, và một mã nguồn không bị biến thành spaghetti sau sáu tháng.

Những nâng cấp thay đổi cuộc chơi

Có một nền tảng kỹ thuật vững chắc cũng trở nên vô dụng nếu các phần thưởng mang lại cảm giác như một bảng tính khô khan. Tôi đã dành rất nhiều thời gian để nghiên cứu xem cảm giác thực tế khi chơi các nâng cấp đó như thế nào.

Một số nâng cấp mang tính an toàn. Tăng tốc độ di chuyển. Thêm máu. Nạp đạn nhanh hơn. Những thứ này cho phép người chơi có thêm dư địa để mắc sai lầm. Chúng mang lại cảm giác an tâm. Chúng làm giảm độ khó của trò chơi mà không làm thay đổi các quy tắc.

Những nâng cấp khác lại thay đổi hoàn toàn các quy tắc. Trong Neon Survivor, tôi đã thêm "Piercing Rounds". Trước khi có nâng cấp này, một viên đạn sẽ dừng lại ở kẻ địch đầu tiên mà nó chạm trúng. Sau khi nâng cấp, nó xuyên qua các kẻ địch, có khả năng quét sạch cả một hàng chỉ trong một phát bắn.

Sự khác biệt là cực kỳ lớn. Tốc độ và máu có thể giúp bạn sống sót lâu hơn, nhưng Piercing Rounds thay đổi cách bạn chọn vị trí. Bạn bắt đầu dàn hàng kẻ địch. Bạn ngừng việc kiting quanh các rìa màn hình và bắt đầu xuyên phá qua chính giữa. Không gian ra quyết định của trò chơi được mở rộng.

Sự tiến triển tốt nên thay đổi quyết định của người chơi, chứ không chỉ là tăng các chỉ số. Nếu mọi nâng cấp đều chỉ là một sự tăng trưởng theo phần trăm, người chơi sẽ ngừng đọc mô tả. Họ nhấn, họ nâng cấp, rồi họ quên. Nếu một nâng cấp khiến họ phải suy nghĩ lại về chiến thuật, họ sẽ ghi nhớ nó. Họ sẽ bàn tán về nó. Họ sẽ quay lại để xem còn điều gì khác có thể đảo ngược hoàn toàn trò chơi hay không.

Thành quả thực sự

Vòng lặp "thêm một lượt nữa" không phải là một hệ thống đơn lẻ. Đó là mối quan hệ giữa mất mát và đạt được, được xây dựng trên một kiến trúc sạch và những phần thưởng đầy ý nghĩa.

Hãy xây dựng hai dòng thời gian riêng biệt và bảo vệ Meta Clock như thể nó đang nắm giữ niềm tin của người chơi, bởi vì đúng là như vậy. Hãy sử dụng các công cụ trong engine của bạn để giữ cho dữ liệu runtime luôn nhanh chóng và dữ liệu lưu trữ luôn an toàn. Hãy tách rời các scene khỏi bộ lưu trữ để bạn có thể cải tiến mà không phải lo sợ. Và khi thiết kế các nâng cấp, hãy tự hỏi liệu chúng mang lại cho người chơi thêm thời gian, hay mang lại cho họ những lựa chọn thú vị hơn.

Làm đúng điều này, và người chơi của bạn sẽ không chỉ đơn thuần là chấp nhận cái chết. Họ sẽ trông chờ vào nó. Mỗi lượt chơi trở thành một bước đệm cho lượt tiếp theo. Trò chơi không còn là một chuỗi các lần khởi động lại mà trở thành một cuộc leo trèo liên tục và duy nhất.