From b0a8060d5be5b383d330ecb5bb72491481bc9aa4 Mon Sep 17 00:00:00 2001 From: Thomas von Dein Date: Sun, 25 Feb 2024 14:05:44 +0100 Subject: [PATCH] added hidden doors/destroyable walls, fixed game reloading (tile clone) --- TODO.md | 8 +- assets/levels/00-deadly-obstacles.lvl | 2 +- assets/levels/04-mayhem.lvl | 10 +- assets/loader-levels.go | 75 ++++++++++--- assets/sprites/block-greycolored-damaged.png | Bin 0 -> 1806 bytes assets/sprites/block-greycolored.png | Bin 0 -> 5871 bytes components/destroyable.go | 29 +++++ game/game.go | 1 - game/levels.go | 51 ++++++--- grid/grid.go | 20 +++- src/block-grey-damage.xcf | Bin 0 -> 20371 bytes src/block-grey.xcf | Bin 1794 -> 20280 bytes systems/destroyable_system.go | 108 +++++++++++++++++++ systems/grid_system.go | 4 +- systems/transient_system.go | 2 +- 15 files changed, 271 insertions(+), 39 deletions(-) create mode 100644 assets/sprites/block-greycolored-damaged.png create mode 100644 assets/sprites/block-greycolored.png create mode 100644 components/destroyable.go create mode 100644 src/block-grey-damage.xcf create mode 100644 systems/destroyable_system.go diff --git a/TODO.md b/TODO.md index 600e787..e448b58 100644 --- a/TODO.md +++ b/TODO.md @@ -32,4 +32,10 @@ if inpututil.IsKeyJustPressed(ebiten.KeyS) { 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 -- Check player-player collisions! +- Check player-player collisions! + +- Do all collision detections in ONE system + +- do not use the map anymore for collision detection + +- check swept AABB instead of my collision detection, to allow for higher speeds diff --git a/assets/levels/00-deadly-obstacles.lvl b/assets/levels/00-deadly-obstacles.lvl index 710e398..41dafbc 100644 --- a/assets/levels/00-deadly-obstacles.lvl +++ b/assets/levels/00-deadly-obstacles.lvl @@ -4,7 +4,7 @@ Background: background-lila ####### - # # + #o # # t # #> S <# # # diff --git a/assets/levels/04-mayhem.lvl b/assets/levels/04-mayhem.lvl index db2966d..52353b9 100644 --- a/assets/levels/04-mayhem.lvl +++ b/assets/levels/04-mayhem.lvl @@ -4,13 +4,13 @@ Background: background-lila - ########## - # v# + ########W# + # v # # # #S s# - # # - #^ # - ########## + ############ + # o # + ######## # diff --git a/assets/loader-levels.go b/assets/loader-levels.go index f75ec09..5defb2a 100644 --- a/assets/loader-levels.go +++ b/assets/loader-levels.go @@ -25,18 +25,42 @@ type Tile struct { Id byte Sprite *ebiten.Image Class string - Solid bool - Player bool - IsPrimary bool - Renderable bool - Velocity bool - Collectible bool - Transient bool - Particle int // -1=unused, 0-3 = show image of slice - Tiles []*ebiten.Image - TileNames []string // same thing, only the names - Obstacle bool - Direction int // obstacles + Solid bool // wall brick + Player bool // player sphere + IsPrimary bool // primary player sphere + Renderable bool // visible, has sprite + Velocity bool // movable + Collectible bool // collectible, vanishes once collected + Transient bool // turns into brick wall when traversed + Destroyable bool // turns into empty floor when bumped into twice + Particle int // -1=unused, 0-3 = show image of slice + Tiles []*ebiten.Image // has N sprites + TileNames []string // same thing, only the names + Obstacle bool // is an obstacle/enemy + Direction int // obstacle business end shows into this direction +} + +func (tile *Tile) Clone() *Tile { + newtile := &Tile{ + Id: tile.Id, + Sprite: tile.Sprite, + Class: tile.Class, + Solid: tile.Solid, + Player: tile.Player, + IsPrimary: tile.IsPrimary, + Renderable: tile.Renderable, + Velocity: tile.Velocity, + Collectible: tile.Collectible, + Transient: tile.Transient, + Destroyable: tile.Destroyable, + Particle: tile.Particle, + Tiles: tile.Tiles, + TileNames: tile.TileNames, + Obstacle: tile.Obstacle, + Direction: tile.Direction, + } + + return newtile } const ( @@ -128,7 +152,7 @@ func NewTileTranswall(class []string) *Tile { } return &Tile{ - Id: '*', + Id: 't', Class: "transwall", Solid: false, Renderable: true, @@ -139,6 +163,27 @@ func NewTileTranswall(class []string) *Tile { } } +func NewTileHiddenDoor(class []string) *Tile { + sprites := []*ebiten.Image{} + names := []string{} + + for _, sprite := range class { + sprites = append(sprites, Assets[sprite]) + names = append(names, sprite) + } + + return &Tile{ + Id: 'W', + Class: "hiddendoor", + Solid: false, + Renderable: true, + Destroyable: true, + Tiles: sprites, + Sprite: sprites[0], // initially use the first + TileNames: names, + } +} + // used to map level data bytes to actual tiles type TileRegistry map[byte]*Tile @@ -164,7 +209,8 @@ type RawLevel struct { func InitTiles() TileRegistry { return TileRegistry{ ' ': {Id: ' ', Class: "floor", Renderable: false}, - '#': NewTileBlock("block-grey32"), + //'#': NewTileBlock("block-grey32"), + '#': NewTileBlock("block-greycolored"), 'B': NewTileBlock("block-orange-32"), 'S': NewTilePlayer(Primary), 's': NewTilePlayer(Secondary), @@ -183,6 +229,7 @@ func InitTiles() TileRegistry { "particle-ring-6", }), 't': NewTileTranswall([]string{"transwall", "block-orange-32"}), + 'W': NewTileHiddenDoor([]string{"block-greycolored", "block-greycolored-damaged"}), } } diff --git a/assets/sprites/block-greycolored-damaged.png b/assets/sprites/block-greycolored-damaged.png new file mode 100644 index 0000000000000000000000000000000000000000..aa9df25cda199a6a7ce75b95d843f19c0af3f599 GIT binary patch literal 1806 zcmV+p2l4ocP)EX>4Tx04R}tkv&MmKpe$iQ^gOe4t7v+$WWc^q9Ts93Pq?8YK2xEOfLO`CJjl7 zi=*ILaPVWX>fqw6tAnc`2!4P#J2)x2NQwVT3N2zhIPS;0dyl(!fKV?p&FY8&nr@q^ zL|n{dSH-SZ2pC2WMD)wdGUg;H3E%N`j{slqqCCt0+@GUQ%~=cxh{Q2wm^SeS@yw=e zaNZ{lv!bjLpA%1*bV1@rt}7nDaW1$l@XWB8PR$dCiN!)2D{ah*rbawX98oo$@`a4Y zD(5ZETDi)a_v9}O<@A+huG1Vv0*hFJL>(!pqJ%PRL}}GYv5=zuxQ~Ct^-JVZ$W;O( z#{w$QAiI9>Klt6Pm7kjQl0tEy^TlyK#(=I}piy(2?_(i|qi@OrgSSBMn%7%%AEysMnz~Bf00)P_ zc!9Flecs*O-rK)tn*IF%YQJ)$tS-bk00006VoOIv0M!810M*5%|?02y>eSad^gZEa<4bO1wgWnpw> zWFU8GbZ8()Nlj2!fese{00ibqL_t(o!@ZZ=Q&U$I#((?d*K$jODg3eme!hv8GQD^w2hg6@KpF_T2{&C3)oUh0J51hsl6SP zQnew`jqB5)l|pHSR{G?gKDj59#?p$QQUuUA0fok(EejpA(b__58?9Xm#Ud-)TL9Re z=K+vD*kkqSV?M?LwE=)t8wkMmt+R~8)WXwnKq<-pWu^%m%kwN-KDu8s5j)jCg><1F5s;>ySn zmSrJ?U}=7at-Tamdk0;AX)2wet~tiX0Z$^OhgPb_P{a1#0g2=`Up=_Tw_iUZv9-(3 zzdj?A%>xh)xjekPz>{ZjDpjv52a4rma)nZhLRocbR7z3xJl=2b677j_>&A7$A(u!v z#KXIbjE`LA`=1{3+j1OFO0EnKF*?-G>UyF(2&x|Yhv_yD)Evm>a+HrNd^S2vZ?wn1 z$P!Fm9pjrv_jvIpfl?YF1fSo!!K=4PGTB^L9C)|2+a?WbI^a4E7h=&fNfoqhTqlSV z3^t(na%rC5S61=Wl(r6dBzIG_G;dDBS}pL&QwNhuF>tXL%Q|&(Yato zA}#mBA(t-}W>{HW>!AGxr4`Xgn6T^mq}-D7Bn_3)T{s}=iGtf(5!^E^dty_wtYQqTl};60xw>_ zC9%1~-eDG{HLhdxaA|?TOMM)qGd`gTxek53Q4*UwOkTaxAp)`%0Y{wafL4m9@in}r z9G@H?=Kk$DV$ld|i6qxP8*AA&JlIciXP=;Lx9tf}A<%(y3XyKG+I4ImEX{L$d=$&F z$QMft_Fp7mS#7goadrx=P20arO%9x$-%2Trsekn>v8JA(TJ`9^c;Q^`bl`vo0y5bg z)#FkN^BXNy>6rQH2}XtnI4YFLkYxZ2$lO07*qoM6N<$f)FZH$p8QV literal 0 HcmV?d00001 diff --git a/assets/sprites/block-greycolored.png b/assets/sprites/block-greycolored.png new file mode 100644 index 0000000000000000000000000000000000000000..a72c4d0a3fca60ebc96d90006851e7e60da790e1 GIT binary patch literal 5871 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 EH%kQ=MF0Q* literal 0 HcmV?d00001 diff --git a/components/destroyable.go b/components/destroyable.go new file mode 100644 index 0000000..f29f375 --- /dev/null +++ b/components/destroyable.go @@ -0,0 +1,29 @@ +package components + +import ( + "log" + + "github.com/hajimehoshi/ebiten/v2" +) + +// A hidden door in a wall. If the player bumps into it once, it shows +// damage and it vanishes the next time. + +type Destroyable struct { + Activated bool + Sprites []*ebiten.Image + Current int // sprite index +} + +func (door *Destroyable) GetNext() *ebiten.Image { + if len(door.Sprites) > door.Current { + door.Current++ + return door.Sprites[door.Current] + } + + log.Fatalf("not enough sprites in transient tile, have %d sprites, index requested: %d", + len(door.Sprites), door.Current+1, + ) + + return nil +} diff --git a/game/game.go b/game/game.go index b75ca31..ba16f05 100644 --- a/game/game.go +++ b/game/game.go @@ -96,7 +96,6 @@ func (game *Game) Update() error { if next == Play { // fresh setup of actual level every time we enter the play scene - //game.Scenes[Play] = NewLevelScene(game, gameobserver.CurrentLevel) game.Scenes[Play].SetLevel(gameobserver.CurrentLevel) } diff --git a/game/levels.go b/game/levels.go index 69e7047..4cb52e8 100644 --- a/game/levels.go +++ b/game/levels.go @@ -3,6 +3,7 @@ package game import ( "image" "log" + "log/slog" "openquell/assets" "openquell/components" "openquell/grid" @@ -15,12 +16,16 @@ import ( "github.com/mlange-42/arche/ecs" ) +type Map map[image.Point]*assets.Tile +type BackupMap map[image.Point]assets.Tile + type Level struct { Cellsize, Width, Height int World *ecs.World Name string Description string - Mapslice map[image.Point]*assets.Tile + Mapslice Map + BackupMapslice Map GridContainer *grid.GridContainer Systems []systems.System Grid *grid.Grid @@ -45,16 +50,21 @@ func NewLevel(game *Game, cellsize int, plan *assets.RawLevel) *Level { systemlist = append(systemlist, systems.NewTransientSystem(game.World, gridcontainer)) + systemlist = append(systemlist, systems.NewDestroyableSystem(game.World, gridcontainer)) + + mapslice, backupmap := LevelToSlice(game, plan, cellsize) + return &Level{ - Mapslice: LevelToSlice(game, plan, cellsize), - Cellsize: cellsize, - World: game.World, - Width: game.ScreenWidth, - Height: game.ScreenHeight, - Description: plan.Description, - Name: plan.Name, - GridContainer: gridcontainer, - Systems: systemlist, + Mapslice: mapslice, + BackupMapslice: backupmap, + Cellsize: cellsize, + World: game.World, + Width: game.ScreenWidth, + Height: game.ScreenHeight, + Description: plan.Description, + Name: plan.Name, + GridContainer: gridcontainer, + Systems: systemlist, } } @@ -77,6 +87,12 @@ func (level *Level) Position2Point(position *components.Position) image.Point { } } +func (level *Level) RestoreMap() { + for point, tile := range level.BackupMapslice { + level.Mapslice[point] = tile.Clone() + } +} + func (level *Level) SetupGrid(game *Game) { // generic variant does not work here: // selector := generic.NewFilter1[components.Position]() @@ -92,15 +108,20 @@ func (level *Level) SetupGrid(game *Game) { playerobserver := observers.GetPlayerObserver(level.World) playerobserver.RemoveEntities() + // get rid of possibly manipulated map + level.RestoreMap() + // setup world + slog.Debug("new grid?") level.GridContainer.SetGrid( grid.NewGrid(game.World, level.Cellsize, level.Width, level.Height, level.Mapslice)) } // parses a RawLevel and generates a mapslice from it, which is being used as grid -func LevelToSlice(game *Game, level *assets.RawLevel, tilesize int) map[image.Point]*assets.Tile { +func LevelToSlice(game *Game, level *assets.RawLevel, tilesize int) (Map, Map) { size := game.ScreenWidth * game.ScreenHeight - mapslice := make(map[image.Point]*assets.Tile, size) + mapslice := make(Map, size) + backupmap := make(Map, size) for y, line := range strings.Split(string(level.Data), "\n") { if len(line) != game.ScreenWidth/tilesize && y < game.ScreenHeight/tilesize { @@ -113,9 +134,11 @@ func LevelToSlice(game *Game, level *assets.RawLevel, tilesize int) map[image.Po log.Fatalf("unregistered tile type %c encountered", char) } - mapslice[image.Point{x, y}] = assets.Tiles[byte(char)] + tile := assets.Tiles[byte(char)] + mapslice[image.Point{x, y}] = tile + backupmap[image.Point{x, y}] = tile.Clone() } } - return mapslice + return mapslice, backupmap } diff --git a/grid/grid.go b/grid/grid.go index 7870f96..5c6edc1 100644 --- a/grid/grid.go +++ b/grid/grid.go @@ -61,12 +61,18 @@ func NewGrid(world *ecs.World, components.Renderable, components.Transient](world) + doormapper := generic.NewMap3[ + components.Position, + components.Renderable, + components.Destroyable](world) + var pos *components.Position var vel *components.Velocity var render *components.Renderable var speed *components.Speed var transient *components.Transient var player *components.Player + var destroyable *components.Destroyable playerobserver := observers.GetPlayerObserver(world) obstacleobserver := observers.GetObstacleObserver(world) @@ -99,6 +105,10 @@ func NewGrid(world *ecs.World, entity := transmapper.New() pos, render, transient = transmapper.Get(entity) transient.Sprites = tile.TileNames + case tile.Destroyable: + entity := doormapper.New() + pos, render, destroyable = doormapper.Get(entity) + destroyable.Sprites = tile.Tiles default: log.Fatalln("unsupported tile type encountered") } @@ -143,7 +153,15 @@ func (grid *Grid) GetTile( return tile } -func (grid *Grid) SetTile(tile *assets.Tile, point image.Point) { +func (grid *Grid) RemoveTile(point image.Point) { + delete(grid.Map, point) +} + +func (grid *Grid) SetFloorTile(point image.Point) { + grid.Map[point] = assets.Tiles[' '] +} + +func (grid *Grid) SetSolidTile(tile *assets.Tile, point image.Point) { solidmapper := generic.NewMap4[ components.Position, components.Renderable, diff --git a/src/block-grey-damage.xcf b/src/block-grey-damage.xcf new file mode 100644 index 0000000000000000000000000000000000000000..728eb2d0746ed8132c9507aabdf8d6d15e869db5 GIT binary patch literal 20371 zcmeHvd0bRiw(dUXR27Aw;EY2I4$&mWQqx_DCMHHf5fpF$M1_j|89-JQO<-AQ-ijZv!VtoyBf3Mixaa{qe2Utg++Qg)siH^|R^qfhd5s}eDxg}V3P0vV5o7gRF zTDpVlxc9+lvvX!mofw+!oSN=k~l=H!J;<;LeB+Z&Q4UAAZ!^?ui3rtAuneUsA95(@p>siX*%Y%px zK73mrzJU)P>ca>4@PR&jLmxf}JdaoN@&m(T^Yx$c@*tuU^Mn^@M<3qTNKjq#QuAv# zQ06)Db@5Vn8noSS4Jz||%v3TXn`S!keI zNJn7~X$tzZ@C#`sOd)NBe@JuCR-!>j3(yv#VMt5RrXmQ`91g~gSUV;fo}s|1@9;M#v%ToPvKgDk~Y9~xa==!8xbgJD~!98TcKx=EC-;UhB^~u0-%$IYngFff7GkEmI=CA(O z_irg&@!wHJ*QP>`_)7rkU;4Ea)$Kl{>f)9`!V~bGZYGas-+h4b>=1EZao(dl`Tl`I zf9XpLxzF?zb4;Y)?a)fx?|PHy VKcucv~82yWQRp_Rx5Iogd+&AaDi9R1<5qgJ9 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 literal 1794 zcmds1%TB^T6rEy4ML~S7j2T}EEJ&ycYZokxi6;I+DWx<4O4_R6Mic+RtqYAS_wEdz zVf+l;Q_r1tlEJXS4GFh7bI*NEr?8wP{q6A*s{)&NbzvH>hs;UYjb z0UgKz+X<(pI@r2odF{5{31Kq|u2+5A4DC9XPIGOYfH zl^CU~jvI2fV>Ru7D!fJ`utP5L6&};kWID4V+HGviJ;!=}padnAy{2bfIyd{a&kv3% zm`XCz(A47y*du;&j}`9$AipR~I27Ag_>RIe3g-%6R``m-vkG4Yr~64+0HJ%+{znOi zVu!>d2=sx%)j5G%O6ox}XxRwb7m|94wOD10{O{7g%c4qdVhk%RSD9LAgac2AVZ?IO zPuT-?P{h|dO9Mhfr-=Td7_tG$farrUF}UCdxlSNjL@==D@8Bb;_(P+LZZBQ5?S j