From c70f85abe57cf6e2b4e522d4b5cf5ac1b7b06dd4 Mon Sep 17 00:00:00 2001 From: Atridad Lahiji Date: Wed, 26 Nov 2025 00:27:28 -0700 Subject: [PATCH] Added proper taggins for gravity --- internal/config/constants.go | 4 +- internal/hero/hero.go | 91 +++++++++++++++++++++++++++++------- internal/maps/plains.go | 37 ++++++++++++++- internal/screens/gameplay.go | 10 ++-- 4 files changed, 118 insertions(+), 24 deletions(-) diff --git a/internal/config/constants.go b/internal/config/constants.go index 57c29ed..4679035 100644 --- a/internal/config/constants.go +++ b/internal/config/constants.go @@ -13,10 +13,10 @@ const ( // Physics const ( Gravity = 1400.0 - JumpStrength = -480.0 + JumpStrength = -580.0 MaxFallSpeed = 900.0 GroundFriction = 0.82 - AirFriction = 0.96 + AirFriction = 0.86 ) // Gameplay diff --git a/internal/hero/hero.go b/internal/hero/hero.go index 5c24ab4..c85b713 100644 --- a/internal/hero/hero.go +++ b/internal/hero/hero.go @@ -7,6 +7,7 @@ import ( "github.com/atridad/LilGuy/internal/config" "github.com/atridad/LilGuy/internal/projectile" + "github.com/atridad/LilGuy/internal/world" ) const ( @@ -49,6 +50,14 @@ const ( DirRight ) +// Tags + +type Tag int + +const ( + TagGravity Tag = iota +) + // Hero state type Hero struct { @@ -63,6 +72,8 @@ type Hero struct { Color color.NRGBA + Tags map[Tag]bool + Stamina float64 MaxStamina float64 StaminaDrain float64 @@ -118,6 +129,7 @@ func New(cfg Config) *Hero { Radius: cfg.Radius, Speed: cfg.Speed, Color: cfg.Color, + Tags: map[Tag]bool{TagGravity: true}, Stamina: cfg.MaxStamina, MaxStamina: cfg.MaxStamina, StaminaDrain: cfg.StaminaDrain, @@ -136,42 +148,69 @@ func New(cfg Config) *Hero { } } -func (h *Hero) Update(input Input, dt float64, bounds Bounds) { +func (h *Hero) Update(input Input, dt float64, bounds Bounds, w *world.World) { if dt > 0.1 { dt = 0.1 } - h.updateMovement(input, dt, bounds) + h.updateMovement(input, dt, bounds, w) h.updateStamina(input, dt) h.updateAnimation(dt) } // Movement and physics -func (h *Hero) updateMovement(input Input, dt float64, bounds Bounds) { - // apply gravity - h.VelocityY += config.Gravity * dt +func (h *Hero) updateMovement(input Input, dt float64, bounds Bounds, w *world.World) { + if h.HasTag(TagGravity) { + h.VelocityY += config.Gravity * dt + } if h.VelocityY > config.MaxFallSpeed { h.VelocityY = config.MaxFallSpeed } newY := h.Y + h.VelocityY*dt - wasGrounded := h.isGrounded - if newY >= bounds.Ground { - h.Y = bounds.Ground - h.VelocityY = 0 - h.isGrounded = true - } else { - h.Y = newY - h.isGrounded = false + h.isGrounded = false + + if w != nil && h.VelocityY >= 0 { + feetX := h.X + var landedSurface *world.Surface + + for _, s := range w.Surfaces { + if !s.IsWalkable() { + continue + } + + if feetX >= s.X && feetX <= s.X+s.Width { + if h.Y <= s.Y && newY >= s.Y { + if landedSurface == nil || s.Y < landedSurface.Y { + landedSurface = s + } + } + } + } + + if landedSurface != nil { + newY = landedSurface.Y + h.VelocityY = 0 + h.isGrounded = true + } } - if input.Jump && (h.isGrounded || (!wasGrounded && h.isGrounded)) { + if !h.isGrounded { + if newY >= bounds.Ground { + newY = bounds.Ground + h.VelocityY = 0 + h.isGrounded = true + } + } + + h.Y = newY + + if input.Jump && h.isGrounded { h.VelocityY = config.JumpStrength h.isGrounded = false } - // horizontal input targetVelocityX := 0.0 if input.Left { targetVelocityX -= h.Speed @@ -184,7 +223,6 @@ func (h *Hero) updateMovement(input Input, dt float64, bounds Bounds) { h.isMoving = targetVelocityX != 0 - // sprinting h.isSprinting = input.Sprint && h.canSprint && h.Stamina > 0 && h.isMoving if h.isSprinting { targetVelocityX *= config.SprintSpeedMultiplier @@ -329,6 +367,27 @@ func (h *Hero) getCurrentSprite() *ebiten.Image { return getKnightSprite(h.direction, h.isMoving, h.animFrame) } +func (h *Hero) AddTag(tag Tag) { + if h.Tags == nil { + h.Tags = make(map[Tag]bool) + } + h.Tags[tag] = true +} + +func (h *Hero) RemoveTag(tag Tag) { + if h.Tags == nil { + return + } + delete(h.Tags, tag) +} + +func (h *Hero) HasTag(tag Tag) bool { + if h.Tags == nil { + return false + } + return h.Tags[tag] +} + func (h *Hero) GetDirection() Direction { return h.direction } diff --git a/internal/maps/plains.go b/internal/maps/plains.go index a3f0a14..904d390 100644 --- a/internal/maps/plains.go +++ b/internal/maps/plains.go @@ -13,13 +13,48 @@ func CreatePlains(screenWidth, screenHeight float64) *Map { m.BackgroundColor = color.NRGBA{R: 135, G: 206, B: 235, A: 255} // ground surface + groundColor := color.NRGBA{R: 34, G: 139, B: 34, A: 255} m.World.AddSurface(&world.Surface{ X: 0, Y: screenHeight - config.GroundHeight, Width: screenWidth, Height: config.GroundHeight, Tag: world.TagGround, - Color: color.NRGBA{R: 34, G: 139, B: 34, A: 255}, + Color: groundColor, + }) + + // Platforms + // Use ground color by default as requested + platformColor := groundColor + + // Platform 1: Low left + m.World.AddSurface(&world.Surface{ + X: 100, + Y: screenHeight - 120, + Width: 150, + Height: 20, + Tag: world.TagPlatform, + Color: platformColor, + }) + + // Platform 2: Mid center + m.World.AddSurface(&world.Surface{ + X: 350, + Y: screenHeight - 200, + Width: 200, + Height: 20, + Tag: world.TagPlatform, + Color: platformColor, + }) + + // Platform 3: High right + m.World.AddSurface(&world.Surface{ + X: 650, + Y: screenHeight - 280, + Width: 150, + Height: 20, + Tag: world.TagPlatform, + Color: platformColor, }) // left portal to desert diff --git a/internal/screens/gameplay.go b/internal/screens/gameplay.go index 435e8a4..f4a8426 100644 --- a/internal/screens/gameplay.go +++ b/internal/screens/gameplay.go @@ -52,7 +52,7 @@ type GameplayScreen struct { func NewGameplayScreen(screenWidth, screenHeight int, mapManager *maps.Manager, fpsEnabled *bool, portalVisibility *bool) *GameplayScreen { cfg := config.Default() - + // Ensure we have a current map if mapManager.CurrentMap() == nil { // Fallback or error later @@ -119,7 +119,7 @@ func (g *GameplayScreen) Update(input GameplayInput, delta time.Duration) { Right: input.Right, Jump: input.Jump, Sprint: input.Sprint, - }, dt, g.bounds) + }, dt, g.bounds, g.world) if input.Shoot { direction := 1.0 @@ -224,7 +224,7 @@ func (g *GameplayScreen) trackFPS(delta time.Duration) { // Rendering func (g *GameplayScreen) Draw(screen *ebiten.Image) { cfg := config.Default() - + currentMap := g.mapManager.CurrentMap() if currentMap != nil { currentMap.Draw(screen) @@ -381,12 +381,12 @@ func (g *GameplayScreen) LoadState(state *save.GameState) { screenHeight := int(g.bounds.Height) g.mapManager.Reset() - + mapID := state.CurrentMap if mapID == "" { mapID = "plains" } - + if err := g.mapManager.SetCurrentMap(mapID); err != nil { g.mapManager.SetCurrentMap("plains") }