doctorlectro/system/input_move.go

268 lines
7.1 KiB
Go

package system
import (
"image"
"log"
"os"
"code.rocketnine.space/tslocum/doctorlectro/asset"
"code.rocketnine.space/tslocum/doctorlectro/entity"
"code.rocketnine.space/tslocum/doctorlectro/component"
"code.rocketnine.space/tslocum/doctorlectro/world"
"code.rocketnine.space/tslocum/gohan"
"github.com/hajimehoshi/ebiten/v2"
"github.com/hajimehoshi/ebiten/v2/inpututil"
)
type playerMoveSystem struct {
Position *component.Position
Velocity *component.Velocity
Sprite *component.Sprite
Player *component.Player
}
func NewPlayerMoveSystem() *playerMoveSystem {
return &playerMoveSystem{}
}
func (s *playerMoveSystem) Update(e gohan.Entity) error {
if ebiten.IsKeyPressed(ebiten.KeyEscape) && !world.DisableEsc {
os.Exit(0)
return nil
}
if world.GameOver {
return nil
}
if ebiten.IsKeyPressed(ebiten.KeyControl) && inpututil.IsKeyJustPressed(ebiten.KeyV) {
v := world.Debug + 1
if v > 2 {
v = 0
}
world.Debug = v
return nil
}
// Find the nearest surface and magnetize.
magnetActive := ebiten.IsKeyPressed(ebiten.KeySpace) && world.CanMagnetize
if magnetActive {
printCollision := func(m string) {
if world.Debug > 1 {
log.Println(m)
}
}
boxOffset := 4
collisionSize := 12
wallThreshold := 16
position := world.PlayerBody.Position()
px1, py1 := int(position.X)+boxOffset, int(position.Y)+boxOffset
px2, py2 := px1+collisionSize-(boxOffset*2), py1+collisionSize-(boxOffset*2)
playerRectD := image.Rect(px1, py1, px2, py2+wallThreshold)
playerRectDL := image.Rect(px1-wallThreshold, py1, px2, py2+wallThreshold)
playerRectL := image.Rect(px1-wallThreshold, py1, px2, py2)
playerRectUL := image.Rect(px1-wallThreshold, py1-wallThreshold, px2, py2)
playerRectU := image.Rect(px1, py1-wallThreshold, px2, py2)
playerRectUR := image.Rect(px1, py1-wallThreshold, px2+wallThreshold, py2)
playerRectR := image.Rect(px1, py1, px2+wallThreshold, py2)
playerRectDR := image.Rect(px1, py1, px2+wallThreshold, py2+wallThreshold)
var (
collideL bool
collideR bool
collideU bool
collideD bool
collideUL bool
collideUR bool
collideDL bool
collideDR bool
)
checkCollisions := func(r image.Rectangle) {
if !collideL && r.Overlaps(playerRectL) {
collideL = true
}
if !collideR && r.Overlaps(playerRectR) {
collideR = true
}
if !collideU && r.Overlaps(playerRectU) {
collideU = true
}
if !collideD && r.Overlaps(playerRectD) {
collideD = true
}
if !collideUL && r.Overlaps(playerRectUL) {
collideUL = true
}
if !collideUR && r.Overlaps(playerRectUR) {
collideUR = true
}
if !collideDL && r.Overlaps(playerRectDL) {
collideDL = true
}
if !collideDR && r.Overlaps(playerRectDR) {
collideDR = true
}
}
for i := range world.MetalRects {
checkCollisions(world.MetalRects[i])
}
for i := range world.DestructibleRects {
checkCollisions(world.DestructibleRects[i])
}
printCollision("COLLIDE")
if collideD {
if collideR {
world.MagnetDirection = world.MagnetizeDownRight
printCollision("DOWN RIGHT")
} else if collideL {
world.MagnetDirection = world.MagnetizeDownLeft
printCollision("DOWN LEFT")
} else {
world.MagnetDirection = world.MagnetizeDown
printCollision("DOWN")
}
} else if collideU {
printCollision("U")
if collideR {
world.MagnetDirection = world.MagnetizeUpRight
printCollision("UP RIGHT")
} else if collideL {
world.MagnetDirection = world.MagnetizeUpLeft
printCollision("UP LEFT")
} else {
world.MagnetDirection = world.MagnetizeUp
printCollision("UP")
}
} else if collideR {
printCollision("R")
if collideU {
world.MagnetDirection = world.MagnetizeUpRight
printCollision("UP RIGHT")
} else if collideD {
world.MagnetDirection = world.MagnetizeDownRight
printCollision("DOWN RIGHT")
} else {
world.MagnetDirection = world.MagnetizeRight
printCollision("RIGHT")
}
} else if collideL {
printCollision("L")
if collideU {
world.MagnetDirection = world.MagnetizeUpLeft
printCollision("UP LEFT")
} else if collideD {
world.MagnetDirection = world.MagnetizeDownLeft
printCollision("DOWN LEFT")
} else {
world.MagnetDirection = world.MagnetizeLeft
printCollision("LEFT")
}
} else if collideUL {
printCollision("UL")
world.MagnetDirection = world.MagnetizeUpLeft
} else if collideUR {
printCollision("UR")
world.MagnetDirection = world.MagnetizeUpRight
} else if collideDL {
printCollision("DL")
world.MagnetDirection = world.MagnetizeDownLeft
} else if collideDR {
printCollision("DR")
world.MagnetDirection = world.MagnetizeDownRight
} else {
printCollision("NONE")
magnetActive = false
}
}
world.MagnetActive = magnetActive
// Jump.
grounded := world.PlayerNormal.X != 0 || world.PlayerNormal.Y != 0
if inpututil.IsKeyJustPressed(ebiten.KeyJ) && grounded && world.CanJump {
const jumpVelocity = 333
vel := world.PlayerBody.Velocity()
switch world.PlayerDirection {
case world.MagnetizeDown:
vel.Y = -jumpVelocity
case world.MagnetizeDownLeft:
vel.X = jumpVelocity / 2
vel.Y = -jumpVelocity / 2
case world.MagnetizeLeft:
vel.X = jumpVelocity
case world.MagnetizeUpLeft:
vel.X = jumpVelocity / 2
vel.Y = jumpVelocity / 2
case world.MagnetizeUp:
vel.Y = jumpVelocity
case world.MagnetizeUpRight:
vel.X = -jumpVelocity / 2
vel.Y = jumpVelocity / 2
case world.MagnetizeRight:
vel.X = -jumpVelocity
case world.MagnetizeDownRight:
vel.X = -jumpVelocity / 2
vel.Y = -jumpVelocity / 2
}
world.PlayerBody.SetVelocity(vel.X, vel.Y)
}
// Fire.
const fireRate = 144 / 2
if ebiten.IsKeyPressed(ebiten.KeyK) && world.CanFire && (world.LastFire == 0 || world.Tick-world.LastFire >= fireRate) {
asset.SoundFire.Rewind()
asset.SoundFire.Play()
bullet := entity.NewBullet()
playerPosition := world.PlayerBody.Position()
bullet.With(func(position *component.Position, velocity *component.Velocity) {
bulletSpeed := 8.0
switch world.PlayerDirection {
case world.MagnetizeDown:
if world.LastWalkDirL {
velocity.X, velocity.Y = bulletSpeed, 0
} else {
velocity.X, velocity.Y = -bulletSpeed, 0
}
position.X, position.Y = playerPosition.X-2, playerPosition.Y-9
case world.MagnetizeLeft:
if world.LastWalkDirU {
velocity.X, velocity.Y = 0, -bulletSpeed
} else {
velocity.X, velocity.Y = 0, bulletSpeed
}
position.X, position.Y = playerPosition.X+7, playerPosition.Y-2
case world.MagnetizeUp:
if world.LastWalkDirL {
velocity.X, velocity.Y = bulletSpeed, 0
} else {
velocity.X, velocity.Y = -bulletSpeed, 0
}
position.X, position.Y = playerPosition.X-2, playerPosition.Y+7
case world.MagnetizeRight:
if world.LastWalkDirU {
velocity.X, velocity.Y = 0, -bulletSpeed
} else {
velocity.X, velocity.Y = 0, bulletSpeed
}
position.X, position.Y = playerPosition.X-9, playerPosition.Y-2
}
})
world.LastFire = world.Tick
}
return nil
}
func (s *playerMoveSystem) Draw(_ gohan.Entity, _ *ebiten.Image) error {
return gohan.ErrUnregister
}
func (s *playerMoveSystem) updateSprite() {
}