obstacle collission added, but not working yet

This commit is contained in:
Thomas von Dein 2024-02-20 18:47:32 +01:00
parent fd570216f0
commit 646b227b8e
15 changed files with 112 additions and 21 deletions

View File

@ -27,3 +27,7 @@ if inpututil.IsKeyJustPressed(ebiten.KeyS) {
- Add some final message when the player reaches the last level, start - Add some final message when the player reaches the last level, start
from scratch or a message to buy me some beer, whatever from scratch or a message to buy me some beer, whatever
- Calculate obstacle collision the same as solid collision with future
velocity and included snap in so that the player ends up right on
the edge of the obstacle and not inside as it is now

View File

@ -5,13 +5,13 @@ Background: background-lila
######## ########
# o # # #v o #
# S # # # S<# #
# #### # # #### #
# #### # # #### #
# # # #
# # #> ^#
######## ########

View File

@ -6,9 +6,11 @@ import (
"io/fs" "io/fs"
"log" "log"
"log/slog" "log/slog"
"openquell/config"
"openquell/util" "openquell/util"
"os" "os"
"path/filepath" "path/filepath"
"sort"
"strings" "strings"
"github.com/hajimehoshi/ebiten/v2" "github.com/hajimehoshi/ebiten/v2"
@ -28,9 +30,10 @@ type Tile struct {
Renderable bool Renderable bool
Velocity bool Velocity bool
Collectible bool Collectible bool
Obstacle bool
Particle int // -1=unused, 0-3 = show image of slice Particle int // -1=unused, 0-3 = show image of slice
Particles []*ebiten.Image Particles []*ebiten.Image
Obstacle bool
Direction int // obstacles
} }
func NewTilePlayer() *Tile { func NewTilePlayer() *Tile {
@ -65,7 +68,7 @@ func NewTileCollectible(class string) *Tile {
} }
} }
func NewTileObstacle(class string) *Tile { func NewTileObstacle(class string, direction int) *Tile {
return &Tile{ return &Tile{
Id: '+', Id: '+',
Sprite: Assets[class], Sprite: Assets[class],
@ -73,6 +76,7 @@ func NewTileObstacle(class string) *Tile {
Solid: false, Solid: false,
Renderable: true, Renderable: true,
Obstacle: true, Obstacle: true,
Direction: direction,
} }
} }
@ -121,7 +125,11 @@ func InitTiles() TileRegistry {
'#': NewTileBlock("block-grey32"), '#': NewTileBlock("block-grey32"),
'S': NewTilePlayer(), 'S': NewTilePlayer(),
'o': NewTileCollectible("collectible-orange"), 'o': NewTileCollectible("collectible-orange"),
'+': NewTileObstacle("obstacle-star"), '+': NewTileObstacle("obstacle-star", config.All),
'^': NewTileObstacle("obstacle-north", config.North),
'v': NewTileObstacle("obstacle-south", config.South),
'<': NewTileObstacle("obstacle-east", config.East),
'>': NewTileObstacle("obstacle-west", config.West),
'*': NewTileParticle([]string{ '*': NewTileParticle([]string{
//"particle-ring-1", //"particle-ring-1",
"particle-ring-2", "particle-ring-2",
@ -143,6 +151,10 @@ func LoadLevels(dir string) []RawLevel {
log.Fatalf("failed to read level dir %s: %s", dir, err) log.Fatalf("failed to read level dir %s: %s", dir, err)
} }
sort.Slice(entries, func(i, j int) bool {
return entries[i].Name() < entries[j].Name()
})
for _, levelfile := range entries { for _, levelfile := range entries {
if levelfile.Type().IsRegular() && strings.Contains(levelfile.Name(), ".lvl") { if levelfile.Type().IsRegular() && strings.Contains(levelfile.Name(), ".lvl") {
path := filepath.Join("assets", dir) path := filepath.Join("assets", dir)

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

View File

@ -72,7 +72,13 @@ func (position *Position) String() string {
} }
func (position *Position) Move(velocity *Velocity, speed *Speed) { func (position *Position) Move(velocity *Velocity, speed *Speed) {
position.Update(position.X+(velocity.Data.X*speed.Value), position.Y+(velocity.Data.Y*speed.Value)) if velocity.Direction != 0 {
slog.Debug("moving", "velocity", velocity, "speed", speed)
}
position.Update(
position.X+(velocity.Data.X*speed.Value),
position.Y+(velocity.Data.Y*speed.Value),
)
} }
func (position *Position) Set(newpos *Position) { func (position *Position) Set(newpos *Position) {

View File

@ -35,3 +35,21 @@ func (velocity *Velocity) Change(direction int) {
func (velocity *Velocity) Moving() bool { func (velocity *Velocity) Moving() bool {
return velocity.Data.X != 0 || velocity.Data.Y != 0 return velocity.Data.X != 0 || velocity.Data.Y != 0
} }
func (velocity *Velocity) InvertDirection() int {
switch velocity.Direction {
case East:
return West
case West:
return East
case South:
return North
case North:
return South
case All:
return Stop
}
// should not happen
return All
}

View File

@ -8,6 +8,7 @@ const (
West West
South South
North North
All
) )
const PLAYERSPEED int = 4 const PLAYERSPEED int = 4

View File

@ -48,12 +48,14 @@ func NewGrid(world *ecs.World,
components.Renderable, components.Renderable,
components.Collectible](world) components.Collectible](world)
obsmapper := generic.NewMap3[ obsmapper := generic.NewMap4[
components.Position, components.Position,
components.Velocity,
components.Renderable, components.Renderable,
components.Obstacle](world) components.Obstacle](world)
var pos *components.Position var pos *components.Position
var vel *components.Velocity
var render *components.Renderable var render *components.Renderable
var speed *components.Speed var speed *components.Speed
@ -78,7 +80,8 @@ func NewGrid(world *ecs.World,
pos, render, _ = colmapper.Get(entity) pos, render, _ = colmapper.Get(entity)
case tile.Obstacle: case tile.Obstacle:
entity := obsmapper.New() entity := obsmapper.New()
pos, render, _ = obsmapper.Get(entity) pos, vel, render, _ = obsmapper.Get(entity)
vel.Direction = tile.Direction
default: default:
log.Fatalln("unsupported tile type encountered") log.Fatalln("unsupported tile type encountered")
} }

Binary file not shown.

View File

@ -5,9 +5,9 @@ import (
"openquell/assets" "openquell/assets"
"openquell/components" "openquell/components"
. "openquell/components" . "openquell/components"
"openquell/config"
. "openquell/config" . "openquell/config"
"openquell/observers" "openquell/observers"
"openquell/util"
"github.com/hajimehoshi/ebiten/v2" "github.com/hajimehoshi/ebiten/v2"
"github.com/mlange-42/arche/ecs" "github.com/mlange-42/arche/ecs"
@ -15,13 +15,14 @@ import (
) )
type ObstacleSystem struct { type ObstacleSystem struct {
World *ecs.World World *ecs.World
Selector *generic.Filter3[Position, Obstacle, Renderable] Selector *generic.Filter4[Position, Velocity, Obstacle, Renderable]
PreviousFreePos *components.Position
} }
func NewObstacleSystem(world *ecs.World) *ObstacleSystem { func NewObstacleSystem(world *ecs.World) *ObstacleSystem {
system := &ObstacleSystem{ system := &ObstacleSystem{
Selector: generic.NewFilter3[Position, Obstacle, Renderable](), Selector: generic.NewFilter4[Position, Velocity, Obstacle, Renderable](),
World: world, World: world,
} }
@ -45,17 +46,25 @@ func (system *ObstacleSystem) Update() {
gameover := false gameover := false
for query.Next() { for query.Next() {
obsposition, obstacle, _ := query.Get() obsposition, obsvelocity, obstacle, _ := query.Get()
for player := range playerobserver.Entities { for player := range playerobserver.Entities {
playerposition := (*Position)(system.World.Get(player, posID)) playerposition := (*Position)(system.World.Get(player, posID))
playervelocity := (*Velocity)(system.World.Get(player, veloID)) playervelocity := (*Velocity)(system.World.Get(player, veloID))
ok, _ := playerposition.Intersects(obsposition, playervelocity) ok, newpos := playerposition.Intersects(obsposition, playervelocity)
if ok { if ok {
slog.Debug("bumped into obstacle", "obstacle", obstacle) slog.Debug("bumped into obstacle", "obstacle", obstacle)
EntitiesToRemove = append(EntitiesToRemove, player)
gameover = true if CheckObstacleSide(playervelocity, obsvelocity.Direction) {
EntitiesToRemove = append(EntitiesToRemove, player)
gameover = true
} else {
playervelocity.Change(Stop)
slog.Debug("bump not die", "originalpos", playerposition)
playerposition.Set(newpos)
slog.Debug("bump not die", "newpos", newpos)
}
} }
} }
} }
@ -82,7 +91,7 @@ func (system *ObstacleSystem) Draw(screen *ebiten.Image) {
query := system.Selector.Query(system.World) query := system.Selector.Query(system.World)
for query.Next() { for query.Next() {
pos, _, sprite := query.Get() pos, _, _, sprite := query.Get()
op.GeoM.Reset() op.GeoM.Reset()
op.GeoM.Translate(float64(pos.X), float64(pos.Y)) op.GeoM.Translate(float64(pos.X), float64(pos.Y))
@ -113,5 +122,21 @@ func (system *ObstacleSystem) AddParticle(position *components.Position) {
64, 64,
) )
timer.Start(config.PARTICLE_LOOPWAIT) timer.Start(PARTICLE_LOOPWAIT)
}
// return true if obstacle weapon points into the direction the player is moving
func CheckObstacleSide(playervelocity *Velocity, obsdirection int) bool {
movingdirection := playervelocity.InvertDirection()
if movingdirection == Stop || movingdirection == obsdirection {
slog.Debug("Damaging obstacle collision",
"playerdirection", util.DirectionStr(playervelocity.Direction),
"obsdirection", util.DirectionStr(obsdirection),
"movingdirection", util.DirectionStr(movingdirection),
)
return true
}
return false
} }

View File

@ -76,8 +76,8 @@ func (system PlayerSystem) Update() error {
} }
system.Particle.Update() system.Particle.Update()
system.Collectible.Update()
system.Obstacle.Update() system.Obstacle.Update()
system.Collectible.Update()
return nil return nil
} }
@ -96,7 +96,7 @@ func (system *PlayerSystem) Draw(screen *ebiten.Image) {
screen.DrawImage(sprite.Image, op) screen.DrawImage(sprite.Image, op)
} }
system.Obstacle.Draw(screen)
system.Collectible.Draw(screen) system.Collectible.Draw(screen)
system.Particle.Draw(screen) system.Particle.Draw(screen)
system.Obstacle.Draw(screen)
} }

View File

@ -1,5 +1,9 @@
package util package util
import (
. "openquell/config"
)
// find an item in a list, generic variant // find an item in a list, generic variant
func Contains[E comparable](s []E, v E) bool { func Contains[E comparable](s []E, v E) bool {
for _, vs := range s { for _, vs := range s {
@ -19,3 +23,21 @@ func Exists[K comparable, V any](m map[K]V, v K) bool {
return false return false
} }
func DirectionStr(dir int) string {
str := "Stop"
switch dir {
case East:
str = "East"
case West:
str = "West"
case South:
str = "South"
case North:
str = "North"
case All:
str = "All"
}
return str
}