doctorlectro/entity/player.go

121 lines
2.8 KiB
Go
Raw Normal View History

2022-06-17 21:17:03 +00:00
package entity
import (
"time"
2022-06-18 21:08:53 +00:00
"github.com/hajimehoshi/ebiten/v2"
"github.com/jakecoffman/cp"
"code.rocketnine.space/tslocum/doctorlectro/world"
2022-06-17 21:17:03 +00:00
"code.rocketnine.space/tslocum/doctorlectro/asset"
"code.rocketnine.space/tslocum/doctorlectro/component"
"code.rocketnine.space/tslocum/gohan"
)
2022-06-18 21:08:53 +00:00
const (
playerVelocity = 40.0
playerGroundAccelTime = 0.1
playerGroundAccel = playerVelocity / playerGroundAccelTime
playerAirAccelTime = 0.25
playerAirAccel = playerVelocity / playerAirAccelTime
fallVelocity = 900.0
)
2022-06-17 21:17:03 +00:00
func NewPlayer() gohan.Entity {
2022-06-18 21:08:53 +00:00
playerBody := world.Space.AddBody(cp.NewBody(4, cp.INFINITY))
playerBody.SetPosition(cp.Vector{0, 0})
playerBody.SetVelocityUpdateFunc(playerUpdateVelocity)
x1, y1 := 1.0, 1.0
x2, y2 := 15.0, 15.0
playerShape := world.Space.AddShape(cp.NewBox2(playerBody, cp.BB{x1, y2, x2, y1}, 0))
playerShape.SetElasticity(0)
playerShape.SetFriction(0)
world.PlayerBody = playerBody
world.PlayerShape = playerShape
2022-06-17 21:17:03 +00:00
player := gohan.NewEntity()
2022-06-18 21:08:53 +00:00
player.AddComponent(&component.Position{
Body: world.PlayerBody,
})
2022-06-17 21:17:03 +00:00
player.AddComponent(&component.Velocity{})
player.AddComponent(&component.Sprite{
Frames: asset.PlayerIdleFrames,
2022-06-18 21:08:53 +00:00
FrameTime: 150 * time.Millisecond,
2022-06-17 21:17:03 +00:00
NumFrames: len(asset.PlayerIdleFrames),
2022-06-18 21:08:53 +00:00
OffsetY: -10,
2022-06-17 21:17:03 +00:00
})
player.AddComponent(&component.Player{})
return player
}
2022-06-18 21:08:53 +00:00
func playerUpdateVelocity(body *cp.Body, gravity cp.Vector, damping, dt float64) {
jumpState := false
// Grab the grounding normal from last frame
groundNormal := cp.Vector{}
/*world.PlayerBody.EachArbiter(func(arb *cp.Arbiter) {
n := arb.Normal().Neg()
if n.Y > groundNormal.Y {
groundNormal = n
}
})*/
grounded := groundNormal.Y > 0
if groundNormal.Y < 0 {
//remainingBoost = 0
}
// Do a normal-ish update
boost := jumpState // && remainingBoost > 0
var g cp.Vector
if !boost {
g = gravity
}
body.UpdateVelocity(g, damping, dt)
xDir := 0.0
if ebiten.IsKeyPressed(ebiten.KeyA) {
xDir -= 1
world.LastWalkDirL = false
}
if ebiten.IsKeyPressed(ebiten.KeyD) { // TODO
xDir += 1
world.LastWalkDirL = true
}
// Target horizontal speed for air/ground control
targetVx := playerVelocity * xDir
// Update the surface velocity and friction
// Note that the "feet" move in the opposite direction of the player.
surfaceV := cp.Vector{-targetVx, 0}
world.PlayerShape.SetSurfaceV(surfaceV)
if grounded {
world.PlayerShape.SetFriction(playerGroundAccel / world.Gravity)
} else {
world.PlayerShape.SetFriction(0)
}
// Apply air control if not grounded
if !grounded {
v := world.PlayerBody.Velocity()
world.PlayerBody.SetVelocity(cp.LerpConst(v.X, targetVx, playerAirAccel*dt), v.Y)
}
v := body.Velocity()
body.SetVelocity(v.X, cp.Clamp(v.Y, -fallVelocity, cp.INFINITY))
}