Private
Public Access
1
0

add new Gameplay func.
All checks were successful
Dynamic Branch Deploy / build-and-deploy (push) Successful in 1m59s

This commit is contained in:
Sebastian Unterschütz
2025-11-25 20:05:25 +01:00
parent 36a4847381
commit ddc861ceac
8 changed files with 80 additions and 19 deletions

View File

@@ -39,21 +39,21 @@ func initGameConfig() {
defaultConfig = GameConfig{
Obstacles: []ObstacleDef{
// --- HINDERNISSE ---
{ID: "desk", Type: "obstacle", Width: 40, Height: 30, Color: "#8B4513", Image: "desk.png"},
{ID: "teacher", Type: "teacher", Width: 30, Height: 60, Color: "#000080", Image: "teacher.png", CanTalk: true, SpeechLines: []string{"Halt!", "Handy weg!"}},
{ID: "trashcan", Type: "obstacle", Width: 25, Height: 35, Color: "#555", Image: "trash.png"},
{ID: "eraser", Type: "obstacle", Width: 30, Height: 20, Color: "#fff", Image: "eraser.png", YOffset: 45.0},
{ID: "desk", Type: "obstacle", Width: 40, Height: 30, Color: "#8B4513", Image: "desk1.png"},
{ID: "teacher", Type: "teacher", Width: 30, Height: 60, Color: "#000080", Image: "teacher1.png", CanTalk: true, SpeechLines: []string{"Halt!", "Handy weg!"}},
{ID: "trashcan", Type: "obstacle", Width: 25, Height: 35, Color: "#555", Image: "trash1.png"},
{ID: "eraser", Type: "obstacle", Width: 30, Height: 20, Color: "#fff", Image: "eraser1.png", YOffset: 45.0},
// --- BOSS OBJEKTE (Kommen häufiger im Bosskampf) ---
{ID: "principal", Type: "teacher", Width: 40, Height: 70, Color: "#000", Image: "principal.png", CanTalk: true, SpeechLines: []string{"EXMATRIKULATION!"}},
{ID: "principal", Type: "teacher", Width: 40, Height: 70, Color: "#000", Image: "principal1.png", CanTalk: true, SpeechLines: []string{"EXMATRIKULATION!"}},
// --- COINS ---
{ID: "coin", Type: "coin", Width: 20, Height: 20, Color: "gold", Image: "coin.png", YOffset: 20.0},
{ID: "coin", Type: "coin", Width: 20, Height: 20, Color: "gold", Image: "coin1.png", YOffset: 20.0},
// --- POWERUPS ---
{ID: "p_god", Type: "powerup", Width: 30, Height: 30, Color: "cyan", Image: "powerup_god.png", YOffset: 20.0}, // Godmode
{ID: "p_bat", Type: "powerup", Width: 30, Height: 30, Color: "red", Image: "powerup_bat.png", YOffset: 20.0}, // Schläger
{ID: "p_boot", Type: "powerup", Width: 30, Height: 30, Color: "lime", Image: "powerup_boot.png", YOffset: 20.0}, // Boots
{ID: "p_god", Type: "powerup", Width: 30, Height: 30, Color: "cyan", Image: "powerup_god1.png", YOffset: 20.0}, // Godmode
{ID: "p_bat", Type: "powerup", Width: 30, Height: 30, Color: "red", Image: "powerup_bat1.png", YOffset: 20.0}, // Schläger
{ID: "p_boot", Type: "powerup", Width: 30, Height: 30, Color: "lime", Image: "powerup_boot1.png", YOffset: 20.0}, // Boots
},
// Mehrere Hintergründe für Level-Wechsel
Backgrounds: []string{"gym-background.jpg", "school-background.jpg", "school2-background.jpg"},

View File

@@ -3,10 +3,13 @@ package main
import (
"encoding/json"
"fmt"
"log"
"math"
"strconv"
)
func simulateChunk(sessionID string, inputs []Input, totalTicks int, vals map[string]string) (bool, int, []ActiveObstacle) {
posY := parseOr(vals["pos_y"], PlayerYBase)
velY := parseOr(vals["vel_y"], 0.0)
score := int(parseOr(vals["score"], 0))
@@ -16,6 +19,9 @@ func simulateChunk(sessionID string, inputs []Input, totalTicks int, vals map[st
hasBat := vals["p_has_bat"] == "1"
bootTicks := int(parseOr(vals["p_boot_ticks"], 0))
lastJumpDist := parseOr(vals["ac_last_dist"], 0.0)
suspicionScore := int(parseOr(vals["ac_suspicion"], 0))
rng := NewRNG(rngStateVal)
var obstacles []ActiveObstacle
@@ -25,9 +31,22 @@ func simulateChunk(sessionID string, inputs []Input, totalTicks int, vals map[st
obstacles = []ActiveObstacle{}
}
jumpCount := 0
for _, inp := range inputs {
if inp.Act == "JUMP" {
jumpCount++
}
}
if jumpCount > 10 {
log.Printf("[%s] 🤖 [ANTI-CHEAT] SPAM DETECTED: %d mal JUMP!", sessionID, jumpCount)
return true, score, obstacles
}
playerDead := false
for i := 0; i < totalTicks; i++ {
currentSpeed := BaseSpeed + (float64(score)/500.0)*0.5
if currentSpeed > 12.0 {
currentSpeed = 12.0
@@ -53,6 +72,7 @@ func simulateChunk(sessionID string, inputs []Input, totalTicks int, vals map[st
}
isGrounded := posY >= PlayerYBase-1.0
currentHeight := PlayerHeight
if isCrouching {
currentHeight = PlayerHeight / 2
@@ -63,10 +83,32 @@ func simulateChunk(sessionID string, inputs []Input, totalTicks int, vals map[st
if didJump && isGrounded && !isCrouching {
velY = currentJumpPower
nextObsDist := -1.0
for _, o := range obstacles {
if o.X > 50.0 {
nextObsDist = o.X - 50.0
break
}
}
if nextObsDist > 0 {
diff := math.Abs(nextObsDist - lastJumpDist)
if diff < 0.5 {
suspicionScore++
log.Printf("[%s] ⚠️ [ANTI-CHEAT] Verdächtiger Sprung! Diff: %.4f | Suspicion: %d", sessionID, diff, suspicionScore)
} else {
if suspicionScore > 0 {
suspicionScore--
}
}
lastJumpDist = nextObsDist
}
}
velY += Gravity
posY += velY
if posY > PlayerYBase {
posY = PlayerYBase
velY = 0
@@ -87,43 +129,52 @@ func simulateChunk(sessionID string, inputs []Input, totalTicks int, vals map[st
continue
}
paddingX := 10.0
paddingY_Top := 10.0
paddingX := 5.0
paddingY_Top := 5.0
if obs.Type == "teacher" {
paddingY_Top = 25.0
paddingY_Top = 5.0
}
pLeft, pRight := 50.0+paddingX, 50.0+30.0-paddingX
pTop, pBottom := hitboxY+paddingY_Top, hitboxY+currentHeight-5.0
paddingY_Bottom := 5.0
pLeft, pRight := 50.0+paddingX, 50.0+60.0-paddingX
pTop, pBottom := hitboxY+paddingY_Top, hitboxY+currentHeight-paddingY_Bottom
oLeft, oRight := obs.X+paddingX, obs.X+obs.Width-paddingX
oTop, oBottom := obs.Y+paddingY_Top, obs.Y+obs.Height-5.0
oTop, oBottom := obs.Y+paddingY_Top, obs.Y+obs.Height-paddingY_Bottom
isCollision := pRight > oLeft && pLeft < oRight && pBottom > oTop && pTop < oBottom
if pRight > oLeft && pLeft < oRight && pBottom > oTop && pTop < oBottom {
if isCollision {
if obs.Type == "coin" {
score += 2000
continue
} else if obs.Type == "powerup" {
if obs.ID == "p_god" {
godLives = 3
log.Printf("[%s] 🛡️ POWERUP: Godmode collected", sessionID)
}
if obs.ID == "p_bat" {
hasBat = true
log.Printf("[%s] ⚾ POWERUP: Bat collected", sessionID)
}
if obs.ID == "p_boot" {
bootTicks = 600
log.Printf("[%s] 👟 POWERUP: Boots collected", sessionID)
}
continue
} else {
if hasBat && obs.Type == "teacher" {
hasBat = false
log.Printf("[%s] ⚾ BAT SMASH! Lehrer %s zerstört.", sessionID, obs.ID)
continue
}
if godLives > 0 {
godLives--
log.Printf("[%s] 🛡️ GODMODE schützt! (%d lives left)", sessionID, godLives)
continue
}
log.Printf("[%s] 💀 [DEATH] PlayerY: %.1f | Obs: %s @ %.1f", sessionID, hitboxY, obs.ID, obs.X)
playerDead = true
}
}
@@ -136,7 +187,8 @@ func simulateChunk(sessionID string, inputs []Input, totalTicks int, vals map[st
obstacles = nextObstacles
if rightmostX < GameWidth-10.0 {
gap := float64(int(400.0 + rng.NextRange(0, 500)))
rawGap := 400.0 + rng.NextRange(0, 500)
gap := float64(int(rawGap))
spawnX := rightmostX + gap
if spawnX < GameWidth {
spawnX = GameWidth
@@ -195,6 +247,11 @@ func simulateChunk(sessionID string, inputs []Input, totalTicks int, vals map[st
}
}
if suspicionScore > 10 {
log.Printf("[%s] 🤖 [ANTI-CHEAT] BOT BANNED: %d suspicion", sessionID, suspicionScore)
playerDead = true
}
obsJson, _ := json.Marshal(obstacles)
batStr := "0"
if hasBat {
@@ -210,6 +267,8 @@ func simulateChunk(sessionID string, inputs []Input, totalTicks int, vals map[st
"p_god_lives": godLives,
"p_has_bat": batStr,
"p_boot_ticks": bootTicks,
"ac_last_dist": fmt.Sprintf("%f", lastJumpDist),
"ac_suspicion": suspicionScore,
})
return playerDead, score, obstacles

BIN
static/assets/coin.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 71 KiB

BIN
static/assets/desk.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 107 KiB

BIN
static/assets/eraser.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

BIN
static/coin.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 71 KiB

View File

@@ -25,7 +25,7 @@ function updateGameLogic() {
if (player.y + originalHeight >= GROUND_Y) {
player.y = GROUND_Y - originalHeight; player.vy = 0; player.grounded = true;
} else { player.grounded = false; }
// 3. Obstacles
let nextObstacles = [];

View File

@@ -109,10 +109,12 @@ function drawGame() {
if(bootTicks > 0) statusText += `👟 ${(bootTicks/60).toFixed(1)}s`;
// Drift Anzeige
/*
if (obstacles.length > 0 && serverObstacles.length > 0) {
const drift = Math.abs(obstacles[0].x - serverObstacles[0].x).toFixed(1);
statusText += ` | Drift: ${drift}px`;
}
*/
ctx.fillText(statusText, 10, 40);
}