add new Gameplay func.
All checks were successful
Dynamic Branch Deploy / build-and-deploy (push) Successful in 1m59s
All checks were successful
Dynamic Branch Deploy / build-and-deploy (push) Successful in 1m59s
This commit is contained in:
18
config.go
18
config.go
@@ -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"},
|
||||
|
||||
@@ -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
BIN
static/assets/coin.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 71 KiB |
BIN
static/assets/desk.png
Normal file
BIN
static/assets/desk.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 107 KiB |
BIN
static/assets/eraser.png
Normal file
BIN
static/assets/eraser.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 70 KiB |
BIN
static/coin.png
Normal file
BIN
static/coin.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 71 KiB |
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user