Skip to content

Commit 5b882a4

Browse files
committed
Port from sdl2 to ebitengine
1 parent 76d73ec commit 5b882a4

File tree

14 files changed

+718
-736
lines changed

14 files changed

+718
-736
lines changed

.gitignore

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
*.exe
22
lynsrd
33
coverage.out
4-
coverage.html
4+
coverage.html
5+
web/game.wasm
6+
web/wasm_exec.js

Makefile

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
1-
.PHONY: deps build run
1+
.PHONY: deps build run web serve
22

33
deps:
4-
brew list sdl2{,_mixer,_image,_ttf} || brew install sdl2{,_mixer,_image,_ttf}
54
go mod tidy
65

76
# -w -s reduces binary size by ~1.3MB
@@ -10,3 +9,10 @@ build:
109

1110
run:
1211
go run main.go
12+
13+
web:
14+
GOOS=js GOARCH=wasm go build -o web/game.wasm .
15+
cp "$$(go env GOROOT)/lib/wasm/wasm_exec.js" web/wasm_exec.js
16+
17+
serve:
18+
cd web && python3 -m http.server 8080

game/assets.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
package game
2+
3+
import "embed"
4+
5+
//go:embed maps/*.map maps/world.txt
6+
var AssetsFS embed.FS

game/game.go

