A card game engine for TCGs, primarily Magic: The Gathering but with support for others
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Adding an events struct and text drawing

authored by

Cass Unterholzner and committed by
Tangled
842e55db f1d8b1d3

+71 -25
+11
game/events.go
··· 1 + package game 2 + 3 + type Event struct { 4 + eventType EventType 5 + callback func(game *Game) 6 + } 7 + 8 + type EventType int 9 + 10 + // reserved for event types 11 + const ()
+36 -18
game/game.go
··· 1 1 package game 2 2 3 3 import ( 4 + "bytes" 4 5 "image" 5 6 "image/color" 6 7 7 8 "github.com/hajimehoshi/ebiten/v2" 9 + "github.com/hajimehoshi/ebiten/v2/examples/resources/fonts" 10 + "github.com/hajimehoshi/ebiten/v2/text/v2" 8 11 ) 9 12 10 13 type Game struct { 11 - state GameState 12 - cards map[CardDefId]Card 13 - events []interface{} 14 + state GameState 15 + cards map[CardDefId]Card 16 + events []Event 17 + fontSource *text.GoTextFaceSource 18 + fontFace *text.GoTextFace 14 19 } 15 20 16 21 var ( 17 22 whiteImage = ebiten.NewImage(3, 3) 18 23 ) 19 24 20 - func NewGame(player_names []string) Game { 25 + func NewGame(player_names []string) (Game, error) { 21 26 whiteImage.Fill(color.White) 22 27 23 - return Game{ 24 - state: NewGameState(player_names), 25 - cards: make(map[CardDefId]Card), 26 - events: make([]interface{}, 0), 28 + fontSource, err := text.NewGoTextFaceSource(bytes.NewReader(fonts.MPlus1pRegular_ttf)) 29 + 30 + if err != nil { 31 + return Game{}, err 27 32 } 33 + 34 + game := Game{ 35 + state: NewGameState(player_names), 36 + cards: make(map[CardDefId]Card), 37 + events: make([]Event, 0), 38 + fontSource: fontSource, 39 + fontFace: &text.GoTextFace{ 40 + Source: fontSource, 41 + Size: 14, 42 + }, 43 + } 44 + 45 + return game, nil 28 46 } 29 47 30 48 func (g *Game) Update() error { ··· 50 68 op := &ebiten.DrawTrianglesOptions{} 51 69 op.Address = ebiten.AddressUnsafe 52 70 rectImage := whiteImage.SubImage(image.Rect(1, 1, 2, 2)).(*ebiten.Image) 53 - DrawRect(1770, 860, 150, 220, rectImage, screen, op, &area_labels[0]) // Command 54 - DrawRect(1620, 860, 150, 220, rectImage, screen, op, &area_labels[1]) // Exile 55 - DrawRect(1470, 860, 150, 220, rectImage, screen, op, &area_labels[2]) // Graveyard 56 - DrawRect(1320, 860, 150, 220, rectImage, screen, op, &area_labels[3]) // Library 57 - DrawRect(200, 860, 1120, 220, rectImage, screen, op, &area_labels[4]) // Hand 58 - DrawRect(0, 860, 200, 220, rectImage, screen, op, &area_labels[5]) // Resource Pool / Status Counters 59 - DrawRect(200, 0, 1720, 430, rectImage, screen, op, &area_labels[6]) // Battlefield (Lands) 60 - DrawRect(200, 430, 1720, 430, rectImage, screen, op, &area_labels[7]) // Battlefield (Non-Lands) 61 - DrawRect(0, 430, 200, 430, rectImage, screen, op, &area_labels[8]) // Life / Commander Damage 62 - DrawRect(0, 0, 200, 430, rectImage, screen, op, &area_labels[9]) // Player Name / Icon 71 + DrawRect(1770, 860, 150, 220, rectImage, screen, op, &area_labels[0], g.fontFace) // Command 72 + DrawRect(1620, 860, 150, 220, rectImage, screen, op, &area_labels[1], g.fontFace) // Exile 73 + DrawRect(1470, 860, 150, 220, rectImage, screen, op, &area_labels[2], g.fontFace) // Graveyard 74 + DrawRect(1320, 860, 150, 220, rectImage, screen, op, &area_labels[3], g.fontFace) // Library 75 + DrawRect(200, 860, 1120, 220, rectImage, screen, op, &area_labels[4], g.fontFace) // Hand 76 + DrawRect(0, 860, 200, 220, rectImage, screen, op, &area_labels[5], g.fontFace) // Resource Pool / Status Counters 77 + DrawRect(200, 430, 1720, 430, rectImage, screen, op, &area_labels[6], g.fontFace) // Battlefield (Lands) 78 + DrawRect(200, 0, 1720, 430, rectImage, screen, op, &area_labels[7], g.fontFace) // Battlefield (Non-Lands) 79 + DrawRect(0, 430, 200, 430, rectImage, screen, op, &area_labels[8], g.fontFace) // Life / Commander Damage 80 + DrawRect(0, 0, 200, 430, rectImage, screen, op, &area_labels[9], g.fontFace) // Player Name / Icon 63 81 } 64 82 65 83 func (g *Game) Layout(outsideWidth, outsideHeight int) (screenWidth, screenHeight int) {
+9 -6
game/utils.go
··· 1 1 package game 2 2 3 3 import ( 4 - "fmt" 5 - 6 4 "github.com/hajimehoshi/ebiten/v2" 5 + "github.com/hajimehoshi/ebiten/v2/text/v2" 7 6 ) 8 7 9 8 var ( ··· 13 12 } 14 13 ) 15 14 16 - func DrawRect(x, y, w, h int, image *ebiten.Image, screen *ebiten.Image, op *ebiten.DrawTrianglesOptions, text *string) { 15 + func DrawRect(x, y, w, h int, image *ebiten.Image, screen *ebiten.Image, op *ebiten.DrawTrianglesOptions, rectText *string, fontFace *text.GoTextFace) { 17 16 vertices := []ebiten.Vertex{ 18 17 { 19 18 DstX: float32(x), ··· 51 50 52 51 screen.DrawTriangles(vertices, indices, image, op) 53 52 54 - if text != nil { 55 - // draw text 56 - fmt.Printf("Drawing %s\n", *text) 53 + if rectText != nil { 54 + txtOp := &text.DrawOptions{} 55 + txtOp.GeoM.Translate((float64(w)/2.0)+float64(x), (float64(h)/2.0)+float64(y)) 56 + txtOp.ColorScale.SetR(0.0) 57 + txtOp.ColorScale.SetG(0.0) 58 + txtOp.ColorScale.SetB(0.0) 59 + text.Draw(screen, *rectText, fontFace, txtOp) 57 60 } 58 61 }
+4
go.mod
··· 8 8 github.com/ebitengine/gomobile v0.0.0-20250923094054-ea854a63cce1 // indirect 9 9 github.com/ebitengine/hideconsole v1.0.0 // indirect 10 10 github.com/ebitengine/purego v0.9.0 // indirect 11 + github.com/go-text/typesetting v0.3.0 // indirect 11 12 github.com/google/uuid v1.6.0 // indirect 12 13 github.com/jezek/xgb v1.1.1 // indirect 14 + github.com/rivo/uniseg v0.4.7 // indirect 15 + golang.org/x/image v0.31.0 // indirect 13 16 golang.org/x/sync v0.17.0 // indirect 14 17 golang.org/x/sys v0.36.0 // indirect 18 + golang.org/x/text v0.29.0 // indirect 15 19 )
+6
go.sum
··· 4 4 github.com/ebitengine/hideconsole v1.0.0/go.mod h1:hTTBTvVYWKBuxPr7peweneWdkUwEuHuB3C1R/ielR1A= 5 5 github.com/ebitengine/purego v0.9.0 h1:mh0zpKBIXDceC63hpvPuGLiJ8ZAa3DfrFTudmfi8A4k= 6 6 github.com/ebitengine/purego v0.9.0/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ= 7 + github.com/go-text/typesetting v0.3.0 h1:OWCgYpp8njoxSRpwrdd1bQOxdjOXDj9Rqart9ML4iF4= 8 + github.com/go-text/typesetting v0.3.0/go.mod h1:qjZLkhRgOEYMhU9eHBr3AR4sfnGJvOXNLt8yRAySFuY= 7 9 github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= 8 10 github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 9 11 github.com/hajimehoshi/ebiten/v2 v2.9.9 h1:JdDag6Ndj12iD4lxQGG8kbsrh7ssj4Sbzth6r929H/M= 10 12 github.com/hajimehoshi/ebiten/v2 v2.9.9/go.mod h1:DAt4tnkYYpCvu3x9i1X/nK/vOruNXIlYq/tBXxnhrXM= 11 13 github.com/jezek/xgb v1.1.1 h1:bE/r8ZZtSv7l9gk6nU0mYx51aXrvnyb44892TwSaqS4= 12 14 github.com/jezek/xgb v1.1.1/go.mod h1:nrhwO0FX/enq75I7Y7G8iN1ubpSGZEiA3v9e9GyRFlk= 15 + github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= 16 + github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= 13 17 golang.org/x/image v0.31.0 h1:mLChjE2MV6g1S7oqbXC0/UcKijjm5fnJLUYKIYrLESA= 14 18 golang.org/x/image v0.31.0/go.mod h1:R9ec5Lcp96v9FTF+ajwaH3uGxPH4fKfHHAVbUILxghA= 15 19 golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug= 16 20 golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= 17 21 golang.org/x/sys v0.36.0 h1:KVRy2GtZBrk1cBYA7MKu5bEZFxQk4NIDV6RLVcC8o0k= 18 22 golang.org/x/sys v0.36.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= 23 + golang.org/x/text v0.29.0 h1:1neNs90w9YzJ9BocxfsQNHKuAT4pkghyXc4nhZ6sJvk= 24 + golang.org/x/text v0.29.0/go.mod h1:7MhJOA9CD2qZyOKYazxdYMF85OwPdEr9jTtBpO7ydH4=
+5 -1
main.go
··· 18 18 log.Fatal(err) 19 19 } 20 20 21 - game := game.NewGame([]string{"Player 1", "Player 2", "Player 3", "Player 4"}) 21 + game, err := game.NewGame([]string{"Player 1", "Player 2", "Player 3", "Player 4"}) 22 + 23 + if err != nil { 24 + log.Fatal(err) 25 + } 22 26 23 27 if err := ebiten.RunGame(&game); err != nil { 24 28 log.Fatal(err)