Refine player movement and physics constants for improved 20 TPS gameplay, add reusable config values, enhance button loading states, and prevent duplicate game starts. Update cache-busting version for client assets.
All checks were successful
Dynamic Branch Deploy / build-and-deploy (push) Successful in 2m3s
All checks were successful
Dynamic Branch Deploy / build-and-deploy (push) Successful in 2m3s
This commit is contained in:
@@ -362,11 +362,12 @@ func (g *Game) DrawGame(screen *ebiten.Image) {
|
|||||||
sprite := "player" // Default: am Boden
|
sprite := "player" // Default: am Boden
|
||||||
|
|
||||||
// Nur Jump-Animation wenn wirklich in der Luft
|
// Nur Jump-Animation wenn wirklich in der Luft
|
||||||
// (nicht auf Boden, nicht auf Platform mit VY ~= 0)
|
// Bei 20 TPS größerer Threshold (3.0 statt 1.0)
|
||||||
isInAir := !onGround && (vy < -1.0 || vy > 1.0)
|
// OnGround oder sehr kleine VY = am Boden/Plattform
|
||||||
|
isInAir := !onGround && (vy < -3.0 || vy > 3.0)
|
||||||
|
|
||||||
if isInAir {
|
if isInAir {
|
||||||
if vy < -2.0 {
|
if vy < -5.0 {
|
||||||
// Springt nach oben
|
// Springt nach oben
|
||||||
sprite = "jump0"
|
sprite = "jump0"
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -21,8 +21,8 @@ func (g *Game) ApplyInput(input InputState) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Geschwindigkeit skaliert mit Joystick-Intensität
|
// Geschwindigkeit skaliert mit Joystick-Intensität
|
||||||
// war 4.0 bei 60 TPS (4.0 * 3 = 12.0)
|
// Bewegung relativ zum Scroll (symmetrisch)
|
||||||
speed := config.RunSpeed + (moveX * 12.0)
|
speed := config.RunSpeed + (moveX * config.PlayerSpeed)
|
||||||
g.predictedX += speed
|
g.predictedX += speed
|
||||||
|
|
||||||
// Gravitation
|
// Gravitation
|
||||||
@@ -33,12 +33,12 @@ func (g *Game) ApplyInput(input InputState) {
|
|||||||
|
|
||||||
// Fast Fall
|
// Fast Fall
|
||||||
if input.Down {
|
if input.Down {
|
||||||
g.predictedVY = 45.0 // war 15.0 bei 60 TPS (15.0 * 3)
|
g.predictedVY = config.FastFall
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sprung
|
// Sprung
|
||||||
if input.Jump && g.predictedGround {
|
if input.Jump && g.predictedGround {
|
||||||
g.predictedVY = -30.0 // Reduziert für besseres Spielgefühl bei 20 TPS
|
g.predictedVY = -config.JumpVelocity
|
||||||
g.predictedGround = false
|
g.predictedGround = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
// Game State
|
// Game State
|
||||||
let wasmReady = false;
|
let wasmReady = false;
|
||||||
let gameStarted = false;
|
let gameStarted = false;
|
||||||
|
let gameStarting = false; // Verhindert doppeltes Starten
|
||||||
let audioMuted = false;
|
let audioMuted = false;
|
||||||
let currentLeaderboard = []; // Store full leaderboard data with proof codes
|
let currentLeaderboard = []; // Store full leaderboard data with proof codes
|
||||||
|
|
||||||
@@ -234,7 +235,7 @@ window.onWasmReady = function() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Cache Management - Version wird bei jedem Build aktualisiert
|
// Cache Management - Version wird bei jedem Build aktualisiert
|
||||||
const CACHE_VERSION = 1767639190355; // Wird durch Build-Prozess ersetzt
|
const CACHE_VERSION = 1767643088942; // Wird durch Build-Prozess ersetzt
|
||||||
|
|
||||||
// Fetch mit Cache-Busting
|
// Fetch mit Cache-Busting
|
||||||
async function fetchWithCache(url) {
|
async function fetchWithCache(url) {
|
||||||
@@ -315,7 +316,22 @@ function startSoloGame() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Verhindere doppeltes Starten
|
||||||
|
if (gameStarting) {
|
||||||
|
console.log('⚠️ Game is already starting...');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
gameStarting = true;
|
||||||
|
|
||||||
const playerName = document.getElementById('playerName').value || 'ANON';
|
const playerName = document.getElementById('playerName').value || 'ANON';
|
||||||
|
const startBtn = document.getElementById('startBtn');
|
||||||
|
|
||||||
|
// Button deaktivieren und Loading anzeigen
|
||||||
|
if (startBtn) {
|
||||||
|
startBtn.disabled = true;
|
||||||
|
startBtn.innerHTML = '<span class="spinner-small"></span> Starte...';
|
||||||
|
startBtn.style.opacity = '0.6';
|
||||||
|
}
|
||||||
|
|
||||||
// Store in localStorage for WASM to read
|
// Store in localStorage for WASM to read
|
||||||
localStorage.setItem('escape_player_name', playerName);
|
localStorage.setItem('escape_player_name', playerName);
|
||||||
@@ -341,6 +357,21 @@ function createRoom() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Verhindere doppeltes Starten
|
||||||
|
if (gameStarting) {
|
||||||
|
console.log('⚠️ Game is already starting...');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
gameStarting = true;
|
||||||
|
|
||||||
|
const createBtn = document.getElementById('createRoomBtn');
|
||||||
|
// Button deaktivieren und Loading anzeigen
|
||||||
|
if (createBtn) {
|
||||||
|
createBtn.disabled = true;
|
||||||
|
createBtn.innerHTML = '<span class="spinner-small"></span> Erstelle Raum...';
|
||||||
|
createBtn.style.opacity = '0.6';
|
||||||
|
}
|
||||||
|
|
||||||
const playerName = document.getElementById('playerName').value || 'ANON';
|
const playerName = document.getElementById('playerName').value || 'ANON';
|
||||||
const roomID = 'R' + Math.random().toString(36).substr(2, 5).toUpperCase();
|
const roomID = 'R' + Math.random().toString(36).substr(2, 5).toUpperCase();
|
||||||
const teamName = 'TEAM';
|
const teamName = 'TEAM';
|
||||||
@@ -352,12 +383,17 @@ function createRoom() {
|
|||||||
localStorage.setItem('escape_team_name', teamName);
|
localStorage.setItem('escape_team_name', teamName);
|
||||||
localStorage.setItem('escape_is_host', 'true');
|
localStorage.setItem('escape_is_host', 'true');
|
||||||
|
|
||||||
// Show Lobby
|
// Show Lobby nach kurzer Verzögerung (damit User Feedback sieht)
|
||||||
|
setTimeout(() => {
|
||||||
setUIState(UIState.LOBBY);
|
setUIState(UIState.LOBBY);
|
||||||
document.getElementById('lobbyRoomCode').textContent = roomID;
|
document.getElementById('lobbyRoomCode').textContent = roomID;
|
||||||
document.getElementById('lobbyHostControls').classList.remove('hidden');
|
document.getElementById('lobbyHostControls').classList.remove('hidden');
|
||||||
document.getElementById('lobbyStatus').textContent = 'Du bist Host - starte wenn bereit!';
|
document.getElementById('lobbyStatus').textContent = 'Du bist Host - starte wenn bereit!';
|
||||||
|
|
||||||
|
// Reset gameStarting für Lobby
|
||||||
|
gameStarting = false;
|
||||||
|
}, 300);
|
||||||
|
|
||||||
// Trigger WASM game start (im Hintergrund)
|
// Trigger WASM game start (im Hintergrund)
|
||||||
if (window.startGame) {
|
if (window.startGame) {
|
||||||
console.log('🎮 Calling window.startGame with:', 'coop', playerName, roomID, teamName, true);
|
console.log('🎮 Calling window.startGame with:', 'coop', playerName, roomID, teamName, true);
|
||||||
@@ -375,12 +411,34 @@ function joinRoom() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Verhindere doppeltes Starten
|
||||||
|
if (gameStarting) {
|
||||||
|
console.log('⚠️ Game is already starting...');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
gameStarting = true;
|
||||||
|
|
||||||
|
const joinBtn = document.getElementById('joinRoomBtn');
|
||||||
|
// Button deaktivieren und Loading anzeigen
|
||||||
|
if (joinBtn) {
|
||||||
|
joinBtn.disabled = true;
|
||||||
|
joinBtn.innerHTML = '<span class="spinner-small"></span> Trete bei...';
|
||||||
|
joinBtn.style.opacity = '0.6';
|
||||||
|
}
|
||||||
|
|
||||||
const playerName = document.getElementById('playerName').value || 'ANON';
|
const playerName = document.getElementById('playerName').value || 'ANON';
|
||||||
const roomID = document.getElementById('joinRoomCode').value.toUpperCase();
|
const roomID = document.getElementById('joinRoomCode').value.toUpperCase();
|
||||||
const teamName = document.getElementById('teamNameJoin').value || 'TEAM';
|
const teamName = document.getElementById('teamNameJoin').value || 'TEAM';
|
||||||
|
|
||||||
if (!roomID || roomID.length < 4) {
|
if (!roomID || roomID.length < 4) {
|
||||||
alert('Bitte gib einen gültigen Raum-Code ein!');
|
alert('Bitte gib einen gültigen Raum-Code ein!');
|
||||||
|
// Reset bei Fehler
|
||||||
|
gameStarting = false;
|
||||||
|
if (joinBtn) {
|
||||||
|
joinBtn.disabled = false;
|
||||||
|
joinBtn.innerHTML = 'RAUM BEITRETEN';
|
||||||
|
joinBtn.style.opacity = '1';
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -391,12 +449,21 @@ function joinRoom() {
|
|||||||
localStorage.setItem('escape_team_name', teamName);
|
localStorage.setItem('escape_team_name', teamName);
|
||||||
localStorage.setItem('escape_is_host', 'false');
|
localStorage.setItem('escape_is_host', 'false');
|
||||||
|
|
||||||
// Show Lobby
|
// Show Lobby nach kurzer Verzögerung
|
||||||
|
setTimeout(() => {
|
||||||
setUIState(UIState.LOBBY);
|
setUIState(UIState.LOBBY);
|
||||||
document.getElementById('lobbyRoomCode').textContent = roomID;
|
document.getElementById('lobbyRoomCode').textContent = roomID;
|
||||||
document.getElementById('lobbyHostControls').classList.add('hidden');
|
document.getElementById('lobbyHostControls').classList.add('hidden');
|
||||||
document.getElementById('lobbyStatus').textContent = 'Warte auf Host...';
|
document.getElementById('lobbyStatus').textContent = 'Warte auf Host...';
|
||||||
|
|
||||||
|
// Reset gameStarting für Lobby
|
||||||
|
gameStarting = false;
|
||||||
|
}, 300);
|
||||||
|
|
||||||
|
// Reset gameStarting für Lobby
|
||||||
|
gameStarting = false;
|
||||||
|
}, 300);
|
||||||
|
|
||||||
// Trigger WASM game start (im Hintergrund)
|
// Trigger WASM game start (im Hintergrund)
|
||||||
if (window.startGame) {
|
if (window.startGame) {
|
||||||
console.log('🎮 Calling window.startGame with:', 'coop', playerName, roomID, teamName, false);
|
console.log('🎮 Calling window.startGame with:', 'coop', playerName, roomID, teamName, false);
|
||||||
|
|||||||
@@ -291,7 +291,7 @@
|
|||||||
<!-- WASM Execution -->
|
<!-- WASM Execution -->
|
||||||
<script>
|
<script>
|
||||||
// Cache-Busting für JavaScript-Dateien (wird beim Build aktualisiert)
|
// Cache-Busting für JavaScript-Dateien (wird beim Build aktualisiert)
|
||||||
const BUILD_VERSION = 1767639190355;
|
const BUILD_VERSION = 1767643088942;
|
||||||
document.write('<script src="wasm_exec.js?v=' + BUILD_VERSION + '"><\/script>');
|
document.write('<script src="wasm_exec.js?v=' + BUILD_VERSION + '"><\/script>');
|
||||||
document.write('<script src="game.js?v=' + BUILD_VERSION + '"><\/script>');
|
document.write('<script src="game.js?v=' + BUILD_VERSION + '"><\/script>');
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ input[type=range]{width:100%;max-width:300px}
|
|||||||
.setting-item span{color:#fff;font-size:14px}
|
.setting-item span{color:#fff;font-size:14px}
|
||||||
.loading-screen{position:absolute;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,.95);display:flex;flex-direction:column;justify-content:center;align-items:center;z-index:9999}
|
.loading-screen{position:absolute;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,.95);display:flex;flex-direction:column;justify-content:center;align-items:center;z-index:9999}
|
||||||
.spinner{border:8px solid #333;border-top:8px solid #fc0;border-radius:50%;width:60px;height:60px;animation:spin 1s linear infinite}
|
.spinner{border:8px solid #333;border-top:8px solid #fc0;border-radius:50%;width:60px;height:60px;animation:spin 1s linear infinite}
|
||||||
|
.spinner-small{display:inline-block;border:2px solid #666;border-top:2px solid #000;border-radius:50%;width:12px;height:12px;animation:spin 1s linear infinite;vertical-align:middle;margin-right:8px}
|
||||||
@keyframes spin{0%{transform:rotate(0)}100%{transform:rotate(360deg)}}
|
@keyframes spin{0%{transform:rotate(0)}100%{transform:rotate(360deg)}}
|
||||||
#mute-btn{position:fixed;top:10px;left:10px;z-index:10000;background:rgba(0,0,0,.5);border:2px solid #555;color:#fff;font-size:20px;width:40px;height:40px;border-radius:50%;cursor:pointer;padding:0;margin:0;display:flex;align-items:center;justify-content:center;box-shadow:0 0 10px rgba(0,0,0,.5)}
|
#mute-btn{position:fixed;top:10px;left:10px;z-index:10000;background:rgba(0,0,0,.5);border:2px solid #555;color:#fff;font-size:20px;width:40px;height:40px;border-radius:50%;cursor:pointer;padding:0;margin:0;display:flex;align-items:center;justify-content:center;box-shadow:0 0 10px rgba(0,0,0,.5)}
|
||||||
#mute-btn:hover{background:rgba(255,255,255,.2);border-color:#fff}
|
#mute-btn:hover{background:rgba(255,255,255,.2);border-color:#fff}
|
||||||
|
|||||||
@@ -10,13 +10,19 @@ const (
|
|||||||
|
|
||||||
// Physics (angepasst für 20 TPS statt 60 TPS)
|
// Physics (angepasst für 20 TPS statt 60 TPS)
|
||||||
// Bei 20 TPS ist jeder Tick 3x länger (50ms statt 16.67ms)
|
// Bei 20 TPS ist jeder Tick 3x länger (50ms statt 16.67ms)
|
||||||
// Geschwindigkeiten müssen mit 3 multipliziert werden
|
|
||||||
Gravity = 1.5 // war 0.5 bei 60 TPS
|
Gravity = 1.5 // war 0.5 bei 60 TPS
|
||||||
MaxFall = 45.0 // war 15.0 bei 60 TPS
|
MaxFall = 45.0 // war 15.0 bei 60 TPS
|
||||||
TileSize = 64
|
TileSize = 64
|
||||||
|
|
||||||
|
// Player Movement (bei 20 TPS)
|
||||||
|
RunSpeed = 21.0 // Basis-Scroll-Geschwindigkeit
|
||||||
|
PlayerSpeed = 33.0 // Links/Rechts Bewegung relativ zu Scroll (war 11.0 * 3)
|
||||||
|
JumpVelocity = 24.0 // Sprunghöhe (reduziert für besseres Gefühl)
|
||||||
|
FastFall = 45.0 // Schnell-Fall nach unten
|
||||||
|
WallSlideMax = 9.0 // Maximale Rutsch-Geschwindigkeit an Wand
|
||||||
|
WallClimbSpeed = 15.0 // Kletter-Geschwindigkeit
|
||||||
|
|
||||||
// Gameplay
|
// Gameplay
|
||||||
RunSpeed = 21.0 // war 7.0 bei 60 TPS (7.0 * 3)
|
|
||||||
StartTime = 5 // Sekunden Countdown
|
StartTime = 5 // Sekunden Countdown
|
||||||
TickRate = time.Millisecond * 50 // 20 TPS (war 16ms für 60 TPS)
|
TickRate = time.Millisecond * 50 // 20 TPS (war 16ms für 60 TPS)
|
||||||
|
|
||||||
|
|||||||
@@ -261,17 +261,17 @@ func (r *Room) HandleInput(input game.ClientInput) {
|
|||||||
switch input.Type {
|
switch input.Type {
|
||||||
case "JUMP":
|
case "JUMP":
|
||||||
if p.OnGround {
|
if p.OnGround {
|
||||||
p.VY = -30.0 // Reduziert für besseres Spielgefühl bei 20 TPS
|
p.VY = -config.JumpVelocity
|
||||||
p.OnGround = false
|
p.OnGround = false
|
||||||
p.DoubleJumpUsed = false // Reset double jump on ground jump
|
p.DoubleJumpUsed = false // Reset double jump on ground jump
|
||||||
} else if p.HasDoubleJump && !p.DoubleJumpUsed {
|
} else if p.HasDoubleJump && !p.DoubleJumpUsed {
|
||||||
// Double Jump in der Luft
|
// Double Jump in der Luft
|
||||||
p.VY = -30.0 // Reduziert für besseres Spielgefühl bei 20 TPS
|
p.VY = -config.JumpVelocity
|
||||||
p.DoubleJumpUsed = true
|
p.DoubleJumpUsed = true
|
||||||
log.Printf("⚡ %s verwendet Double Jump!", p.Name)
|
log.Printf("⚡ %s verwendet Double Jump!", p.Name)
|
||||||
}
|
}
|
||||||
case "DOWN":
|
case "DOWN":
|
||||||
p.VY = 45.0 // war 15.0 bei 60 TPS (15.0 * 3)
|
p.VY = config.FastFall
|
||||||
case "LEFT_DOWN":
|
case "LEFT_DOWN":
|
||||||
p.InputX = -1
|
p.InputX = -1
|
||||||
case "LEFT_UP":
|
case "LEFT_UP":
|
||||||
@@ -355,11 +355,10 @@ func (r *Room) Update() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// X Bewegung
|
// X Bewegung
|
||||||
// Symmetrische Geschwindigkeit: Links = Rechts
|
// Spieler bewegt sich relativ zum Scroll
|
||||||
// Nach rechts: CurrentSpeed + 33, Nach links: CurrentSpeed - 33
|
// Scroll-Geschwindigkeit + Links/Rechts Bewegung
|
||||||
// Verwendet r.CurrentSpeed statt config.RunSpeed für dynamische Geschwindigkeit
|
playerMovement := p.InputX * config.PlayerSpeed
|
||||||
// war 11.0 bei 60 TPS (11.0 * 3 = 33.0)
|
currentSpeed := r.CurrentSpeed + playerMovement
|
||||||
currentSpeed := r.CurrentSpeed + (p.InputX * 33.0)
|
|
||||||
nextX := p.X + currentSpeed
|
nextX := p.X + currentSpeed
|
||||||
|
|
||||||
hitX, typeX := r.CheckCollision(nextX+r.pDrawOffX+r.pHitboxOffX, p.Y+r.pDrawOffY+r.pHitboxOffY, r.pW, r.pH)
|
hitX, typeX := r.CheckCollision(nextX+r.pDrawOffX+r.pHitboxOffX, p.Y+r.pDrawOffY+r.pHitboxOffY, r.pW, r.pH)
|
||||||
@@ -408,13 +407,13 @@ func (r *Room) Update() {
|
|||||||
if p.OnWall {
|
if p.OnWall {
|
||||||
// Wandrutschen (langsame Fallgeschwindigkeit)
|
// Wandrutschen (langsame Fallgeschwindigkeit)
|
||||||
p.VY += config.Gravity * 0.3 // 30% Gravität an der Wand
|
p.VY += config.Gravity * 0.3 // 30% Gravität an der Wand
|
||||||
if p.VY > 9.0 { // war 3.0 bei 60 TPS (3.0 * 3)
|
if p.VY > config.WallSlideMax {
|
||||||
p.VY = 9.0 // Maximal 9.0 beim Rutschen
|
p.VY = config.WallSlideMax
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hochklettern wenn nach oben gedrückt (InputX in Wandrichtung)
|
// Hochklettern wenn nach oben gedrückt (InputX in Wandrichtung)
|
||||||
if p.InputX != 0 {
|
if p.InputX != 0 {
|
||||||
p.VY = -15.0 // war -5.0 bei 60 TPS (-5.0 * 3)
|
p.VY = -config.WallClimbSpeed
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Normal: Volle Gravität
|
// Normal: Volle Gravität
|
||||||
|
|||||||
Reference in New Issue
Block a user