Skip to content

Commit

Permalink
Merge pull request #9 from kensonjohnson/smooth-entity-movement
Browse files Browse the repository at this point in the history
Smooth entity movement
  • Loading branch information
kensonjohnson authored Aug 12, 2024
2 parents b8ca29f + 27d281a commit 24a4b36
Show file tree
Hide file tree
Showing 5 changed files with 65 additions and 19 deletions.
20 changes: 19 additions & 1 deletion component/sprite.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,29 @@ package component

import (
"github.com/hajimehoshi/ebiten/v2"
"github.com/kensonjohnson/roguelike-game-go/config"
"github.com/yohamta/donburi"
)

type SpriteData struct {
Image *ebiten.Image
Image *ebiten.Image
OffestX int // The direction the sprite is moving FROM, -1, 0, 1
OffestY int // The direction the sprite is moving FROM, -1, 0, 1
AnimationFrame int
progress float64 // The progress of the current animation frame from 0 to 1
Animating bool
}

// Returns the X and Y offset for the current animation frame. TODO: Add
// support for animation frames.
func (sd *SpriteData) GetAnimationStep() (float64, float64) {
offsetX := (1 - sd.progress) * config.TileWidth * float64(sd.OffestX)
offsetY := (1 - sd.progress) * config.TileHeight * float64(sd.OffestY)
return offsetX, offsetY
}

func (sd *SpriteData) SetProgress(progress float64) {
sd.progress = progress
}

var Sprite = donburi.NewComponentType[SpriteData]()
6 changes: 5 additions & 1 deletion system/action/monster.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ func TakeMonsterAction(ecs *ecs.ECS) {

archetype.MonsterTag.Each(ecs.World, func(entry *donburi.Entry) {
position := component.Position.Get(entry)

sprite := component.Sprite.Get(entry)
monsterVision := component.Fov.Get(entry).VisibleTiles

// Check if the monster can see the player
Expand All @@ -37,8 +37,12 @@ func TakeMonsterAction(ecs *ecs.ECS) {
// Update the tile this monster is blocking
level.GetFromXY(position.X, position.Y).Blocked = false
nextTile.Blocked = true
sprite.OffestX = position.X - path[1].X
sprite.OffestY = position.Y - path[1].Y
position.X = path[1].X
position.Y = path[1].Y
sprite.Animating = true
sprite.SetProgress(0)
// Since the monster moved, update the field of view
monsterVision.Compute(level, position.X, position.Y, 8)
}
Expand Down
23 changes: 14 additions & 9 deletions system/action/player.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,6 @@ import (
func TakePlayerAction(ecs *ecs.ECS) bool {
turnTaken := false

// Grab current level
levelEntry := archetype.LevelTag.MustFirst(ecs.World)
level := component.Level.Get(levelEntry)

// Grab player data
playerEntry := archetype.PlayerTag.MustFirst(ecs.World)
position := component.Position.Get(playerEntry)
vision := component.Fov.Get(playerEntry)

// Capture any keypresses we care about
moveX := 0
moveY := 0
Expand Down Expand Up @@ -55,6 +46,16 @@ func TakePlayerAction(ecs *ecs.ECS) bool {
return false
}

// Grab current level
levelEntry := archetype.LevelTag.MustFirst(ecs.World)
level := component.Level.Get(levelEntry)

// Grab player data
playerEntry := archetype.PlayerTag.MustFirst(ecs.World)
position := component.Position.Get(playerEntry)
sprite := component.Sprite.Get(playerEntry)
vision := component.Fov.Get(playerEntry)

// TODO: Update so diagonal movement consumes two turns
// Attempt to move
tile := level.GetFromXY(position.X+moveX, position.Y+moveY)
Expand All @@ -66,6 +67,10 @@ func TakePlayerAction(ecs *ecs.ECS) bool {
// Update the player's position
position.X += moveX
position.Y += moveY
sprite.OffestX = -moveX
sprite.OffestY = -moveY
sprite.Animating = true
sprite.SetProgress(0)
// Update the player's field of view
vision.VisibleTiles.Compute(level, position.X, position.Y, 8)
// Update any discoverable entities
Expand Down
7 changes: 6 additions & 1 deletion system/render.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,12 @@ func (r *render) Draw(ecs *ecs.ECS, screen *ebiten.Image) {

if playerVision.IsVisible(position.X, position.Y) {
camera.CamImageOptions.GeoM.Reset()
camera.CamImageOptions.GeoM.Translate(float64(position.X*config.TileWidth), float64(position.Y*config.TileHeight))
if sprite.Animating {
offsetX, offsetY := sprite.GetAnimationStep()
camera.CamImageOptions.GeoM.Translate(float64(position.X*config.TileWidth)+offsetX, float64(position.Y*config.TileHeight)+offsetY)
} else {
camera.CamImageOptions.GeoM.Translate(float64(position.X*config.TileWidth), float64(position.Y*config.TileHeight))
}
camera.MainCamera.Draw(sprite.Image, camera.CamImageOptions, screen)
}
})
Expand Down
28 changes: 21 additions & 7 deletions system/turn.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,9 @@ const (
)

func (td *TurnData) Update(ecs *ecs.ECS) {
td.TurnCounter++

if td.TurnState == BeforePlayerAction {
td.TurnCounter++
// Check if player survived the last cycle of monster turns
entry := archetype.PlayerTag.MustFirst(ecs.World)
playerHealth := component.Health.Get(entry)
Expand All @@ -52,16 +52,30 @@ func (td *TurnData) Update(ecs *ecs.ECS) {
}
})

level.Redraw = true
component.Sprite.Each(ecs.World, func(entry *donburi.Entry) {
sprite := component.Sprite.Get(entry)
sprite.SetProgress(float64(td.TurnCounter) / 12)
})

td.progressTurnState()
if td.TurnCounter > 12 {
// Reset the progress of all sprites
component.Sprite.Each(ecs.World, func(entry *donburi.Entry) {
sprite := component.Sprite.Get(entry)
sprite.SetProgress(0)
sprite.Animating = false
sprite.OffestX = 0
sprite.OffestY = 0
})

level.Redraw = true
td.progressTurnState()
td.resetCounter()
}
}

if td.TurnState == PlayerTurn && td.TurnCounter > 12 {
turnTaken := action.TakePlayerAction(ecs)
if turnTaken {
if td.TurnState == PlayerTurn {
if turnTaken := action.TakePlayerAction(ecs); turnTaken {
td.progressTurnState()
td.resetCounter()
}
}

Expand Down

0 comments on commit 24a4b36

Please sign in to comment.