Add dash ability

This commit is contained in:
Trevor Slocum 2021-12-12 17:56:04 -08:00
parent 639b0b8ab1
commit a1abf7eab5
9 changed files with 554 additions and 515 deletions

File diff suppressed because it is too large Load Diff

View File

@ -22,6 +22,7 @@ func parseFlags() {
flag.BoolVar(&fullscreen, "fullscreen", false, "run in fullscreen mode")
flag.StringVar(&spawn, "spawn", "", "spawn X,Y position")
flag.BoolVar(&world.World.CanDoubleJump, "doublejump", false, "start with double jump ability")
flag.BoolVar(&world.World.CanDash, "dash", false, "start with dash ability")
flag.BoolVar(&world.World.CanLevitate, "levitate", false, "start with levitate ability")
flag.IntVar(&world.World.Debug, "debug", 0, "print debug information")
flag.Parse()

6
go.mod
View File

@ -3,7 +3,7 @@ module code.rocketnine.space/tslocum/monovania
go 1.17
require (
code.rocketnine.space/tslocum/gohan v0.0.0-20211210034951-3c7785e5e57f
code.rocketnine.space/tslocum/gohan v0.0.0-20211212050415-e08cfe7970d8
github.com/fogleman/ease v0.0.0-20170301025033-8da417bf1776
github.com/hajimehoshi/ebiten/v2 v2.2.3
github.com/lafriks/go-tiled v0.5.0
@ -15,8 +15,8 @@ require (
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20211204153444-caad923f49f4 // indirect
github.com/hajimehoshi/oto/v2 v2.1.0-alpha.4 // indirect
github.com/jezek/xgb v0.0.0-20210312150743-0e0f116e1240 // indirect
golang.org/x/exp v0.0.0-20211209182145-6e94b45d164d // indirect
golang.org/x/exp v0.0.0-20211210185655-e05463a05a18 // indirect
golang.org/x/mobile v0.0.0-20211207041440-4e6c2922fdee // indirect
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect
golang.org/x/sys v0.0.0-20211209171907-798191bca915 // indirect
golang.org/x/sys v0.0.0-20211210111614-af8b64212486 // indirect
)

12
go.sum
View File

@ -1,5 +1,5 @@
code.rocketnine.space/tslocum/gohan v0.0.0-20211210034951-3c7785e5e57f h1:stxIGII7DonP7xIsUaEthEj5j3JNnMzVek5fK9hRAMU=
code.rocketnine.space/tslocum/gohan v0.0.0-20211210034951-3c7785e5e57f/go.mod h1:nOvFBFvFPl5sDtkMy2Fn/7QZcWq5RE98/mK+INLqIWg=
code.rocketnine.space/tslocum/gohan v0.0.0-20211212050415-e08cfe7970d8 h1:tsIId//EUkKtk0v2wNEv6qUmS2yDnOTd7cmXhQemDyE=
code.rocketnine.space/tslocum/gohan v0.0.0-20211212050415-e08cfe7970d8/go.mod h1:nOvFBFvFPl5sDtkMy2Fn/7QZcWq5RE98/mK+INLqIWg=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@ -38,8 +38,8 @@ golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8U
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190731235908-ec7cb31e5a56/go.mod h1:JhuoJpWY28nO4Vef9tZUw9qufEGTyX1+7lmHxV5q5G4=
golang.org/x/exp v0.0.0-20211209182145-6e94b45d164d h1:kyDnjigapVz/aaGinVfqN3EK7SGZrOCNjcYuf5to0KE=
golang.org/x/exp v0.0.0-20211209182145-6e94b45d164d/go.mod h1:b9TAUYHmRtqA6klRHApnXMnj+OyLce4yF5cZCUbk2ps=
golang.org/x/exp v0.0.0-20211210185655-e05463a05a18 h1:5GT90y+j5D8fWZ22z0SH3iQ8ZeTWX8quGjetD8Symgg=
golang.org/x/exp v0.0.0-20211210185655-e05463a05a18/go.mod h1:b9TAUYHmRtqA6klRHApnXMnj+OyLce4yF5cZCUbk2ps=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190703141733-d6a02ce849c9/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
@ -72,8 +72,8 @@ golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210917161153-d61c044b1678/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211209171907-798191bca915 h1:P+8mCzuEpyszAT6T42q0sxU+eveBAF/cJ2Kp0x6/8+0=
golang.org/x/sys v0.0.0-20211209171907-798191bca915/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211210111614-af8b64212486 h1:5hpz5aRr+W1erYCL5JRhSUBJRph7l9XkNveoExlrKYk=
golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=

View File

@ -20,7 +20,7 @@ func main() {
ebiten.SetRunnableOnUnfocused(true) // Note - this currently does nothing in ebiten
ebiten.SetWindowClosingHandled(true)
ebiten.SetFPSMode(ebiten.FPSModeVsyncOn)
ebiten.SetCursorShape(ebiten.CursorShapeCrosshair)
ebiten.SetCursorMode(ebiten.CursorModeHidden)
g, err := game.NewGame()
if err != nil {

View File

@ -63,12 +63,28 @@ func (s *playerMoveSystem) Update(ctx *gohan.Context) error {
maxSpeed := 0.5
maxLevitateSpeed := 1.0
maxYSpeed := 0.5
const jumpVelocity = -1
const jumpVelocity = -1.02
const dashVelocity = 5
velocity := component.Velocity(ctx)
var walkKeyPressed bool
// Jump.
if inpututil.IsKeyJustPressed(ebiten.KeyJ) {
if ((s.movement.OnGround != -1 || s.movement.OnLadder != -1) && world.World.Jumps == 0) || (world.World.CanDoubleJump && world.World.Jumps < 2) {
velocity.Y = jumpVelocity
s.movement.Jumping = true
s.movement.LastJump = time.Now()
world.World.Jumps++
} else if world.World.CanLevitate && world.World.Jumps == 2 {
world.World.Levitating = true
}
}
if s.movement.Jumping && (!ebiten.IsKeyPressed(ebiten.KeyJ) || time.Since(s.movement.LastJump) >= 200*time.Millisecond) {
s.movement.Jumping = false
}
if s.movement.OnGround != -1 && ebiten.IsKeyPressed(ebiten.KeyS) && !world.World.NoClip {
if ebiten.IsKeyPressed(ebiten.KeyA) {
s.lastWalkDirL = true
@ -176,6 +192,24 @@ func (s *playerMoveSystem) Update(ctx *gohan.Context) error {
s.lastWalkDirL = false
}
}
// Dash.
if inpututil.IsKeyJustPressed(ebiten.KeyK) && world.World.CanDash && world.World.Dashes == 0 && s.movement.OnGround == -1 && s.movement.OnLadder == -1 {
if s.lastWalkDirL {
velocity.X = -dashVelocity
} else {
velocity.X = dashVelocity
}
velocity.Y = 0
s.movement.Dashing = true
s.movement.LastDash = time.Now()
world.World.Dashes = 1
}
if s.movement.Dashing && (!ebiten.IsKeyPressed(ebiten.KeyK) || time.Since(s.movement.LastDash) >= 250*time.Millisecond) {
velocity.X = 0
s.movement.Dashing = false
}
if s.movement.OnLadder != -1 || world.World.NoClip {
setLadderFrames := func() {
if world.World.NoClip {
@ -216,26 +250,6 @@ func (s *playerMoveSystem) Update(ctx *gohan.Context) error {
setLadderFrames()
walkKeyPressed = true
}
} else {
// Jump.
if inpututil.IsKeyJustPressed(ebiten.KeyW) {
if (s.movement.OnGround != -1 && world.World.Jumps == 0) || (world.World.CanDoubleJump && world.World.Jumps < 2) {
velocity.Y = jumpVelocity
s.movement.Jumping = true
s.movement.LastJump = time.Now()
world.World.Jumps++
// Allow one double jump when falling.
if world.World.Jumps == 1 && s.movement.OnGround == -1 {
world.World.Jumps = 2
}
} else if world.World.CanLevitate && world.World.Jumps == 2 {
world.World.Levitating = true
}
}
if s.movement.Jumping && (!ebiten.IsKeyPressed(ebiten.KeyW) || time.Since(s.movement.LastJump) >= 200*time.Millisecond) {
s.movement.Jumping = false
}
}
if world.World.Levitating {
@ -248,17 +262,17 @@ func (s *playerMoveSystem) Update(ctx *gohan.Context) error {
}
}
if !walkKeyPressed || (s.movement.OnGround == -1 && s.movement.OnLadder == -1) || world.World.NoClip {
if !walkKeyPressed || s.movement.Jumping || (s.movement.OnGround == -1 && s.movement.OnLadder == -1) || world.World.NoClip {
sprite := component.Sprite(ctx)
sprite.NumFrames = 0
if s.lastWalkDirL {
if (s.movement.OnGround == -1 && s.movement.OnLadder == -1) || world.World.NoClip {
if (s.movement.OnGround == -1 && s.movement.OnLadder == -1) || s.movement.Jumping || world.World.NoClip {
sprite.Image = asset.PlayerSS.WalkL2
} else {
sprite.Image = asset.PlayerSS.IdleL
}
} else {
if (s.movement.OnGround == -1 && s.movement.OnLadder == -1) || world.World.NoClip {
if (s.movement.OnGround == -1 && s.movement.OnLadder == -1) || s.movement.Jumping || world.World.NoClip {
sprite.Image = asset.PlayerSS.WalkR2
} else {
sprite.Image = asset.PlayerSS.IdleR

View File

@ -21,6 +21,9 @@ type MovementSystem struct {
Jumping bool
LastJump time.Time
Dashing bool
LastDash time.Time
collisionRects []image.Rectangle
ladderRects []image.Rectangle
@ -227,9 +230,12 @@ func (s *MovementSystem) checkFire(r image.Rectangle) {
func (s *MovementSystem) checkTriggers(r image.Rectangle) {
for i, triggerRect := range world.World.TriggerRects {
if r.Overlaps(triggerRect) {
if world.World.TriggerNames[i] == "DOUBLEJUMP" {
switch world.World.TriggerNames[i] {
case "DOUBLEJUMP":
world.World.CanDoubleJump = true
} else {
case "DASH":
world.World.CanDash = true
default:
panic("unknown trigger " + world.World.TriggerNames[i])
}
@ -265,12 +271,6 @@ func (s *MovementSystem) Update(ctx *gohan.Context) error {
for i, rect := range s.ladderRects {
if playerRect.Overlaps(rect) {
onLadder = i
// Grab the ladder when jumping on to it.
if onLadder != lastOnLadder && !world.World.NoClip {
velocity.Y = 0
//velocity.X /= 2
}
break
}
}
@ -283,17 +283,19 @@ func (s *MovementSystem) Update(ctx *gohan.Context) error {
const maxGravity = 9
const gravityAccel = 0.04
if !bullet {
if s.OnLadder != -1 || world.World.Levitating || world.World.NoClip {
if world.World.Levitating || world.World.NoClip {
velocity.X *= decel
velocity.Y *= decel
} else if s.OnLadder != -1 { // TODO incorrect
velocity.X *= decel
velocity.Y *= ladderDecel
} else if s.Dashing {
velocity.X *= 0.96
} else if velocity.Y < maxGravity {
velocity.X *= decel
if !s.Jumping {
velocity.Y += gravityAccel
if s.OnLadder == -1 {
velocity.Y += gravityAccel
} else {
velocity.Y *= decel
}
}
}
}
@ -349,9 +351,15 @@ func (s *MovementSystem) Update(ctx *gohan.Context) error {
velocity.X, velocity.Y = 0, 0
}
s.OnGround = collideG
// Reset jump counter.
if s.OnGround != -1 && world.World.Jumps != 0 && time.Since(s.LastJump) >= 50*time.Millisecond {
world.World.Jumps = 0
if s.OnGround != -1 || s.OnLadder != -1 {
// Reset jump counter.
if world.World.Jumps != 0 && time.Since(s.LastJump) >= 50*time.Millisecond {
world.World.Jumps = 0
}
// Reset dash counter.
if world.World.Dashes != 0 {
world.World.Dashes = 0
}
}
// Update debug rects.

View File

@ -67,14 +67,14 @@ func (s *RenderSystem) renderSprite(x float64, y float64, offsetx float64, offse
// Skip drawing off-screen tiles.
drawX, drawY := s.levelCoordinatesToScreen(x, y)
padding := float64(TileWidth) * 2
const padding = TileWidth * 4
width, height := float64(TileWidth), float64(TileWidth)
left := drawX
right := drawX + width
top := drawY
bottom := drawY + height
if (left < -padding || left > float64(s.ScreenW)+padding) && (top < -padding || top > float64(s.ScreenH)+padding) &&
(right < -padding || right > float64(s.ScreenW)+padding) && (bottom < -padding || bottom > float64(s.ScreenH)+padding) {
if (left < -padding || left > float64(s.ScreenW)+padding) || (top < -padding || top > float64(s.ScreenH)+padding) ||
(right < -padding || right > float64(s.ScreenW)+padding) || (bottom < -padding || bottom > float64(s.ScreenH)+padding) {
return 0
}

View File

@ -49,9 +49,11 @@ type GameWorld struct {
// Abilities
CanDoubleJump bool
CanDash bool
CanLevitate bool
Jumps int
Dashes int
Levitating bool
TriggerRects []image.Rectangle