doodle/pkg/player_physics.go

139 lines
3.9 KiB
Go
Raw Permalink Normal View History

package doodle
// Subset of the PlayScene that is responsible for movement of the player character.
import (
2022-09-24 22:17:25 +00:00
"git.kirsle.net/SketchyMaze/doodle/pkg/balance"
"git.kirsle.net/SketchyMaze/doodle/pkg/keybind"
"git.kirsle.net/SketchyMaze/doodle/pkg/physics"
"git.kirsle.net/SketchyMaze/doodle/pkg/shmem"
"git.kirsle.net/go/render/event"
)
// movePlayer updates the player's X,Y coordinate based on key pressed.
func (s *PlayScene) movePlayer(ev *event.State) {
var (
playerSpeed = float64(balance.PlayerMaxVelocity)
velocity = s.Player.Velocity()
direction float64
jumping bool
phys = s.playerPhysics
// holdingJump bool // holding down the jump button vs. tapping it
)
if s.slippery {
phys = s.slipperyPhysics
}
// Antigravity: player can move anywhere with arrow keys.
if s.antigravity || !s.Player.HasGravity() {
velocity.X = 0
velocity.Y = 0
// Shift to slow your roll to 1 pixel per tick.
if keybind.Shift(ev) {
playerSpeed = 1
}
if keybind.Left(ev) {
velocity.X = -playerSpeed
} else if keybind.Right(ev) {
velocity.X = playerSpeed
}
if keybind.Up(ev) {
velocity.Y = -playerSpeed
} else if keybind.Down(ev) {
velocity.Y = playerSpeed
}
} else {
// Moving left or right.
if keybind.Left(ev) {
direction = -1
} else if keybind.Right(ev) {
direction = 1
}
// Up button to signal they want to jump.
if keybind.Up(ev) {
if s.Player.IsWet() {
// If they are holding Up put a cooldown in how fast they can swim
// to the surface. Tapping the Jump button allows a faster ascent.
if shmem.Tick > s.jumpCooldownUntil {
s.jumpCooldownUntil = shmem.Tick + balance.SwimJumpCooldown
velocity.Y = balance.SwimJumpVelocity
}
2024-02-07 04:56:07 +00:00
} else if s.Player.Grounded() || s.Player.IsCoyoteTime(true) {
velocity.Y = balance.PlayerJumpVelocity
}
} else {
s.jumpCooldownUntil = 0
if velocity.Y < 0 {
velocity.Y = 0
}
}
// Moving left or right? Interpolate their velocity by acceleration.
if direction != 0 {
if s.playerLastDirection != direction {
velocity.X = 0
}
// TODO: fast turn-around if they change directions so they don't
// slip and slide while their velocity updates.
velocity.X = physics.Lerp(
velocity.X,
direction*phys.MaxSpeed.X,
phys.Acceleration,
)
} else {
// Slow them back to zero using friction.
velocity.X = physics.Lerp(
velocity.X,
0,
phys.Friction,
)
}
// Moving upwards (jumping): give them full acceleration upwards.
if jumping {
velocity.Y = -playerSpeed
}
// While in the air, count down their jump counter; when zero they
// cannot jump again until they touch ground.
if !s.Player.Grounded() {
s.playerJumpCounter--
}
}
s.playerLastDirection = direction
// Move the player unless frozen.
// TODO: if Y=0 then gravity fails, but not doing this allows the
// player to jump while frozen. Not a HUGE deal right now as only Warp Doors
// freeze the player currently but do address this later.
if s.Player.IsFrozen() {
velocity.X = 0
}
s.Player.SetVelocity(velocity)
// If the "Use" key is pressed, set an actor flag on the player.
s.Player.SetUsing(keybind.Use(ev))
// Camera behaviors: Anvils can take the camera's focus while they're falling
// but player inputs will take control back to the player. Most anvils will fall
// a couple pixels upon level load - prevent them taking the camera's focus for
// the first few frames of gameplay.
if s.mustFollowPlayerUntil == 0 {
s.mustFollowPlayerUntil = shmem.Tick + balance.FollowPlayerFirstTicks
}
// If we insist that the canvas follow the player doodad.
Update savegame format, Allow out-of-bounds camera Updates the savegame.json file format: * Levels now have a UUID value assigned at first save. * The savegame.json will now track level completion/score based on UUID, making it robust to filename changes in either levels or levelpacks. * The savegame file is auto-migrated on startup - for any levels not found or have no UUID, no change is made, it's backwards compatible. * Level Properties window adds an "Advanced" tab to show/re-roll UUID. New JavaScript API for doodad scripts: * `Actors.CameraFollowPlayer()` tells the camera to return focus to the player character. Useful for "cutscene" doodads that freeze the player, call `Self.CameraFollowMe()` and do a thing before unfreezing and sending the camera back to the player. (Or it will follow them at their next directional input control). * `Self.MoveBy(Point(x, y int))` to move the current actor a bit. New option for the `doodad` command-line tool: * `doodad resave <.level or .doodad>` will load and re-save a drawing, to migrate it to the newest file format versions. Small tweaks: * On bounded levels, allow the camera to still follow the player if the player finds themselves WELL far out of bounds (40 pixels margin). So on bounded levels you can create "interior rooms" out-of-bounds to Warp Door into. * New wallpaper: "Atmosphere" has a black starscape pattern that fades into a solid blue atmosphere. * Camera strictly follows the player the first 20 ticks, not 60 of level start * If player is frozen, directional inputs do not take the camera focus back.
2023-03-08 05:55:10 +00:00
// Also any directional key will focus the player unless the player is frozen.
if shmem.Tick < s.mustFollowPlayerUntil || (!s.Player.IsFrozen() && (keybind.Up(ev) || keybind.Left(ev) || keybind.Right(ev) || keybind.Use(ev))) {
s.drawing.FollowActor = s.Player.ID()
}
s.scripting.To(s.Player.ID()).Events.RunKeypress(keybind.FromEvent(ev))
}