Initial commit
This commit is contained in:
commit
49b2e83e54
11 changed files with 353 additions and 0 deletions
18
go.mod
Normal file
18
go.mod
Normal file
|
@ -0,0 +1,18 @@
|
|||
module code.rocketnine.space/tslocum/twin-stick-ebiten
|
||||
|
||||
go 1.17
|
||||
|
||||
require (
|
||||
github.com/hajimehoshi/ebiten/v2 v2.2.2
|
||||
golang.org/x/image v0.0.0-20210628002857-a66eb6448b8d
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20210727001814-0db043d8d5be // indirect
|
||||
github.com/hajimehoshi/oto/v2 v2.1.0-alpha.2 // indirect
|
||||
github.com/jezek/xgb v0.0.0-20210312150743-0e0f116e1240 // indirect
|
||||
golang.org/x/exp v0.0.0-20190731235908-ec7cb31e5a56 // indirect
|
||||
golang.org/x/mobile v0.0.0-20210902104108-5d9a33257ab5 // indirect
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect
|
||||
golang.org/x/sys v0.0.0-20210917161153-d61c044b1678 // indirect
|
||||
)
|
68
go.sum
Normal file
68
go.sum
Normal file
|
@ -0,0 +1,68 @@
|
|||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20210727001814-0db043d8d5be h1:vEIVIuBApEBQTEJt19GfhoU+zFSV+sNTa9E9FdnRYfk=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20210727001814-0db043d8d5be/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
github.com/hajimehoshi/bitmapfont/v2 v2.1.3/go.mod h1:2BnYrkTQGThpr/CY6LorYtt/zEPNzvE/ND69CRTaHMs=
|
||||
github.com/hajimehoshi/ebiten/v2 v2.2.2 h1:92E+ogdNyH1P/LlvMQ7vonbFDh6bl+O7Ak+H1HX0RX8=
|
||||
github.com/hajimehoshi/ebiten/v2 v2.2.2/go.mod h1:olKl/qqhMBBAm2oI7Zy292nCtE+nitlmYKNF3UpbFn0=
|
||||
github.com/hajimehoshi/file2byteslice v0.0.0-20210813153925-5340248a8f41/go.mod h1:CqqAHp7Dk/AqQiwuhV1yT2334qbA/tFWQW0MD2dGqUE=
|
||||
github.com/hajimehoshi/go-mp3 v0.3.2/go.mod h1:qMJj/CSDxx6CGHiZeCgbiq2DSUkbK0UbtXShQcnfyMM=
|
||||
github.com/hajimehoshi/oto v0.6.1 h1:7cJz/zRQV4aJvMSSRqzN2TImoVVMpE0BCY4nrNJaDOM=
|
||||
github.com/hajimehoshi/oto v0.6.1/go.mod h1:0QXGEkbuJRohbJaxr7ZQSxnju7hEhseiPx2hrh6raOI=
|
||||
github.com/hajimehoshi/oto/v2 v2.1.0-alpha.2 h1:DV2DcbY3YLuLB9gI9R1GT9TPOo92lUeWveV8ci1sBLk=
|
||||
github.com/hajimehoshi/oto/v2 v2.1.0-alpha.2/go.mod h1:rUKQmwMkqmRxe+IAof9+tuYA2ofm8cAWXFmSfzDN8vQ=
|
||||
github.com/jakecoffman/cp v1.1.0/go.mod h1:JjY/Fp6d8E1CHnu74gWNnU0+b9VzEdUVPoJxg2PsTQg=
|
||||
github.com/jezek/xgb v0.0.0-20210312150743-0e0f116e1240 h1:dy+DS31tGEGCsZzB45HmJJNHjur8GDgtRNX9U7HnSX4=
|
||||
github.com/jezek/xgb v0.0.0-20210312150743-0e0f116e1240/go.mod h1:3P4UH/k22rXyHIJD2w4h2XMqPX4Of/eySEZq9L6wqc4=
|
||||
github.com/jfreymuth/oggvorbis v1.0.3/go.mod h1:1U4pqWmghcoVsCJJ4fRBKv9peUJMBHixthRlBeD6uII=
|
||||
github.com/jfreymuth/vorbis v1.0.2/go.mod h1:DoftRo4AznKnShRl1GxiTFCseHr4zR9BN3TWXyuzrqQ=
|
||||
github.com/pkg/browser v0.0.0-20180916011732-0a3d74bf9ce4/go.mod h1:4OwLy04Bl9Ef3GJJCoec+30X3LQs/0/m4HFRt/2LUSA=
|
||||
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190731235908-ec7cb31e5a56 h1:estk1glOnSVeJ9tdEZZc5mAMDZk5lNJNyJ6DvrBkTEU=
|
||||
golang.org/x/exp v0.0.0-20190731235908-ec7cb31e5a56/go.mod h1:JhuoJpWY28nO4Vef9tZUw9qufEGTyX1+7lmHxV5q5G4=
|
||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||
golang.org/x/image v0.0.0-20190703141733-d6a02ce849c9/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/image v0.0.0-20210628002857-a66eb6448b8d h1:RNPAfi2nHY7C2srAV8A49jpsYr0ADedCk1wq6fTMTvs=
|
||||
golang.org/x/image v0.0.0-20210628002857-a66eb6448b8d/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM=
|
||||
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
|
||||
golang.org/x/mobile v0.0.0-20190415191353-3e0bab5405d6/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
|
||||
golang.org/x/mobile v0.0.0-20210902104108-5d9a33257ab5 h1:peBP2oZO/xVnGMaWMCyFEI0WENsGj71wx5K12mRELHQ=
|
||||
golang.org/x/mobile v0.0.0-20210902104108-5d9a33257ab5/go.mod h1:c4YKU3ZylDmvbw+H/PSvm42vhdWbuxCzbonauEAP9B8=
|
||||
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
|
||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||
golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190429190828-d89cdac9e872/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210917161153-d61c044b1678 h1:J27LZFQBFoihqXoegpscI10HpjZ7B5WQLLKL2FZXQKw=
|
||||
golang.org/x/sys v0.0.0-20210917161153-d61c044b1678/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.6/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
33
step-1/game.go
Normal file
33
step-1/game.go
Normal file
|
@ -0,0 +1,33 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"github.com/hajimehoshi/ebiten/v2"
|
||||
"golang.org/x/image/colornames"
|
||||
)
|
||||
|
||||
// Game represents a twin-stick shooter game.
|
||||
type Game struct {
|
||||
}
|
||||
|
||||
// NewGame returns a new Game.
|
||||
func NewGame() *Game {
|
||||
return &Game{}
|
||||
}
|
||||
|
||||
// Layout is called by ebiten when the game starts, and every time the game state is updated.
|
||||
func (g *Game) Layout(width, height int) (int, int) {
|
||||
// Scale the size of the screen to support high-DPI displays.
|
||||
s := ebiten.DeviceScaleFactor()
|
||||
return int(s * float64(width)), int(s * float64(height))
|
||||
}
|
||||
|
||||
// Update is called by ebiten to update the game state.
|
||||
func (g *Game) Update() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Draw is called by ebiten to draw the game onto the screen.
|
||||
func (g *Game) Draw(screen *ebiten.Image) {
|
||||
// Fill the screen with a solid color.
|
||||
screen.Fill(colornames.Darkgreen)
|
||||
}
|
21
step-1/main.go
Normal file
21
step-1/main.go
Normal file
|
@ -0,0 +1,21 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
|
||||
"github.com/hajimehoshi/ebiten/v2"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// Set window title.
|
||||
ebiten.SetWindowTitle("Step 1 - Twin-stick shooter tutorial")
|
||||
|
||||
// Create a new game.
|
||||
game := NewGame()
|
||||
|
||||
// Run the game.
|
||||
err := ebiten.RunGame(game)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
BIN
step-2/assets/audio/bat.wav
Normal file
BIN
step-2/assets/audio/bat.wav
Normal file
Binary file not shown.
3
step-2/assets/image/bat/LICENSE
Normal file
3
step-2/assets/image/bat/LICENSE
Normal file
|
@ -0,0 +1,3 @@
|
|||
These sprites were created by Penusbmic.
|
||||
|
||||
https://penusbmic.itch.io/dungeon-enemy-pack-3
|
BIN
step-2/assets/image/bat/fly.png
Normal file
BIN
step-2/assets/image/bat/fly.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.7 KiB |
76
step-2/audio.go
Normal file
76
step-2/audio.go
Normal file
|
@ -0,0 +1,76 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"embed"
|
||||
"fmt"
|
||||
"log"
|
||||
"sync"
|
||||
|
||||
"github.com/hajimehoshi/ebiten/v2/audio"
|
||||
"github.com/hajimehoshi/ebiten/v2/audio/wav"
|
||||
)
|
||||
|
||||
//go:embed assets/audio
|
||||
var audioAssets embed.FS
|
||||
|
||||
type audioID int
|
||||
|
||||
type audioAtlas struct {
|
||||
ctx *audio.Context
|
||||
atlas map[audioID]*audio.Player
|
||||
sync.RWMutex
|
||||
}
|
||||
|
||||
func newAudioAtlas(ctx *audio.Context) *audioAtlas {
|
||||
return &audioAtlas{
|
||||
ctx: ctx,
|
||||
atlas: make(map[audioID]*audio.Player),
|
||||
}
|
||||
}
|
||||
|
||||
// loadWAV loads a WAV formatted audio file into the atlas.
|
||||
func (a *audioAtlas) loadWAV(id audioID, filePath string) error {
|
||||
f, err := audioAssets.Open("assets/audio/" + filePath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
stream, err := wav.DecodeWithSampleRate(a.ctx.SampleRate(), f)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
player, err := a.ctx.NewPlayer(stream)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Workaround to prevent delays when playing for the first time.
|
||||
player.SetVolume(0)
|
||||
player.Play()
|
||||
player.Pause()
|
||||
player.Rewind()
|
||||
player.SetVolume(1)
|
||||
|
||||
a.atlas[id] = player
|
||||
return nil
|
||||
}
|
||||
|
||||
// playAudio rewinds and starts an audio player from the atlas.
|
||||
func (a *audioAtlas) getAudio(id audioID) *audio.Player {
|
||||
return a.atlas[id]
|
||||
}
|
||||
|
||||
// playAudio rewinds and starts an audio player from the atlas.
|
||||
func (a *audioAtlas) playAudio(id audioID) error {
|
||||
player := a.getAudio(id)
|
||||
if player == nil {
|
||||
return fmt.Errorf("unknown audio ID %d", id)
|
||||
}
|
||||
log.Println(player)
|
||||
player.Pause()
|
||||
player.Rewind()
|
||||
player.Play()
|
||||
return nil
|
||||
}
|
65
step-2/game.go
Normal file
65
step-2/game.go
Normal file
|
@ -0,0 +1,65 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
|
||||
"github.com/hajimehoshi/ebiten/v2/inpututil"
|
||||
|
||||
"github.com/hajimehoshi/ebiten/v2"
|
||||
"github.com/hajimehoshi/ebiten/v2/audio"
|
||||
"golang.org/x/image/colornames"
|
||||
)
|
||||
|
||||
const sampleRate = 44100
|
||||
|
||||
// Game represents a twin-stick shooter game.
|
||||
type Game struct {
|
||||
audioAtlas *audioAtlas
|
||||
imageAtlas *imageAtlas
|
||||
}
|
||||
|
||||
// NewGame returns a new Game.
|
||||
func NewGame() *Game {
|
||||
ctx := audio.NewContext(sampleRate)
|
||||
|
||||
g := &Game{
|
||||
audioAtlas: newAudioAtlas(ctx),
|
||||
imageAtlas: newImageAtlas(),
|
||||
}
|
||||
|
||||
err := g.audioAtlas.loadWAV(1, "bat.wav")
|
||||
if err != nil {
|
||||
log.Fatal(err) // TODO
|
||||
}
|
||||
|
||||
err = g.imageAtlas.loadPNG(1, "bat/fly.png")
|
||||
if err != nil {
|
||||
log.Fatal(err) // TODO
|
||||
}
|
||||
|
||||
return g
|
||||
}
|
||||
|
||||
// Layout is called by ebiten when the game starts, and every time the game state is updated.
|
||||
func (g *Game) Layout(width, height int) (int, int) {
|
||||
// Scale the size of the screen to support high-DPI displays.
|
||||
s := ebiten.DeviceScaleFactor()
|
||||
return int(s * float64(width)), int(s * float64(height))
|
||||
}
|
||||
|
||||
// Update is called by ebiten to update the game state.
|
||||
func (g *Game) Update() error {
|
||||
if inpututil.IsKeyJustPressed(ebiten.KeyB) {
|
||||
err := g.audioAtlas.playAudio(1)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Draw is called by ebiten to draw the game onto the screen.
|
||||
func (g *Game) Draw(screen *ebiten.Image) {
|
||||
// Fill the screen with a solid color.
|
||||
screen.Fill(colornames.Darkgreen)
|
||||
}
|
48
step-2/image.go
Normal file
48
step-2/image.go
Normal file
|
@ -0,0 +1,48 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"embed"
|
||||
"image"
|
||||
_ "image/png"
|
||||
"sync"
|
||||
|
||||
"github.com/hajimehoshi/ebiten/v2"
|
||||
)
|
||||
|
||||
//go:embed assets/image
|
||||
var imageAssets embed.FS
|
||||
|
||||
type imageID int
|
||||
|
||||
type imageAtlas struct {
|
||||
atlas map[imageID]*ebiten.Image
|
||||
sync.RWMutex
|
||||
}
|
||||
|
||||
func newImageAtlas() *imageAtlas {
|
||||
return &imageAtlas{
|
||||
atlas: make(map[imageID]*ebiten.Image),
|
||||
}
|
||||
}
|
||||
|
||||
// loadWAV loads a WAV formatted audio file into the atlas.
|
||||
func (i *imageAtlas) loadPNG(id imageID, filePath string) error {
|
||||
f, err := imageAssets.Open("assets/image/" + filePath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
img, _, err := image.Decode(f)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
i.atlas[id] = ebiten.NewImageFromImage(img)
|
||||
return nil
|
||||
}
|
||||
|
||||
// playAudio rewinds and starts an audio player from the atlas.
|
||||
func (i *imageAtlas) getImage(id imageID) *ebiten.Image {
|
||||
return i.atlas[id]
|
||||
}
|
21
step-2/main.go
Normal file
21
step-2/main.go
Normal file
|
@ -0,0 +1,21 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
|
||||
"github.com/hajimehoshi/ebiten/v2"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// Set window title.
|
||||
ebiten.SetWindowTitle("Step 2 - Twin-stick shooter tutorial")
|
||||
|
||||
// Create a new game.
|
||||
game := NewGame()
|
||||
|
||||
// Run the game.
|
||||
err := ebiten.RunGame(game)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue