Private
Public Access
1
0
Sebastian Unterschütz 0412168c4e
Some checks failed
Dynamic Branch Deploy / build-and-deploy (push) Has been cancelled
better deploy
2025-11-27 19:42:08 +01:00
2025-11-27 19:42:08 +01:00
2025-11-27 19:42:08 +01:00
2025-11-26 18:56:59 +01:00
2025-11-27 19:42:08 +01:00
2025-11-25 23:36:09 +01:00
2025-11-24 22:32:10 +01:00
2025-11-25 18:13:08 +01:00
2025-11-24 22:32:10 +01:00
2025-11-24 22:32:10 +01:00
2025-11-26 18:58:14 +01:00
2025-11-26 18:56:59 +01:00
2025-11-25 23:36:09 +01:00
2025-11-27 19:42:08 +01:00
2025-11-25 18:11:47 +01:00
2025-11-27 19:42:08 +01:00
2025-11-27 19:42:08 +01:00
2025-11-26 18:56:59 +01:00

# **🏃 Escape the Teacher**

**A server-authoritative 2D endless runner built with Go, Redis, and JavaScript.**  

## **📖 About the Project**

"Escape the Teacher" is a high-performance web game developed as a school project. You play as a student caught cheating, running away from an angry teacher. The game features increasing difficulty, power-ups, boss phases, and a competitive global leaderboard.  
Unlike typical browser games, this project implements **anti-cheat architecture** usually found in multiplayer RTS or FPS games. The browser does not decide if you survived; the server does.

## **✨ Features**

### **🎮 Gameplay**

* **Endless Progression:** The game speeds up over time.  
* **Controls:**  
  * **Jump:** Space / Arrow Up / Tap / Left Click.  
  * **Crouch:** Arrow Down / Swipe Down (Mobile).  
* **Power-Ups:**  
  * 🛡️ **Godmode:** Survives 3 hits.  
  * ⚾ **Baseball Bat:** Eliminates the next teacher obstacle.  
  * 👟 **Jumpboots:** Grants higher jumping power for a limited time.  
  * 💰 **Coins:** Bonus points (visual score only, does not affect game speed).  
* **Dynamic Backgrounds:** Environment changes as you progress.  
* **Boss Phases:** Every 1500 ticks, special boss enemies spawn.

### **📱 Mobile First**

* Fully responsive Canvas rendering (Letterboxing).  
* Touch gestures (Swipe to crouch).  
* "Rotate Device" enforcement for optimal gameplay.

### **🛡️ Security & Admin**

* **Admin Panel:** Password-protected (/admin) interface.  
* **Moderation:** Review and delete leaderboard entries.  
* **Badword Filter:** Automatic blocking of inappropriate names using Redis Sets.  
* **Proof System:** Players receive an 8-character "Claim Code" to prove their high score to the teacher.

## **🏗️ Technical Architecture**

The core philosophy is **"Server-Authoritative, Client-Predicted"**.

1. **Frontend (JS):** Captures inputs and renders the game state immediately (Client-Side Prediction) to ensure zero input lag. It sends input logs to the server in chunks.  
2. **Backend (Go):** Validates the inputs by re-simulating the game physics tick-by-tick.  
3. **Database (Redis):** Stores active sessions, RNG states, and leaderboards (Sorted Sets).

### **Tech Stack**

* **Backend:** Go (Golang) 1.21+  
* **Frontend:** Vanilla JavaScript (Canvas API), CSS3  
* **Database:** Redis  
* **Containerization:** Docker (Multi-Stage Build: Node Minifier \-\> Go Builder \-\> Alpine Runner)  
* **Orchestration:** Kubernetes (Deployment, Service, Ingress)

## **🔧 Development Challenges & Solutions**

Developing a cheat-proof game for the web came with significant technical hurdles. Here is how we solved them:

### **1\. The "Butterfly Effect" (RNG Desynchronization)**

* **Problem:** JavaScript's Math.random() and Go's rand implementations are different. Even if seeded with the same number, they produce different sequences. This caused "Ghost Objects" (Server spawns a teacher, Client spawns a coin).  
* **Solution:** We implemented a custom **Linear Congruential Generator (LCG)** in both languages.  
* **The Tricky Part:** JavaScript uses 64-bit Floating Point numbers for everything, while Go uses strict types. Math operations drifted apart after a few hundred iterations.  
* **Fix:** We forced JavaScript to use BigInt to simulate 32-bit integer overflows exactly like Go's uint32.

