diff --git a/asesprite.org b/asesprite.org new file mode 100644 index 0000000..cf478af --- /dev/null +++ b/asesprite.org @@ -0,0 +1,23 @@ +| key | sub key | function | hint | +|--------------+------------+-----------------------+----------------------------------| +| b | | brush | | +| | d | draw | | +| | s | shape | select color range before | +| | x | switch color order | | +| | a | alpha shape | | +| | ctrl+wheel | brush size | | +| c | | pick color | | +| e | | erase | | +| z | | zoom | click and drag, left+right click | +| middle mouse | | move canvas | | +| f | | fill | inside selection | +| ctrl-d | | no selection | | +| m | | marquee | rect selection | +| w | | select by color | contiguous: all or only region | +| q | | lasso select | | +| tab | | hide/show layers | | +| v | | switch layer | by click on region | +| alt-n | | new frame | | +| shift-n | | new layer | | +| ctrl-f | | hide/show ui elements | | +| shift-o | | outline tool | | diff --git a/assets/levels/openquell.ldtk b/assets/levels/openquell.ldtk index fdb99a6..ad85207 100644 --- a/assets/levels/openquell.ldtk +++ b/assets/levels/openquell.ldtk @@ -6096,7 +6096,15 @@ "height": 32, "defUid": 65, "px": [224,224], - "fieldInstances": [{ "__identifier": "Entity_ref", "__type": "EntityRef", "__value": null, "__tile": null, "defUid": 68, "realEditorValues": [] }], + "fieldInstances": [{ "__identifier": "Entity_ref", "__type": "EntityRef", "__value": { + "entityIid": "7d975370-d7b0-11ee-9add-971995295000", + "layerIid": "50624190-d7b0-11ee-968e-3dbcbdc42f40", + "levelIid": "50621a80-d7b0-11ee-968e-a98c2d35fbdb", + "worldIid": "267ee1a0-d7b0-11ee-a97e-53f0a359eae1" + }, "__tile": null, "defUid": 68, "realEditorValues": [{ + "id": "V_String", + "params": ["7d975370-d7b0-11ee-9add-971995295000"] + }] }], "__worldX": 0, "__worldY": 2976 }, diff --git a/assets/loader-levels.go b/assets/loader-levels.go index e44b982..2dc1893 100644 --- a/assets/loader-levels.go +++ b/assets/loader-levels.go @@ -240,8 +240,8 @@ func InitTiles() TileRegistry { "HiddenDoor11": NewTileHiddenDoor("block-greycolored", "damage"), "HiddenDoor12": NewTileHiddenDoor("block-greycolored", "damage"), "HiddenDoor13": NewTileHiddenDoor("block-greycolored", "damage"), - "Switch": NewTileSwitch([]string{"switch-open.png", "switch-closed.png"}), - "Door": NewTileDoor([]string{"door-open.png", "door-closed.png"}), + "Switch": NewTileSwitch([]string{"switch1", "switch2"}), + "Door": NewTileDoor([]string{"door1", "door2"}), } } diff --git a/assets/sprites/door-closed.png b/assets/sprites/door-closed.png deleted file mode 100644 index a2eb837..0000000 Binary files a/assets/sprites/door-closed.png and /dev/null differ diff --git a/assets/sprites/door-open.png b/assets/sprites/door-open.png deleted file mode 100644 index dcc664d..0000000 Binary files a/assets/sprites/door-open.png and /dev/null differ diff --git a/assets/sprites/door.ase b/assets/sprites/door.ase index dc486ea..53e8bf8 100644 Binary files a/assets/sprites/door.ase and b/assets/sprites/door.ase differ diff --git a/assets/sprites/door1.png b/assets/sprites/door1.png new file mode 100644 index 0000000..25a6cfc Binary files /dev/null and b/assets/sprites/door1.png differ diff --git a/assets/sprites/door2.png b/assets/sprites/door2.png new file mode 100644 index 0000000..cac227a Binary files /dev/null and b/assets/sprites/door2.png differ diff --git a/assets/sprites/entitymap.png b/assets/sprites/entitymap.png index aa7aa95..1355958 100644 Binary files a/assets/sprites/entitymap.png and b/assets/sprites/entitymap.png differ diff --git a/assets/sprites/switch-closed.png b/assets/sprites/switch-closed.png deleted file mode 100644 index 524c457..0000000 Binary files a/assets/sprites/switch-closed.png and /dev/null differ diff --git a/assets/sprites/switch-open.png b/assets/sprites/switch-open.png deleted file mode 100644 index b75df7b..0000000 Binary files a/assets/sprites/switch-open.png and /dev/null differ diff --git a/assets/sprites/switch.ase b/assets/sprites/switch.ase index 6a42ed6..bec786b 100644 Binary files a/assets/sprites/switch.ase and b/assets/sprites/switch.ase differ diff --git a/assets/sprites/switch1.png b/assets/sprites/switch1.png new file mode 100644 index 0000000..588e786 Binary files /dev/null and b/assets/sprites/switch1.png differ diff --git a/assets/sprites/switch2.png b/assets/sprites/switch2.png new file mode 100644 index 0000000..af512af Binary files /dev/null and b/assets/sprites/switch2.png differ diff --git a/components/pairs.go b/components/pairs.go index 266fe82..f8af2e2 100644 --- a/components/pairs.go +++ b/components/pairs.go @@ -23,11 +23,15 @@ type Door struct { Id string } -func (door *Door) Open() *ebiten.Image { - return door.OpenSprite +func (door *Door) Toggle() { + door.IsOpen = !door.IsOpen } -func (door *Door) Close() *ebiten.Image { +func (door *Door) Sprite() *ebiten.Image { + if door.IsOpen { + return door.OpenSprite + } + return door.CloseSprite } @@ -39,3 +43,15 @@ type Switch struct { CloseSprite *ebiten.Image Ref string // the IId of the door } + +func (switcher *Switch) Toggle() { + switcher.IsOpen = !switcher.IsOpen +} + +func (switcher *Switch) Sprite() *ebiten.Image { + if switcher.IsOpen { + return switcher.OpenSprite + } + + return switcher.CloseSprite +} diff --git a/game/levels.go b/game/levels.go index 8369b42..f91cdb3 100644 --- a/game/levels.go +++ b/game/levels.go @@ -55,6 +55,8 @@ func NewLevel(game *Game, cellsize int, plan *ldtkgo.Level) *Level { systemlist = append(systemlist, systems.NewDestroyableSystem(game.World, gridcontainer, game.Cellsize)) + systemlist = append(systemlist, systems.NewPairSystem(game.World, gridcontainer)) + systemlist = append(systemlist, systems.NewHudSystem(game.World, plan)) mapslice, backupmap := LevelToSlice(game, plan, cellsize) @@ -176,11 +178,15 @@ func LevelToSlice(game *Game, level *ldtkgo.Level, tilesize int) (Map, Map) { if ref.Value != nil { refid := ref.Value.(map[string]interface{}) tile.Ref = refid["entityIid"].(string) + slog.Debug("LOAD TILE", "tileref", + tile.Ref, "tileid", tile.Id, + "name", entity.Identifier, + "isswitch", tile.Switch, + "isdoor", tile.Door, + ) } } - slog.Debug("LOAD TILE", "tile", entity.TileRect) - tileRect := entity.TileRect tile.Sprite = tileset.SubImage( diff --git a/grid/grid.go b/grid/grid.go index 5ba4e58..0626f6f 100644 --- a/grid/grid.go +++ b/grid/grid.go @@ -8,8 +8,6 @@ import ( "openquell/config" "openquell/observers" - "log/slog" - "github.com/mlange-42/arche/ecs" "github.com/mlange-42/arche/generic" ) @@ -141,16 +139,16 @@ func NewGrid(world *ecs.World, case tile.Switch: entity := switchmapper.New() pos, render, _, switcher = switchmapper.Get(entity) - switcher.OpenSprite = tile.Tiles[0] switcher.CloseSprite = tile.Tiles[0] + switcher.OpenSprite = tile.Tiles[1] switcher.Ref = tile.Ref switches = append(switches, entity) case tile.Door: entity := doormapper.New() pos, render, _, door = doormapper.Get(entity) - door.OpenSprite = tile.Tiles[0] door.CloseSprite = tile.Tiles[0] + door.OpenSprite = tile.Tiles[1] door.Id = tile.Id doors = append(doors, entity) @@ -176,17 +174,19 @@ func NewGrid(world *ecs.World, pos.Update(point.X*tilesize, point.Y*tilesize, tilesize) } + // check for switch->door references for _, switchentity := range switches { _, _, bond, switcher = switchmapper.Get(switchentity) if switcher.Ref != "" { + // this switch has a reference for _, doorentity := range doors { _, _, _, door = doormapper.Get(doorentity) if door.Id == switcher.Ref { + // the switch reference matches the door id, relate the two bond.Ref = switcher.Ref relID := ecs.ComponentID[components.Bond](world) - world.Relations().Set(doorentity, relID, switchentity) - slog.Debug("setup switch/door reference") + world.Relations().Set(switchentity, relID, doorentity) } } } diff --git a/src/entitymap.xcf b/src/entitymap.xcf index 71f4f68..1cd1095 100644 Binary files a/src/entitymap.xcf and b/src/entitymap.xcf differ diff --git a/systems/pair_system.go b/systems/pair_system.go new file mode 100644 index 0000000..37d8276 --- /dev/null +++ b/systems/pair_system.go @@ -0,0 +1,117 @@ +package systems + +import ( + "openquell/components" + . "openquell/components" + . "openquell/config" + "openquell/grid" + "openquell/observers" + + "github.com/hajimehoshi/ebiten/v2" + "github.com/mlange-42/arche/ecs" + "github.com/mlange-42/arche/generic" +) + +type PairSystem struct { + World *ecs.World + DoorSelector *generic.Filter4[Position, Renderable, Bond, Door] + SwitchSelector *generic.Filter4[Position, Renderable, Bond, Switch] + GridContainer *grid.GridContainer + DoorMapper generic.Map4[ + components.Position, + components.Renderable, + components.Bond, + components.Door] +} + +type ToggleDoor struct { + Entity ecs.Entity + Open bool +} + +func NewPairSystem(world *ecs.World, gridcontainer *grid.GridContainer) System { + doormapper := generic.NewMap4[ + components.Position, + components.Renderable, + components.Bond, + components.Door](world) + + system := &PairSystem{ + DoorSelector: generic.NewFilter4[Position, Renderable, Bond, Door](), + SwitchSelector: generic.NewFilter4[Position, Renderable, Bond, Switch](), + World: world, + GridContainer: gridcontainer, + DoorMapper: doormapper, + } + + return system +} + +func (system *PairSystem) Update() error { + observer := observers.GetGameObserver(system.World) + posID := ecs.ComponentID[components.Position](system.World) + veloID := ecs.ComponentID[components.Velocity](system.World) + + query := system.SwitchSelector.Query(system.World) + relID := ecs.ComponentID[Bond](system.World) + + EntitiesToSwitch := []*ToggleDoor{} + + for query.Next() { + swpos, _, _, switcher := query.Get() + + for _, player := range observer.GetPlayers() { + if !system.World.Alive(player) { + continue + } + + playerposition := (*Position)(system.World.Get(player, posID)) + playervelocity := (*Velocity)(system.World.Get(player, veloID)) + + ok, newpos := swpos.Intersects(playerposition, playervelocity) + if ok { + // player moved on top of the switch + switcher.Toggle() + // open door + door := system.World.Relations().Get(query.Entity(), relID) + EntitiesToSwitch = append(EntitiesToSwitch, + &ToggleDoor{Entity: door, Open: true}) + + playervelocity.Change(Stop) + playerposition.Set(newpos) + + } + } + } + + for _, toggle := range EntitiesToSwitch { + _, _, _, door := system.DoorMapper.Get(toggle.Entity) + door.Toggle() + } + + return nil +} + +func (system *PairSystem) Draw(screen *ebiten.Image) { + op := &ebiten.DrawImageOptions{} + query := system.SwitchSelector.Query(system.World) + + for query.Next() { + pos, _, _, switcher := query.Get() + + op.GeoM.Reset() + op.GeoM.Translate(float64(pos.X), float64(pos.Y)) + screen.DrawImage(switcher.Sprite(), op) + } + + doorquery := system.DoorSelector.Query(system.World) + + for doorquery.Next() { + pos, _, _, door := doorquery.Get() + + op.GeoM.Reset() + op.GeoM.Translate(float64(pos.X), float64(pos.Y)) + screen.DrawImage(door.Sprite(), op) + } + +}