Lines changed: 24 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,9 @@ package game
33
import (
44
"bufio"
55
"encoding/csv"
6+
"io/fs"
67
"math"
78
"math/rand"
8-
"os"
9-
"path/filepath"
109
"strconv"
1110
"strings"
1211
"time"
@@ -20,17 +19,25 @@ type Game struct {
2019
CurrentLevel *Level
2120
}
2221

23-
// NewGame needs to know how many channels to take in
24-
func NewGame(numWindows int) *Game {
22+
// NewGame needs to know how many channels to take in.
23+
// An optional fs.FS can be passed for testing; if nil, the embedded AssetsFS is used.
24+
func NewGame(numWindows int, filesystems ...fs.FS) *Game {
25+
var assetFS fs.FS
26+
if len(filesystems) > 0 && filesystems[0] != nil {
27+
assetFS = filesystems[0]
28+
} else {
29+
assetFS = AssetsFS
30+
}
31+
2532
levelChans := make([]chan *Level, numWindows) // 1 level channel for each window
2633
for i := range levelChans {
2734
levelChans[i] = make(chan *Level)
2835
}
2936
inputChan := make(chan *Input)
30-
levels := loadLevels()
37+
levels := loadLevels(assetFS)
3138

3239
game := &Game{levelChans, inputChan, levels, nil}
33-
game.loadWorldFile() // Load world file
40+
game.loadWorldFile(assetFS) // Load world file
3441
game.CurrentLevel.lineOfSight() // Draw visible tiles without moving
3542

3643
return game
@@ -392,11 +399,12 @@ func (level *Level) bresenham(start Pos, end Pos) {
392399
}
393400
}
394401

395-
func (game *Game) loadWorldFile() {
396-
file, err := os.Open("game/maps/world.txt")
402+
func (game *Game) loadWorldFile(assetFS fs.FS) {
403+
file, err := assetFS.Open("maps/world.txt")
397404
if err != nil {
398405
panic(err)
399406
}
407+
defer file.Close()
400408
csvReader := csv.NewReader(file)
401409
csvReader.FieldsPerRecord = -1 // Don't enforce each row to have same num columns
402410
csvReader.TrimLeadingSpace = true
@@ -447,7 +455,7 @@ func (game *Game) loadWorldFile() {
447455
}
448456

449457
// loadLevels opens and prints a map
450-
func loadLevels() map[string]*Level {
458+
func loadLevels(assetFS fs.FS) map[string]*Level {
451459
// Make player
452460
player := &Player{} // Player used to not be a pointer
453461
player.MaxStamina = 2
@@ -462,21 +470,18 @@ func loadLevels() map[string]*Level {
462470
player.PatternRNG = rand.New(rand.NewSource(time.Now().UnixNano()))
463471
levels := make(map[string]*Level)
464472
// Load level
465-
filenames, err := filepath.Glob("game/maps/*.map")
473+
entries, err := fs.ReadDir(assetFS, "maps")
466474
if err != nil {
467475
panic(err)
468476
}
469-
for _, filename := range filenames {
470-
extIndex := strings.LastIndex(filename, ".map")
471-
lastSlashIndexWindows := strings.LastIndex(filename, "\\") // Windows
472-
lastSlashIndexLinux := strings.LastIndex(filename, "/") // Linux
473-
lastSlashIndex := lastSlashIndexWindows
474-
if lastSlashIndexLinux > lastSlashIndexWindows {
475-
lastSlashIndex = lastSlashIndexLinux
477+
for _, entry := range entries {
478+
filename := entry.Name()
479+
if !strings.HasSuffix(filename, ".map") {
480+
continue
476481
}
477-
levelName := filename[lastSlashIndex+1 : extIndex]
482+
levelName := strings.TrimSuffix(filename, ".map")
478483
// Open file
479-
file, err := os.Open(filename)
484+
file, err := assetFS.Open("maps/" + filename)
480485
if err != nil {
481486
panic(err)
482487
}

game/game_test.go

Lines changed: 6 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,8 @@ import (
44
"fmt"
55
"math"
66
mrand "math/rand" // alias to avoid confusion with built-in rand
7-
"os"
8-
"path/filepath"
97
"testing"
8+
"testing/fstest"
109
"time"
1110
)
1211

@@ -1038,42 +1037,14 @@ func minInt(a, b int) int {
10381037
}
10391038

10401039
func TestNewGame(t *testing.T) {
1041-
// Create a temporary directory for test files
1042-
tmpDir := t.TempDir()
1043-
1044-
// Create the game/maps directory structure
1045-
mapsDir := filepath.Join(tmpDir, "game", "maps")
1046-
if err := os.MkdirAll(mapsDir, 0755); err != nil {
1047-
t.Fatalf("Failed to create maps directory: %v", err)
1048-
}
1049-
1050-
// Create a test world.txt file
1051-
worldContent := "test_level"
1052-
worldPath := filepath.Join(mapsDir, "world.txt")
1053-
if err := os.WriteFile(worldPath, []byte(worldContent), 0644); err != nil {
1054-
t.Fatalf("Failed to write world.txt: %v", err)
1055-
}
1056-
1057-
// Create a test map file
1058-
mapContent := "####\n#@.#\n####"
1059-
mapPath := filepath.Join(mapsDir, "test_level.map")
1060-
if err := os.WriteFile(mapPath, []byte(mapContent), 0644); err != nil {
1061-
t.Fatalf("Failed to write test_level.map: %v", err)
1062-
}
1063-
1064-
// Save the original working directory and switch to the temp dir
1065-
oldWd, err := os.Getwd()
1066-
if err != nil {
1067-
t.Fatalf("Failed to get current working directory: %v", err)
1068-
}
1069-
defer os.Chdir(oldWd) // Ensure we revert to the original directory after the test
1070-
1071-
if err := os.Chdir(tmpDir); err != nil {
1072-
t.Fatalf("Failed to change working directory: %v", err)
1040+
// Create an in-memory filesystem for test data
1041+
testFS := fstest.MapFS{
1042+
"maps/test_level.map": &fstest.MapFile{Data: []byte("####\n#@.#\n####")},
1043+
"maps/world.txt": &fstest.MapFile{Data: []byte("test_level")},
10731044
}
10741045

10751046
// Now initialize the game which should use our test files
1076-
game := NewGame(1)
1047+
game := NewGame(1, testFS)
10771048
if game == nil {
10781049
t.Fatal("NewGame returned nil")
10791050
}

go.mod

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,19 @@ module github.com/maxproske/lyns-rhythm-dungeon
22

33
go 1.24.0
44

5-
require github.com/veandco/go-sdl2 v0.4.40
5+
require github.com/hajimehoshi/ebiten/v2 v2.8.6
6+
7+
require (
8+
github.com/ebitengine/gomobile v0.0.0-20240911145611-4856209ac325 // indirect
9+
github.com/ebitengine/hideconsole v1.0.0 // indirect
10+
github.com/ebitengine/oto/v3 v3.3.2 // indirect
11+
github.com/ebitengine/purego v0.8.0 // indirect
12+
github.com/go-text/typesetting v0.2.0 // indirect
13+
github.com/jezek/xgb v1.1.1 // indirect
14+
github.com/jfreymuth/oggvorbis v1.0.5 // indirect
15+
github.com/jfreymuth/vorbis v1.0.2 // indirect
16+
golang.org/x/image v0.20.0 // indirect
17+
golang.org/x/sync v0.8.0 // indirect
18+
golang.org/x/sys v0.25.0 // indirect
19+
golang.org/x/text v0.18.0 // indirect
20+
)

go.sum

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,32 @@
1-
github.com/veandco/go-sdl2 v0.4.40 h1:fZv6wC3zz1Xt167P09gazawnpa0KY5LM7JAvKpX9d/U=
2-
github.com/veandco/go-sdl2 v0.4.40/go.mod h1:OROqMhHD43nT4/i9crJukyVecjPNYYuCofep6SNiAjY=
1+
github.com/ebitengine/gomobile v0.0.0-20240911145611-4856209ac325 h1:Gk1XUEttOk0/hb6Tq3WkmutWa0ZLhNn/6fc6XZpM7tM=
2+
github.com/ebitengine/gomobile v0.0.0-20240911145611-4856209ac325/go.mod h1:ulhSQcbPioQrallSuIzF8l1NKQoD7xmMZc5NxzibUMY=
3+
github.com/ebitengine/hideconsole v1.0.0 h1:5J4U0kXF+pv/DhiXt5/lTz0eO5ogJ1iXb8Yj1yReDqE=
4+
github.com/ebitengine/hideconsole v1.0.0/go.mod h1:hTTBTvVYWKBuxPr7peweneWdkUwEuHuB3C1R/ielR1A=
5+
github.com/ebitengine/oto/v3 v3.3.2 h1:VTWBsKX9eb+dXzaF4jEwQbs4yWIdXukJ0K40KgkpYlg=
6+
github.com/ebitengine/oto/v3 v3.3.2/go.mod h1:MZeb/lwoC4DCOdiTIxYezrURTw7EvK/yF863+tmBI+U=
7+
github.com/ebitengine/purego v0.8.0 h1:JbqvnEzRvPpxhCJzJJ2y0RbiZ8nyjccVUrSM3q+GvvE=
8+
github.com/ebitengine/purego v0.8.0/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ=
9+
github.com/go-text/typesetting v0.2.0 h1:fbzsgbmk04KiWtE+c3ZD4W2nmCRzBqrqQOvYlwAOdho=
10+
github.com/go-text/typesetting v0.2.0/go.mod h1:2+owI/sxa73XA581LAzVuEBZ3WEEV2pXeDswCH/3i1I=
11+
github.com/go-text/typesetting-utils v0.0.0-20240317173224-1986cbe96c66 h1:GUrm65PQPlhFSKjLPGOZNPNxLCybjzjYBzjfoBGaDUY=
12+
github.com/go-text/typesetting-utils v0.0.0-20240317173224-1986cbe96c66/go.mod h1:DDxDdQEnB70R8owOx3LVpEFvpMK9eeH1o2r0yZhFI9o=
13+
github.com/hajimehoshi/bitmapfont/v3 v3.2.0 h1:0DISQM/rseKIJhdF29AkhvdzIULqNIIlXAGWit4ez1Q=
14+
github.com/hajimehoshi/bitmapfont/v3 v3.2.0/go.mod h1:8gLqGatKVu0pwcNCJguW3Igg9WQqVXF0zg/RvrGQWyg=
15+
github.com/hajimehoshi/ebiten/v2 v2.8.6 h1:Dkd/sYI0TYyZRCE7GVxV59XC+WCi2BbGAbIBjXeVC1U=
16+
github.com/hajimehoshi/ebiten/v2 v2.8.6/go.mod h1:cCQ3np7rdmaJa1ZnvslraVlpxNb3wCjEnAP1LHNyXNA=
17+
github.com/jezek/xgb v1.1.1 h1:bE/r8ZZtSv7l9gk6nU0mYx51aXrvnyb44892TwSaqS4=
18+
github.com/jezek/xgb v1.1.1/go.mod h1:nrhwO0FX/enq75I7Y7G8iN1ubpSGZEiA3v9e9GyRFlk=
19+
github.com/jfreymuth/oggvorbis v1.0.5 h1:u+Ck+R0eLSRhgq8WTmffYnrVtSztJcYrl588DM4e3kQ=
20+
github.com/jfreymuth/oggvorbis v1.0.5/go.mod h1:1U4pqWmghcoVsCJJ4fRBKv9peUJMBHixthRlBeD6uII=
21+
github.com/jfreymuth/vorbis v1.0.2 h1:m1xH6+ZI4thH927pgKD8JOH4eaGRm18rEE9/0WKjvNE=
22+
github.com/jfreymuth/vorbis v1.0.2/go.mod h1:DoftRo4AznKnShRl1GxiTFCseHr4zR9BN3TWXyuzrqQ=
23+
github.com/pierrec/lz4/v4 v4.1.21 h1:yOVMLb6qSIDP67pl/5F7RepeKYu/VmTyEXvuMI5d9mQ=
24+
github.com/pierrec/lz4/v4 v4.1.21/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
25+
golang.org/x/image v0.20.0 h1:7cVCUjQwfL18gyBJOmYvptfSHS8Fb3YUDtfLIZ7Nbpw=
26+
golang.org/x/image v0.20.0/go.mod h1:0a88To4CYVBAHp5FXJm8o7QbUl37Vd85ply1vyD8auM=
27+
golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
28+
golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
29+
golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34=
30+
golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
31+
golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224=
32+
golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=

main.go

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,19 @@
11
package main
22

33
import (
4-
"runtime"
5-
4+
"github.com/hajimehoshi/ebiten/v2"
65
"github.com/maxproske/lyns-rhythm-dungeon/game"
76
"github.com/maxproske/lyns-rhythm-dungeon/ui2d"
87
)
98

109
func main() {
11-
// Make new game
12-
game := game.NewGame(1)
13-
go game.Run()
10+
g := game.NewGame(1)
11+
go g.Run()
1412

15-
// Make our UI
16-
runtime.LockOSThread()
17-
ui := ui2d.NewUI(game.InputChan, game.LevelChans[0])
18-
ui.Run()
13+
ebiten.SetWindowSize(780, 480)
14+
ebiten.SetWindowTitle("Lyn's Rhythm Dungeon")
15+
ui := ui2d.NewUI(g.InputChan, g.LevelChans[0])
16+
if err := ebiten.RunGame(ui); err != nil {
17+
panic(err)
18+
}
1919
}

ui2d/assets.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package ui2d
2+
3+
import "embed"
4+
5+
//go:embed assets/tiles.png assets/noteskin.png
6+
//go:embed assets/atlas-index.txt assets/noteskin-index.txt
7+
//go:embed assets/gothic.ttf
8+
//go:embed assets/dungeon-theme.ogg assets/hitsound.ogg
9+
//go:embed assets/doorOpen_1.ogg assets/doorOpen_2.ogg
10+
//go:embed assets/footstep00.ogg assets/footstep01.ogg assets/footstep02.ogg assets/footstep03.ogg assets/footstep04.ogg
11+
//go:embed assets/footstep05.ogg assets/footstep06.ogg assets/footstep07.ogg assets/footstep08.ogg assets/footstep09.ogg
12+
var assetsFS embed.FS

0 commit comments

Comments
 (0)