City-building simulation video game
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

212 lines
5.5 KiB

package system
import (
"os"
"code.rocketnine.space/tslocum/citylimits/component"
"code.rocketnine.space/tslocum/citylimits/world"
"code.rocketnine.space/tslocum/gohan"
"github.com/hajimehoshi/ebiten/v2"
"github.com/hajimehoshi/ebiten/v2/inpututil"
)
const (
moveSpeed = 1.5
)
type playerMoveSystem struct {
player gohan.Entity
movement *MovementSystem
lastWalkDirL bool
rewindTicks int
nextRewindTick int
scrollDragX, scrollDragY int
scrollCamStartX, scrollCamStartY float64
}
func NewPlayerMoveSystem(player gohan.Entity, m *MovementSystem) *playerMoveSystem {
return &playerMoveSystem{
player: player,
movement: m,
scrollDragX: -1,
scrollDragY: -1,
}
}
func (_ *playerMoveSystem) Needs() []gohan.ComponentID {
return []gohan.ComponentID{
component.PositionComponentID,
component.VelocityComponentID,
component.WeaponComponentID,
}
}
func (_ *playerMoveSystem) Uses() []gohan.ComponentID {
return nil
}
func (s *playerMoveSystem) Update(ctx *gohan.Context) error {
if ebiten.IsKeyPressed(ebiten.KeyEscape) && !world.World.DisableEsc {
os.Exit(0)
return nil
}
if ebiten.IsKeyPressed(ebiten.KeyControl) && inpututil.IsKeyJustPressed(ebiten.KeyV) {
v := 1
if ebiten.IsKeyPressed(ebiten.KeyShift) {
v = 2
}
if world.World.Debug == v {
world.World.Debug = 0
} else {
world.World.Debug = v
}
return nil
}
if ebiten.IsKeyPressed(ebiten.KeyControl) && inpututil.IsKeyJustPressed(ebiten.KeyN) {
world.World.NoClip = !world.World.NoClip
return nil
}
if !world.World.GameStarted {
if ebiten.IsKeyPressed(ebiten.KeyEnter) || ebiten.IsMouseButtonPressed(ebiten.MouseButtonLeft) {
world.StartGame()
}
return nil
}
if inpututil.IsKeyJustPressed(ebiten.KeyM) {
// TODO mute sound
}
if world.World.GameOver {
if inpututil.IsKeyJustPressed(ebiten.KeyEnter) {
world.World.ResetGame = true
}
return nil
}
// Update target zoom level.
var scrollY float64
if ebiten.IsKeyPressed(ebiten.KeyC) || ebiten.IsKeyPressed(ebiten.KeyPageDown) {
scrollY = -0.25
} else if ebiten.IsKeyPressed(ebiten.KeyE) || ebiten.IsKeyPressed(ebiten.KeyPageUp) {
scrollY = .25
} else {
_, scrollY = ebiten.Wheel()
if scrollY < -1 {
scrollY = -1
} else if scrollY > 1 {
scrollY = 1
}
}
world.World.CamScaleTarget += scrollY * (world.World.CamScaleTarget / 7)
const minZoom = .15
const maxZoom = 2
if world.World.CamScaleTarget < minZoom {
world.World.CamScaleTarget = minZoom
} else if world.World.CamScaleTarget > maxZoom {
world.World.CamScaleTarget = maxZoom
}
// Smooth zoom transition.
div := 10.0
if world.World.CamScaleTarget > world.World.CamScale {
world.World.CamScale += (world.World.CamScaleTarget - world.World.CamScale) / div
} else if world.World.CamScaleTarget < world.World.CamScale {
world.World.CamScale -= (world.World.CamScale - world.World.CamScaleTarget) / div
}
pressLeft := ebiten.IsKeyPressed(ebiten.KeyLeft)
pressRight := ebiten.IsKeyPressed(ebiten.KeyRight)
pressUp := ebiten.IsKeyPressed(ebiten.KeyUp)
pressDown := ebiten.IsKeyPressed(ebiten.KeyDown)
const camSpeed = 10
if (pressLeft && !pressRight) ||
(pressRight && !pressLeft) {
if pressLeft {
world.World.CamX -= camSpeed
} else {
world.World.CamX += camSpeed
}
}
if (pressUp && !pressDown) ||
(pressDown && !pressUp) {
if pressUp {
world.World.CamY -= camSpeed
} else {
world.World.CamY += camSpeed
}
}
const scrollEdgeSize = 5
x, y := ebiten.CursorPosition()
if !world.World.GotCursorPosition {
if x != 0 || y != 0 {
world.World.GotCursorPosition = true
} else {
return nil
}
}
if ebiten.IsMouseButtonPressed(ebiten.MouseButtonMiddle) {
if s.scrollDragX == -1 && s.scrollDragY == -1 {
ebiten.SetCursorMode(ebiten.CursorModeCaptured)
s.scrollDragX, s.scrollDragY = x, y
s.scrollCamStartX, s.scrollCamStartY = world.World.CamX, world.World.CamY
} else {
dx, dy := float64(x-s.scrollDragX)/world.World.CamScale, float64(y-s.scrollDragY)/world.World.CamScale
world.World.CamX, world.World.CamY = s.scrollCamStartX-dx, s.scrollCamStartY-dy
}
} else {
if s.scrollDragX != -1 && s.scrollDragY != -1 {
s.scrollDragX, s.scrollDragY = -1, -1
ebiten.SetCursorMode(ebiten.CursorModeVisible)
} else if x >= 0 && y >= 0 && x < world.World.ScreenW && y < world.World.ScreenH {
// Pan via screen edge.
if x <= scrollEdgeSize {
world.World.CamX -= camSpeed
} else if x >= world.World.ScreenW-scrollEdgeSize-1 {
world.World.CamX += camSpeed
}
if y <= scrollEdgeSize {
world.World.CamY -= camSpeed
} else if y >= world.World.ScreenH-scrollEdgeSize-1 {
world.World.CamY += camSpeed
}
}
}
if world.World.HoverStructure != 0 {
xx, yy := world.ScreenToIso(x, y)
tileX, tileY := world.IsoToCartesian(xx, yy)
if tileX >= 0 && tileY >= 0 && tileX < 256 && tileY < 256 {
if inpututil.IsMouseButtonJustPressed(ebiten.MouseButtonLeft) {
world.BuildStructure(world.World.HoverStructure, false, int(tileX), int(tileY))
} else if int(tileX) != world.World.HoverX || int(tileY) != world.World.HoverY {
world.BuildStructure(world.World.HoverStructure, true, int(tileX), int(tileY))
}
world.World.HoverX, world.World.HoverY = int(tileX), int(tileY)
}
}
return nil
}
func (s *playerMoveSystem) Draw(_ *gohan.Context, _ *ebiten.Image) error {
return gohan.ErrSystemWithoutDraw
}
func deltaXY(x1, y1, x2, y2 float64) (dx float64, dy float64) {
dx, dy = x1-x2, y1-y2
if dx < 0 {
dx *= -1
}
if dy < 0 {
dy *= -1
}
return dx, dy
}