- Updated tileset configuration in 'tileset.tsj' to include new tiles and adjust dimensions. - Added 'settings.json' for key bindings related to climbing and movement actions. - Enhanced game logging in 'game.log' to track game start events and map loading. - Updated the game binary to the latest version.
672 lines
18 KiB
Go
672 lines
18 KiB
Go
package scenes
|
|
|
|
import (
|
|
"fmt"
|
|
"image"
|
|
"image/color"
|
|
_ "image/jpeg"
|
|
_ "image/png"
|
|
"log"
|
|
"sort"
|
|
|
|
"mountain/internal/entities"
|
|
"mountain/internal/input"
|
|
|
|
"github.com/go-gl/mathgl/mgl64"
|
|
"github.com/hajimehoshi/ebiten/v2"
|
|
"github.com/hajimehoshi/ebiten/v2/ebitenutil"
|
|
"github.com/hajimehoshi/ebiten/v2/inpututil"
|
|
)
|
|
|
|
const (
|
|
Gravity = 0.5
|
|
JumpForce = -8.0
|
|
MoveSpeed = 4.0
|
|
ViewSize = 380 // 800 width, we have 2 viewports (380 each with 20 padding)
|
|
)
|
|
|
|
type PlayState int
|
|
|
|
const (
|
|
StatePlaying PlayState = iota
|
|
StatePaused
|
|
StateSettings
|
|
)
|
|
|
|
type Player struct {
|
|
Pos mgl64.Vec3 // 3D Kordinater: X (vänster/höger), Y (upp/ner), Z (djup)
|
|
Vel mgl64.Vec3 // Hastighet
|
|
|
|
Width, Height float64 // För (AABB)
|
|
IsGrounded bool
|
|
|
|
// Sprites
|
|
SpriteRun *ebiten.Image
|
|
SpriteJump *ebiten.Image
|
|
SpriteIdle *ebiten.Image
|
|
SpriteTop *ebiten.Image
|
|
AnimationFrame int
|
|
AnimationCounter int
|
|
|
|
FacingRight bool
|
|
}
|
|
|
|
type PlayScene struct {
|
|
world *entities.World
|
|
player *Player
|
|
leftView *ebiten.Image
|
|
rightView *ebiten.Image
|
|
state PlayState
|
|
|
|
// Settings UI state
|
|
sortedActions []string
|
|
selectedIndex int
|
|
}
|
|
|
|
func NewPlayScene() *PlayScene {
|
|
w, err := entities.LoadWorldFromTiled("assets/maps/room1.tmj")
|
|
if err != nil {
|
|
log.Println("Kunde inte ladda room1:", err)
|
|
w = entities.NewWorld(100, 10, 100) // Fallback tom värd om JSON saknas
|
|
}
|
|
|
|
pRun, _, err := ebitenutil.NewImageFromFile("assets/images/Warrior_1/Run.png")
|
|
if err != nil {
|
|
log.Println("Run sprite error:", err)
|
|
pRun = ebiten.NewImage(96, 96)
|
|
}
|
|
pIdle, _, _ := ebitenutil.NewImageFromFile("assets/images/Warrior_1/Idle.png")
|
|
if pIdle == nil {
|
|
pIdle = pRun
|
|
}
|
|
pJump, _, _ := ebitenutil.NewImageFromFile("assets/images/Warrior_1/Jump.png")
|
|
if pJump == nil {
|
|
pJump = pRun
|
|
}
|
|
|
|
pTop := ebiten.NewImage(96, 96)
|
|
pTop.Fill(color.RGBA{255, 255, 0, 255})
|
|
|
|
player := &Player{
|
|
Pos: mgl64.Vec3{50.0 * entities.TileSize, 6.0 * entities.TileSize, 50.0 * entities.TileSize},
|
|
Width: 32,
|
|
Height: 32,
|
|
SpriteRun: pRun,
|
|
SpriteIdle: pIdle,
|
|
SpriteJump: pJump,
|
|
SpriteTop: pTop,
|
|
FacingRight: true,
|
|
}
|
|
|
|
return &PlayScene{
|
|
world: w,
|
|
player: player,
|
|
leftView: ebiten.NewImage(ViewSize, ViewSize),
|
|
rightView: ebiten.NewImage(ViewSize, ViewSize),
|
|
state: StatePlaying,
|
|
sortedActions: make([]string, 0),
|
|
selectedIndex: 0,
|
|
}
|
|
}
|
|
|
|
func (s *PlayScene) Update() error {
|
|
switch s.state {
|
|
case StatePlaying:
|
|
return s.updatePlaying()
|
|
case StatePaused:
|
|
return s.updatePaused()
|
|
case StateSettings:
|
|
return s.updateSettings()
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (s *PlayScene) updatePaused() error {
|
|
if inpututil.IsKeyJustPressed(ebiten.KeyEscape) {
|
|
s.state = StatePlaying
|
|
}
|
|
// Menu logic for pausing
|
|
if inpututil.IsKeyJustPressed(ebiten.KeyEnter) {
|
|
if s.selectedIndex == 0 {
|
|
s.state = StatePlaying
|
|
} else if s.selectedIndex == 1 {
|
|
s.state = StateSettings
|
|
s.initSettings()
|
|
}
|
|
}
|
|
if inpututil.IsKeyJustPressed(ebiten.KeyUp) || inpututil.IsKeyJustPressed(ebiten.KeyW) {
|
|
s.selectedIndex--
|
|
if s.selectedIndex < 0 {
|
|
s.selectedIndex = 1
|
|
}
|
|
}
|
|
if inpututil.IsKeyJustPressed(ebiten.KeyDown) || inpututil.IsKeyJustPressed(ebiten.KeyS) {
|
|
s.selectedIndex++
|
|
if s.selectedIndex > 1 {
|
|
s.selectedIndex = 0
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (s *PlayScene) initSettings() {
|
|
s.sortedActions = make([]string, 0, len(input.Manager.Actions))
|
|
for k := range input.Manager.Actions {
|
|
s.sortedActions = append(s.sortedActions, k)
|
|
}
|
|
sort.Strings(s.sortedActions)
|
|
s.selectedIndex = 0
|
|
}
|
|
|
|
func (s *PlayScene) updateSettings() error {
|
|
if input.Manager.IsRecording() {
|
|
if input.Manager.UpdateRecording() {
|
|
// Recording finished
|
|
}
|
|
return nil
|
|
}
|
|
|
|
if inpututil.IsKeyJustPressed(ebiten.KeyEscape) {
|
|
s.state = StatePaused
|
|
s.selectedIndex = 1 // back to settings button
|
|
return nil
|
|
}
|
|
|
|
if inpututil.IsKeyJustPressed(ebiten.KeyUp) || inpututil.IsKeyJustPressed(ebiten.KeyW) {
|
|
s.selectedIndex--
|
|
if s.selectedIndex < 0 {
|
|
s.selectedIndex = len(s.sortedActions) - 1
|
|
}
|
|
}
|
|
if inpututil.IsKeyJustPressed(ebiten.KeyDown) || inpututil.IsKeyJustPressed(ebiten.KeyS) {
|
|
s.selectedIndex++
|
|
if s.selectedIndex >= len(s.sortedActions) {
|
|
s.selectedIndex = 0
|
|
}
|
|
}
|
|
|
|
if inpututil.IsKeyJustPressed(ebiten.KeyEnter) {
|
|
action := s.sortedActions[s.selectedIndex]
|
|
input.Manager.StartRecording(action)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (s *PlayScene) updatePlaying() error {
|
|
if inpututil.IsKeyJustPressed(ebiten.KeyEscape) {
|
|
s.state = StatePaused
|
|
s.selectedIndex = 0
|
|
return nil
|
|
}
|
|
|
|
p := s.player
|
|
|
|
currentMoveSpeed := MoveSpeed
|
|
if input.Manager.IsActionPressed("Run") {
|
|
currentMoveSpeed = MoveSpeed * 1.8 // Lite snabbare när man springer
|
|
}
|
|
|
|
p.Vel[0] = 0
|
|
p.Vel[2] = 0
|
|
isMoving := false
|
|
|
|
// Kolla om spelaren är i ett klättringsbart objekt
|
|
currentGridX := int((p.Pos[0] + p.Width/2) / entities.TileSize)
|
|
currentGridY := int((p.Pos[1] + p.Height/2) / entities.TileSize)
|
|
currentGridZ := int((p.Pos[2] + p.Width/2) / entities.TileSize)
|
|
entIn := s.world.GetEntityAt(currentGridX, currentGridY, currentGridZ)
|
|
|
|
isClimbing := false
|
|
if entIn != nil && entIn.IsClimbable() && input.Manager.IsActionPressed("ClimbMode") {
|
|
isClimbing = true
|
|
}
|
|
|
|
if isClimbing {
|
|
p.Vel[1] = 0 // Ingen gravitation när man klättrar
|
|
|
|
if input.Manager.IsActionPressed("ClimbLeft") {
|
|
p.Vel[0] = -currentMoveSpeed
|
|
p.FacingRight = false
|
|
isMoving = true
|
|
}
|
|
if input.Manager.IsActionPressed("ClimbRight") {
|
|
p.Vel[0] = currentMoveSpeed
|
|
p.FacingRight = true
|
|
isMoving = true
|
|
}
|
|
if input.Manager.IsActionPressed("ClimbUp") {
|
|
p.Vel[1] = -currentMoveSpeed // Uppåt
|
|
isMoving = true
|
|
}
|
|
if input.Manager.IsActionPressed("ClimbDown") {
|
|
p.Vel[1] = currentMoveSpeed // Nedåt
|
|
isMoving = true
|
|
}
|
|
if input.Manager.IsActionPressed("ClimbIn") {
|
|
p.Vel[2] = -currentMoveSpeed // Inåt (mot djupet Z-)
|
|
isMoving = true
|
|
}
|
|
if input.Manager.IsActionPressed("ClimbOut") {
|
|
p.Vel[2] = currentMoveSpeed // Utåt (från djupet Z+)
|
|
isMoving = true
|
|
}
|
|
} else {
|
|
if input.Manager.IsActionPressed("MoveLeft") {
|
|
p.Vel[0] = -currentMoveSpeed
|
|
p.FacingRight = false
|
|
isMoving = true
|
|
}
|
|
if input.Manager.IsActionPressed("MoveRight") {
|
|
p.Vel[0] = currentMoveSpeed
|
|
p.FacingRight = true
|
|
isMoving = true
|
|
}
|
|
if input.Manager.IsActionPressed("MoveUp") {
|
|
p.Vel[2] = -currentMoveSpeed
|
|
isMoving = true
|
|
}
|
|
if input.Manager.IsActionPressed("MoveDown") {
|
|
p.Vel[2] = currentMoveSpeed
|
|
isMoving = true
|
|
}
|
|
|
|
if input.Manager.IsActionPressed("Jump") && p.IsGrounded {
|
|
p.Vel[1] = JumpForce
|
|
p.IsGrounded = false
|
|
}
|
|
|
|
if !p.IsGrounded {
|
|
p.Vel[1] += Gravity
|
|
}
|
|
}
|
|
|
|
// === FYSIK OCH KOLLISION ===
|
|
|
|
// Få tag på det nuvarande objektet i spelarens mitt-punkt för att veta om vi står i något klättringsbart
|
|
currGridX := int((p.Pos[0] + p.Width/2) / entities.TileSize)
|
|
currGridY := int((p.Pos[1] + p.Height/2) / entities.TileSize)
|
|
currGridZ := int((p.Pos[2] + p.Width/2) / entities.TileSize)
|
|
|
|
currentEnt := s.world.GetEntityAt(currGridX, currGridY, currGridZ)
|
|
isCurrentClimbable := currentEnt != nil && currentEnt.IsClimbable()
|
|
|
|
// 1. Hantera kollision för X-axeln (vänster/höger)
|
|
nextX := p.Pos[0] + p.Vel[0]
|
|
if p.Vel[0] != 0 {
|
|
targetGridX := int((nextX + p.Width/2) / entities.TileSize)
|
|
entX := s.world.GetEntityAt(targetGridX, currGridY, currGridZ)
|
|
|
|
if entX != nil && entX.IsBlocking() {
|
|
isTargetClimbable := entX.IsClimbable()
|
|
|
|
// Auto-klättra om målet är klättringsbart ELLER om vi redan står i något klättringsbart (t.ex framför en vägg på en stege)
|
|
if isTargetClimbable || isCurrentClimbable {
|
|
nextX = p.Pos[0] // Avbryt rörelse framåt
|
|
p.Vel[0] = 0
|
|
p.Pos[1] -= MoveSpeed * 0.6 // Långsam rörelse uppåt ("klättra upp")
|
|
p.IsGrounded = false
|
|
} else {
|
|
// Vanlig vägg - stoppa rörelse helt
|
|
nextX = p.Pos[0]
|
|
p.Vel[0] = 0
|
|
}
|
|
}
|
|
}
|
|
p.Pos[0] = nextX
|
|
|
|
// 2. Hantera kollision för Z-axeln (djup in/ut)
|
|
nextZ := p.Pos[2] + p.Vel[2]
|
|
if p.Vel[2] != 0 {
|
|
// Uppdatera currGridX eftersom vi kan ha rört oss
|
|
currGridX = int((p.Pos[0] + p.Width/2) / entities.TileSize)
|
|
targetGridZ := int((nextZ + p.Width/2) / entities.TileSize)
|
|
entZ := s.world.GetEntityAt(currGridX, currGridY, targetGridZ)
|
|
|
|
if entZ != nil && entZ.IsBlocking() {
|
|
isTargetClimbable := entZ.IsClimbable()
|
|
|
|
if isTargetClimbable || isCurrentClimbable {
|
|
nextZ = p.Pos[2] // Avbryt rörelse framåt
|
|
p.Vel[2] = 0
|
|
p.Pos[1] -= MoveSpeed * 0.6 // Långsam rörelse uppåt ("klättra upp")
|
|
p.IsGrounded = false
|
|
} else {
|
|
// Vanlig vägg - stoppa rörelse helt
|
|
nextZ = p.Pos[2]
|
|
p.Vel[2] = 0
|
|
}
|
|
}
|
|
}
|
|
p.Pos[2] = nextZ
|
|
|
|
// 3. Hantera kollision för Y-axeln (upp/ner + gravitation)
|
|
nextY := p.Pos[1] + p.Vel[1]
|
|
|
|
gridX := int((p.Pos[0] + p.Width/2) / entities.TileSize)
|
|
gridZ := int((p.Pos[2] + p.Width/2) / entities.TileSize)
|
|
|
|
if p.Vel[1] >= 0 {
|
|
// Faller (eller står still) - kolla kollision med marken (fötterna)
|
|
gridYFeet := int((nextY + p.Height) / entities.TileSize)
|
|
entY := s.world.GetEntityAt(gridX, gridYFeet, gridZ)
|
|
|
|
if entY != nil && entY.IsBlocking() {
|
|
nextY = float64(gridYFeet)*entities.TileSize - p.Height - 0.1
|
|
p.Vel[1] = 0
|
|
p.IsGrounded = true
|
|
} else {
|
|
p.IsGrounded = false
|
|
}
|
|
} else {
|
|
// Hoppar eller klättrar uppåt - kolla kollision med taket (huvudet)
|
|
p.IsGrounded = false
|
|
gridYHead := int(nextY / entities.TileSize)
|
|
entY := s.world.GetEntityAt(gridX, gridYHead, gridZ)
|
|
|
|
// Vi studsar i taket om det är solid OCH inte är klättringsbart
|
|
if entY != nil && entY.IsBlocking() && !entY.IsClimbable() {
|
|
nextY = float64(gridYHead+1)*entities.TileSize + 0.1
|
|
p.Vel[1] = 0
|
|
}
|
|
}
|
|
p.Pos[1] = nextY
|
|
|
|
// Kolla ifall vi står på en portal (mittpunkten)
|
|
standEnt := s.world.GetEntityAt(gridX, int((p.Pos[1]+p.Height/2)/entities.TileSize), gridZ)
|
|
if prt, ok := standEnt.(*entities.Portal); ok {
|
|
log.Println("Byter rum till: ", prt.TargetMap)
|
|
newW, err := entities.LoadWorldFromTiled("assets/maps/" + prt.TargetMap + ".tmj")
|
|
if err == nil {
|
|
s.world = newW
|
|
// Reset player position for new map
|
|
if prt.TargetMap == "room1" {
|
|
p.Pos = mgl64.Vec3{80.0 * entities.TileSize, 6.0 * entities.TileSize, 10.0 * entities.TileSize}
|
|
} else {
|
|
p.Pos = mgl64.Vec3{40.0 * entities.TileSize, 6.0 * entities.TileSize, 65.0 * entities.TileSize}
|
|
}
|
|
}
|
|
}
|
|
|
|
if isMoving {
|
|
p.AnimationCounter++
|
|
if p.AnimationCounter > 5 {
|
|
p.AnimationFrame = (p.AnimationFrame + 1) % 6
|
|
p.AnimationCounter = 0
|
|
}
|
|
} else {
|
|
p.AnimationFrame = 0
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (s *PlayScene) Draw(screen *ebiten.Image) {
|
|
screen.Fill(color.RGBA{20, 20, 20, 255})
|
|
|
|
s.leftView.Fill(color.RGBA{135, 206, 235, 255})
|
|
s.rightView.Fill(color.RGBA{50, 150, 50, 255})
|
|
|
|
playerGridZ := int((s.player.Pos[2] + s.player.Width/2) / entities.TileSize)
|
|
playerGridY := int((s.player.Pos[1] + s.player.Height/2) / entities.TileSize)
|
|
|
|
camX := s.player.Pos[0] - float64(ViewSize)/2.0
|
|
camY := s.player.Pos[1] - float64(ViewSize)/2.0
|
|
camZ := s.player.Pos[2] - float64(ViewSize)/2.0
|
|
|
|
// Vänster vy: Sido-vy (renderar objekt vid spelarens Z, max -3 till +3 djup)
|
|
leftDepthStart := playerGridZ - 3
|
|
if leftDepthStart < 0 {
|
|
leftDepthStart = 0
|
|
}
|
|
leftDepthEnd := playerGridZ + 3
|
|
if leftDepthEnd >= s.world.Depth {
|
|
leftDepthEnd = s.world.Depth - 1
|
|
}
|
|
|
|
for zLevel := leftDepthStart; zLevel <= leftDepthEnd; zLevel++ {
|
|
alpha := float32(1.0)
|
|
diff := float32(zLevel - playerGridZ)
|
|
|
|
if diff < 0 {
|
|
// Bakom spelaren: självande alpha
|
|
alpha = 1.0 + (diff * 0.2) // diff är negativt, så detta minskar alpha
|
|
if alpha < 0.2 {
|
|
alpha = 0.2
|
|
}
|
|
} else if diff > 0 {
|
|
// Framför spelaren: självande alpha
|
|
alpha = 1.0 - (diff * 0.3)
|
|
if alpha < 0.1 {
|
|
alpha = 0.1
|
|
}
|
|
}
|
|
|
|
// Rendera spelaren på rätt Z-lager (vid diff == 0)
|
|
if zLevel == playerGridZ {
|
|
for x := 0; x < s.world.Width; x++ {
|
|
for y := 0; y < s.world.Height; y++ {
|
|
ent := s.world.GetEntityAt(x, y, zLevel)
|
|
if ent != nil {
|
|
px := float64(x)*entities.TileSize - camX
|
|
py := float64(y)*entities.TileSize - camY
|
|
ent.DrawSide(s.leftView, px, py, 1.0)
|
|
}
|
|
}
|
|
}
|
|
s.drawPlayerSide(s.leftView, camX, camY)
|
|
} else {
|
|
for x := 0; x < s.world.Width; x++ {
|
|
for y := 0; y < s.world.Height; y++ {
|
|
ent := s.world.GetEntityAt(x, y, zLevel)
|
|
if ent != nil {
|
|
px := float64(x)*entities.TileSize - camX
|
|
py := float64(y)*entities.TileSize - camY
|
|
ent.DrawSide(s.leftView, px, py, alpha)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Höger vy: Ovan-vy (renderar Y-lager runt spelaren)
|
|
// Positivt 'diff' i Y-axel betyder djupare in i marken (Längre bort = mer transparent)
|
|
// Negativt 'diff' i Y-axel betyder högre upp mot kameran (Närmare = mer transparent så man ser igenom)
|
|
for diff := 3; diff >= -3; diff-- {
|
|
yLevel := playerGridY + diff
|
|
if yLevel >= 0 && yLevel < s.world.Height {
|
|
alpha := float32(1.0)
|
|
|
|
if diff > 0 {
|
|
// Under marknivån: sjunkande alpha
|
|
alpha = 1.0 - (float32(diff) * 0.2)
|
|
if alpha < 0.2 {
|
|
alpha = 0.2
|
|
}
|
|
} else if diff < 0 {
|
|
// Över marknivån: sjunkande alpha
|
|
alpha = 1.0 - (float32(-diff) * 0.3)
|
|
if alpha < 0.1 {
|
|
alpha = 0.1
|
|
}
|
|
}
|
|
|
|
if diff == 0 {
|
|
for x := 0; x < s.world.Width; x++ {
|
|
for z := 0; z < s.world.Depth; z++ {
|
|
ent := s.world.GetEntityAt(x, yLevel, z)
|
|
if ent != nil {
|
|
px := float64(x)*entities.TileSize - camX
|
|
pz := float64(z)*entities.TileSize - camZ
|
|
ent.DrawTop(s.rightView, px, pz, 1.0)
|
|
}
|
|
}
|
|
}
|
|
s.drawPlayerTop(s.rightView, camX, camZ)
|
|
} else {
|
|
for x := 0; x < s.world.Width; x++ {
|
|
for z := 0; z < s.world.Depth; z++ {
|
|
ent := s.world.GetEntityAt(x, yLevel, z)
|
|
if ent != nil {
|
|
px := float64(x)*entities.TileSize - camX
|
|
pz := float64(z)*entities.TileSize - camZ
|
|
ent.DrawTop(s.rightView, px, pz, alpha)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
opL := &ebiten.DrawImageOptions{}
|
|
opL.GeoM.Translate(10, 100)
|
|
screen.DrawImage(s.leftView, opL)
|
|
|
|
opR := &ebiten.DrawImageOptions{}
|
|
opR.GeoM.Translate(410, 100)
|
|
screen.DrawImage(s.rightView, opR)
|
|
|
|
ebitenutil.DebugPrint(screen, "VÄNSTER (Sido vy) HÖGER (Top vy: Slice av din Hojd)")
|
|
|
|
// Rita UI ovanpå allt, beroende på state
|
|
if s.state == StatePaused {
|
|
s.drawPauseUI(screen)
|
|
} else if s.state == StateSettings {
|
|
s.drawSettingsUI(screen)
|
|
}
|
|
}
|
|
|
|
func (s *PlayScene) drawPlayerSide(screen *ebiten.Image, camX, camY float64) {
|
|
p := s.player
|
|
|
|
sx := p.AnimationFrame * 96
|
|
srcRect := image.Rect(sx, 0, sx+96, 96)
|
|
var activeSprite *ebiten.Image
|
|
|
|
if p.Vel[0] != 0 || p.Vel[2] != 0 { // Is moving X or Z
|
|
activeSprite = p.SpriteRun
|
|
} else {
|
|
activeSprite = p.SpriteIdle
|
|
}
|
|
|
|
subImg := activeSprite.SubImage(srcRect).(*ebiten.Image)
|
|
|
|
op := &ebiten.DrawImageOptions{}
|
|
if !p.FacingRight {
|
|
op.GeoM.Scale(-1, 1)
|
|
op.GeoM.Translate(96, 0)
|
|
}
|
|
|
|
drawX := p.Pos[0] - camX - 32
|
|
drawY := p.Pos[1] - camY - 64
|
|
|
|
op.GeoM.Translate(drawX, drawY)
|
|
screen.DrawImage(subImg, op)
|
|
}
|
|
|
|
func (s *PlayScene) drawPlayerTop(screen *ebiten.Image, camX, camZ float64) {
|
|
p := s.player
|
|
|
|
sx := p.AnimationFrame * 96
|
|
srcRect := image.Rect(sx, 0, sx+96, 96)
|
|
var activeSprite *ebiten.Image
|
|
|
|
if p.Vel[0] != 0 || p.Vel[2] != 0 || p.Vel[1] != 0 {
|
|
activeSprite = p.SpriteRun
|
|
} else {
|
|
activeSprite = p.SpriteIdle
|
|
}
|
|
|
|
subImg := activeSprite.SubImage(srcRect).(*ebiten.Image)
|
|
|
|
op := &ebiten.DrawImageOptions{}
|
|
if !p.FacingRight {
|
|
op.GeoM.Scale(-1, 1)
|
|
op.GeoM.Translate(96, 0)
|
|
}
|
|
|
|
drawX := p.Pos[0] - camX - 32
|
|
drawZ := p.Pos[2] - camZ - 64
|
|
op.GeoM.Translate(drawX, drawZ)
|
|
|
|
// Rita med lite tint i toppen kanske? Vi ritar bara ut imagen
|
|
screen.DrawImage(subImg, op)
|
|
}
|
|
|
|
func (s *PlayScene) drawPauseUI(screen *ebiten.Image) {
|
|
// Mörka ner bakgrunden något
|
|
overlay := ebiten.NewImage(800, 600)
|
|
overlay.Fill(color.RGBA{0, 0, 0, 150})
|
|
screen.DrawImage(overlay, &ebiten.DrawImageOptions{})
|
|
|
|
ebitenutil.DebugPrintAt(screen, "--- PAUSAD ---", 350, 200)
|
|
|
|
options := []string{"Fortsatt", "Installningar"}
|
|
for i, opt := range options {
|
|
prefix := " "
|
|
if i == s.selectedIndex {
|
|
prefix = "> "
|
|
}
|
|
ebitenutil.DebugPrintAt(screen, prefix+opt, 350, 250+(i*30))
|
|
}
|
|
}
|
|
|
|
func (s *PlayScene) drawSettingsUI(screen *ebiten.Image) {
|
|
overlay := ebiten.NewImage(800, 600)
|
|
overlay.Fill(color.RGBA{0, 0, 0, 200})
|
|
screen.DrawImage(overlay, &ebiten.DrawImageOptions{})
|
|
|
|
ebitenutil.DebugPrintAt(screen, "--- INSTALLNINGAR ---", 300, 30)
|
|
|
|
if input.Manager.IsRecording() {
|
|
ebitenutil.DebugPrintAt(screen, ">> SPELAR IN: HÅLL IN TANGENTER OCH TRYCK ENTER FOR ATT SPARA <<", 180, 60)
|
|
ebitenutil.DebugPrintAt(screen, "ESC for att avbryta", 300, 80)
|
|
} else {
|
|
ebitenutil.DebugPrintAt(screen, "Tryck Enter for att ga in i redigeringslage, ESC for att abryta", 180, 60)
|
|
}
|
|
|
|
startY := 120
|
|
for i, action := range s.sortedActions {
|
|
prefix := " "
|
|
if i == s.selectedIndex {
|
|
prefix = "> "
|
|
}
|
|
|
|
// Bygg en sträng för att visa nuvarande tangenter
|
|
bindingStr := ""
|
|
bindings := input.Manager.Actions[action]
|
|
if input.Manager.IsRecording() && input.Manager.GetRecordingAction() == action {
|
|
// Visar vilka knappar som spelas in just nu
|
|
recKeys := input.Manager.GetRecordingKeys()
|
|
if len(recKeys) == 0 {
|
|
bindingStr = "[Vantar pa dig...]"
|
|
} else {
|
|
names := []string{}
|
|
for _, rk := range recKeys {
|
|
names = append(names, input.KeyName(rk))
|
|
}
|
|
bindingStr = fmt.Sprintf("[TRYCK ENTER FOR ATT SPARA: %v]", names)
|
|
}
|
|
} else {
|
|
if len(bindings) > 0 {
|
|
for bi, b := range bindings {
|
|
if bi > 0 {
|
|
bindingStr += " ELLER "
|
|
}
|
|
names := []string{}
|
|
for _, k := range b {
|
|
names = append(names, input.KeyName(k))
|
|
}
|
|
bindingStr += fmt.Sprintf("%v", names)
|
|
}
|
|
} else {
|
|
bindingStr = "[Ingen]"
|
|
}
|
|
}
|
|
|
|
line := fmt.Sprintf("%s%-15s : %s", prefix, action, bindingStr)
|
|
ebitenutil.DebugPrintAt(screen, line, 100, startY+(i*25))
|
|
}
|
|
}
|