### **2\. Floating Point Drift & Spawning**

* **Problem:** We initially spawned objects based on pixel positions (if x \< 800). Due to floating point precision errors, the client sometimes calculated 799.99 (Spawn\!) while the server calculated 800.01 (Wait\!). This desynchronized the RNG state immediately.  
* **Solution:** **Tick-Based Spawning.** We decoupled spawning from spatial positions. The game now decides: *"The next object spawns at Tick 500"* rather than *"at Pixel 1200"*. Integers don't drift.

### **3\. Logic-Score Coupling**

* **Problem:** Initially, game speed and boss phases depended on the *Score*. When we added Coins (+2000 Points), the client's score jumped instantly, speeding up the game on the client side before the server acknowledged the coin pickup. This caused massive desyncs.  
* **Solution:** We decoupled logic from the visual score. Game difficulty now depends strictly on **"Ticks Alive" (Time)**, which cannot be manipulated by picking up items.

### **4\. Physics Tunneling (High Speed Collisions)**

* **Problem:** At high speeds, the player could move 20 pixels per frame. If an obstacle was only 15 pixels wide, the player effectively "teleported" through it without triggering a collision.  
* **Solution:** **Continuous Collision Detection (CCD).** We extend the hitbox of obstacles dynamically based on their current speed (width \+ speed).

### **5\. "Ghost Hits" (The CCD Side Effect)**

* **Problem:** The CCD fix caused a new issue where the extended hitbox would hit the player *after* they had already jumped over the obstacle (hitting them from behind).  
* **Solution:** A **"Passed Check"**. Before checking collisions, we verify if the obstacle's right edge is already physically behind the player's left edge. If so, collision is ignored.

## **🚀 Getting Started**

### **Using Docker (Recommended)**

This project includes a production-ready Dockerfile and docker-compose.yml.

1. **Clone the repository:**  
   git clone \[https://git.zb-server.de/ZB-Server/it232Abschied.git\](https://git.zb-server.de/ZB-Server/it232Abschied.git)  
   cd it232Abschied

2. Configure Environment (Optional):  
   Edit docker-compose.yml to set your admin credentials:  
   environment:  
     \- ADMIN\_USER=teacher  
     \- ADMIN\_PASS=secret123

3. **Run:**  
   docker-compose up \--build \-d

4. **Play:** Open http://localhost:8080

### **Local Development (Go & Redis)**

1. Start Redis:  
   docker run \-d \-p 6379:6379 redis:alpine

2. Start the Server:  
   go run .

   *(Note: Use go run . to include all files, not just main.go)*

## **📂 Project Structure**

.  
├── k8s/                    \# Kubernetes manifests  
├── static/                 \# Frontend files  
│   ├── assets/             \# Images & Sprites  
│   ├── fonts/              \# Local GDPR-compliant fonts  
│   ├── js/                 \# Modular Game Engine  
│   │   ├── config.js       \# Constants  
│   │   ├── logic.js        \# Physics & Collision  
│   │   ├── network.js      \# Server-Sync  
│   │   └── ...  
│   ├── index.html          \# Entry Point  
│   └── style.css           \# Retro Design  
├── secure/                 \# Protected Admin Files  
├── main.go                 \# Go Server Entrypoint  
├── simulation.go           \# Server-side Physics Engine  
├── rng.go                  \# Deterministic RNG  
├── types.go                \# Data Structures  
├── Dockerfile              \# Multi-Stage Build  
└── ...

## **📜 Legal**

This is a non-commercial educational project.

* **Privacy:** No tracking cookies are used. Highscores are stored in Redis; local scores in LocalStorage.  
* **Assets:** Font "Press Start 2P" is hosted locally.

**Good luck escaping\! 🏃💨**
Description
No description provided
Readme 36 MiB
Languages
JavaScript 85.9%
HTML 7.6%
Go 5.2%
CSS 1.1%
Dockerfile 0.2%