everything I got

This commit is contained in:
MrDonuts
2023-11-19 20:53:35 -05:00
commit a875a4ed57
45 changed files with 903 additions and 0 deletions

11
.vscode/launch.json vendored Normal file
View File

@@ -0,0 +1,11 @@
{
"configurations": [
{
"name": "Launch Package",
"type": "go",
"request": "launch",
"mode": "auto",
"program": "${workspaceFolder}"
}
]
}

BIN
assets/.DS_Store vendored Normal file

Binary file not shown.

71
assets/audio.go Normal file
View File

@@ -0,0 +1,71 @@
package assets
import (
"bytes"
"embed"
"fmt"
"io/fs"
"log"
"github.com/hajimehoshi/ebiten/v2/audio"
"github.com/hajimehoshi/ebiten/v2/audio/wav"
)
//go:embed *
//go:embed */*
var embeddedFiles embed.FS
var sampleRate = 44100
var audioContext = audio.NewContext(sampleRate)
var songChoice = 2
var SongTracks = loadTracksForSong(songChoice)
func loadTracksForSong(sng int) map[int]*audio.Player {
tempMap := make(map[int]*audio.Player)
for i := 1; i <= 10; i++ {
tempMap[i] = LoadWavAudioFile(fmt.Sprintf("audio/song0%d/track%02d.wav", sng, i), true)
}
return tempMap
}
var SFXLibrary = map[string]*audio.Player{
"newLevel": LoadWavAudioFile("audio/portal2.wav", false),
"colourMatch": LoadWavAudioFile("audio/portal.wav", false),
"gameOver": LoadWavAudioFile("audio/gameOver.wav", false),
}
func LoadWavAudioFile(filePath string, loop bool) *audio.Player {
audioData, err := fs.ReadFile(embeddedFiles, filePath)
if err != nil {
log.Fatal(err)
}
stream, err := wav.DecodeWithSampleRate(sampleRate, bytes.NewReader(audioData))
if err != nil {
log.Fatalf("failed to decode audio: %v", err)
}
var player *audio.Player
if loop {
lengthOfAudioData := int64(len(audioData))
loopingStream := audio.NewInfiniteLoop(stream, lengthOfAudioData)
player, err = audioContext.NewPlayer(loopingStream)
} else {
player, err = audioContext.NewPlayer(stream)
}
if err != nil {
log.Fatal(err)
}
return player
}
func SilenceSongTracks() {
for _, song := range SongTracks {
song.SetVolume(0)
}
}

BIN
assets/audio/.DS_Store vendored Normal file

Binary file not shown.

BIN
assets/audio/gameOver.wav Normal file

Binary file not shown.

BIN
assets/audio/portal.wav Normal file

Binary file not shown.

BIN
assets/audio/portal2.wav Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
assets/audio/song02/.DS_Store vendored Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

37
assets/fonts.go Normal file
View File

@@ -0,0 +1,37 @@
package assets
import (
"embed"
"log"
"golang.org/x/image/font"
"golang.org/x/image/font/opentype"
)
//go:embed *
var FontFiles embed.FS
var fontFace font.Face
func LoadFontFace(fileName string, size float64) font.Face {
fontBytes, err := FontFiles.ReadFile(fileName)
if err != nil {
log.Fatal(err)
}
tt, err := opentype.Parse(fontBytes)
if err != nil {
log.Fatal(err)
}
const dpi = 144
fontFace, err = opentype.NewFace(tt, &opentype.FaceOptions{
Size: size,
DPI: dpi,
Hinting: font.HintingNone,
})
if err != nil {
log.Fatal(err)
}
return fontFace
}

BIN
assets/fonts/mechanical.otf Normal file

Binary file not shown.

BIN
assets/fonts/robot.otf Normal file

Binary file not shown.

182
geometry/grid.go Normal file
View File

@@ -0,0 +1,182 @@
package geom
import (
//"fmt"
"image/color"
"math/rand"
"github.com/hajimehoshi/ebiten/v2"
)
var defaultSquareSpacing = 5
var minBorder = 20
var ScoreOffset = 50
var HighScoreOffset = 10
var GameGrid Grid
var MaxGridDimension = 20
type Grid struct {
squareSpacing int
squares [][]Square
startX int
startY int
squareSize int
coloredSquaresRemaining int
}
// used for comparing two squares positions
type Pair struct {
rowNum int
colNum int
}
func (pr Pair) equal(pr2 Pair) bool {
return pr.rowNum == pr2.rowNum && pr.colNum == pr2.colNum
}
func pairAlreadyExists(pr Pair, pairs []Pair) bool {
result := false
for _, nextPair := range pairs {
if pr.equal(nextPair) {
return true
}
}
return result
}
func (grd *Grid) NumSquares() int {
size := -1
if len(grd.squares[0]) != 0 {
size = len(grd.squares) * len(grd.squares[0])
}
return size
}
// returns num rows by num columns
func (grd *Grid) Size() (int, int) {
if len(grd.squares[0]) != 0 {
return len(grd.squares), len(grd.squares[0])
}
return 0, 0
}
func BuildGrid(numRows int, numColumns int) {
grd := Grid{squareSpacing: defaultSquareSpacing}
winWidth, winHeight := ebiten.WindowSize()
sqSize := min((winWidth-2*minBorder-defaultSquareSpacing*numColumns)/numColumns, (winHeight-2*minBorder-ScoreOffset-3*HighScoreOffset-defaultSquareSpacing*numRows)/numRows)
sqSize = max(sqSize, 1) //ensure a nonzero, nonnegative square size
gridWidth := numColumns*(sqSize+grd.squareSpacing) - grd.squareSpacing
gridHeight := numRows*(sqSize+grd.squareSpacing) - grd.squareSpacing
currentX := (winWidth - gridWidth) / 2
currentY := ScoreOffset + (winHeight-gridHeight-ScoreOffset-HighScoreOffset)/2
grd.startX = currentX
grd.startY = currentY
grd.squareSize = sqSize
table := make([][]Square, numRows)
for i := 0; i < numRows; i++ {
row := make([]Square, numColumns)
for j := 0; j < numColumns; j++ {
sq := MakeSquare(sqSize)
sq.SetPosition(currentX, currentY)
row[j] = sq
currentX += sqSize + grd.squareSpacing
}
table[i] = row
currentY += sqSize + grd.squareSpacing
currentX = grd.startX
}
grd.squares = table
//assign random colours to a subset of all squares
squaresToColour := min(numColumns, numRows)
usedPositions := make([]Pair, squaresToColour)
coloredSoFar := 0
for i := 0; i < squaresToColour; i++ {
colourIndex := rand.Intn(len(LightRGBMap))
row := rand.Intn(numRows) + 1
col := rand.Intn(numColumns) + 1
//prevent a colour on the starting square
if row == numRows && col == 1 {
col = 2
}
//make sure we don't colour the same square twice
nextPair := Pair{rowNum: row, colNum: col}
if coloredSoFar == 0 {
usedPositions[0] = nextPair
coloredSoFar = 1
} else {
for pairAlreadyExists(nextPair, usedPositions) {
row = rand.Intn(numRows) + 1
col = rand.Intn(numColumns) + 1
//prevent a colour on the starting square
if row == numRows && col == 1 {
col = 2
}
nextPair = Pair{rowNum: row, colNum: col}
}
usedPositions[coloredSoFar] = nextPair
coloredSoFar += 1
}
grd.ChangeColour(row, col, LightRGBMap[colourIndex])
grd.GetSquareAt(row, col).RGBColourIndex = colourIndex
}
grd.coloredSquaresRemaining = squaresToColour
GameGrid = grd
}
func (grd *Grid) Draw(screen *ebiten.Image) {
opts := &ebiten.DrawImageOptions{}
for _, rowOfSquares := range grd.squares {
for _, sq := range rowOfSquares {
xPos := float64(sq.X())
yPos := float64(sq.Y())
opts.GeoM.Translate(xPos, yPos)
screen.DrawImage(sq.Img, opts)
opts.GeoM.Reset()
}
}
}
func (grd *Grid) DrawUpTo(finalSquareCount int, screen *ebiten.Image) {
opts := &ebiten.DrawImageOptions{}
curr := 1
for _, rowOfSquares := range grd.squares {
for _, sq := range rowOfSquares {
xPos := float64(sq.X())
yPos := float64(sq.Y())
opts.GeoM.Translate(xPos, yPos)
screen.DrawImage(sq.Img, opts)
opts.GeoM.Reset()
if curr == finalSquareCount {
return
}
curr++
}
}
}
func (grd *Grid) ChangeColour(row int, column int, clr color.Color) {
sq := grd.squares[row-1][column-1]
sq.ChangeColour(clr)
}
func (grd *Grid) GetSquareAt(row int, column int) *Square {
return &grd.squares[row-1][column-1]
}
func (grd *Grid) ColouredSquaresRemaining() int {
return grd.coloredSquaresRemaining
}

131
geometry/player.go Normal file
View File

@@ -0,0 +1,131 @@
package geom
import (
"image/color"
"github.com/hajimehoshi/ebiten/v2"
"github.com/hajimehoshi/ebiten/v2/inpututil"
"src.robn.tv/MrDonuts/RGB/assets"
)
var MainPlayer *Player
var totalColors = 3
var colorMap = map[int]color.Color{
0: RedFill,
1: GreenFill,
2: BlueFill,
}
var defaultStartingEnergy = 50
var nextLevelEnergyJump = 30
var CurrentEnergy = defaultStartingEnergy
var CurrentLevel = 1
type Player struct {
square Square
row int
col int
currColorIndex int
}
func SetupPlayer() {
rows, _ := GameGrid.Size()
//build default square
sq := MakeSquare(GameGrid.squareSize)
//adjust to red as starting value
sq.ChangeColour(RedFill)
//position on bottom left
gridSq := GameGrid.GetSquareAt(rows, 1)
sq.SetPosition(gridSq.x, gridSq.y)
//setup struct for passing around
ply := Player{square: sq, row: rows, col: 1, currColorIndex: 0}
MainPlayer = &ply
}
func (p *Player) Update() {
moveOccurs := false
if inpututil.IsKeyJustPressed(ebiten.KeyArrowDown) {
rows, _ := GameGrid.Size()
if p.row < rows {
p.row += 1
p.square.moveDownOnGrid()
moveOccurs = true
}
}
if inpututil.IsKeyJustPressed(ebiten.KeyArrowRight) {
_, cols := GameGrid.Size()
if p.col < cols {
p.col += 1
p.square.moveRightOnGrid()
moveOccurs = true
}
}
if inpututil.IsKeyJustPressed(ebiten.KeyArrowLeft) {
if p.col > 1 {
p.col -= 1
p.square.moveLeftOnGrid()
moveOccurs = true
}
}
if inpututil.IsKeyJustPressed(ebiten.KeyArrowUp) {
if p.row > 1 {
p.row -= 1
p.square.moveUpOnGrid()
moveOccurs = true
}
}
if moveOccurs {
moveOccurs = false
p.NextColor()
// check if player is on same colour square
gridSquare := GameGrid.GetSquareAt(p.row, p.col)
if p.currColorIndex == gridSquare.RGBColourIndex {
GameGrid.coloredSquaresRemaining -= 1
gridSquare.RGBColourIndex = -1
gridSquare.ChangeColour(GrayFill)
if GameGrid.coloredSquaresRemaining != 0 {
assets.SFXLibrary["colourMatch"].Rewind()
assets.SFXLibrary["colourMatch"].Play()
}
}
// reduce energy
CurrentEnergy -= 1
}
}
func (p *Player) Draw(screen *ebiten.Image) {
opts := &ebiten.DrawImageOptions{}
opts.GeoM.Translate(float64(p.square.x), float64(p.square.y))
screen.DrawImage(p.square.Img, opts)
}
func (p *Player) NextColor() {
p.currColorIndex = (p.currColorIndex + 1) % totalColors
p.square.ChangeColour(colorMap[p.currColorIndex])
}
func ResetPlayerValues() {
CurrentEnergy = defaultStartingEnergy
CurrentLevel = 1
}
func PrepareForNextLevel() {
CurrentEnergy += nextLevelEnergyJump
CurrentLevel += 1
}

93
geometry/square.go Normal file
View File

@@ -0,0 +1,93 @@
package geom
import (
"image/color"
"github.com/hajimehoshi/ebiten/v2"
)
var GrayFill = color.RGBA{R: 128, G: 128, B: 128, A: 255}
var RedFill = color.RGBA{R: 200, G: 0, B: 0, A: 255}
var GreenFill = color.RGBA{R: 0, G: 200, B: 0, A: 255}
var BlueFill = color.RGBA{R: 0, G: 0, B: 200, A: 255}
var LightRedFill = color.RGBA{R: 255, G: 104, B: 103, A: 255}
var LightGreenFill = color.RGBA{R: 144, G: 255, B: 143, A: 255}
var LightBlueFill = color.RGBA{R: 150, G: 150, B: 255, A: 255}
var RGBColourMap = map[int]color.Color{
0: RedFill,
1: GreenFill,
2: BlueFill,
}
var AllColourMap = map[int]color.Color{
0: GrayFill,
1: RedFill,
2: GreenFill,
3: BlueFill,
4: LightRedFill,
5: LightBlueFill,
6: LightGreenFill,
}
var LightRGBMap = map[int]color.Color{
0: LightRedFill,
1: LightGreenFill,
2: LightBlueFill,
}
type Square struct {
x int
y int
clr color.Color
width int
height int
Img *ebiten.Image
RGBColourIndex int
}
func MakeSquare(size int) Square {
image := ebiten.NewImage(size, size)
defaultColor := color.RGBA{R: 128, G: 128, B: 128, A: 255}
image.Fill(defaultColor)
sq := Square{clr: defaultColor, Img: image, width: size, height: size, x: 0, y: 0, RGBColourIndex: -1}
return sq
}
func (sq *Square) ChangeColour(newColor color.Color) {
sq.clr = newColor
sq.Img.Fill(newColor)
}
func (sq *Square) SetPosition(x int, y int) {
sq.x = x
sq.y = y
}
func (sq *Square) X() int {
return sq.x
}
func (sq *Square) Y() int {
return sq.y
}
func (sq *Square) moveRightOnGrid() {
newX := sq.x + GameGrid.squareSize + GameGrid.squareSpacing
sq.x = newX
}
func (sq *Square) moveLeftOnGrid() {
newX := sq.x - GameGrid.squareSize - GameGrid.squareSpacing
sq.x = newX
}
func (sq *Square) moveDownOnGrid() {
newY := sq.y + GameGrid.squareSize + GameGrid.squareSpacing
sq.y = newY
}
func (sq *Square) moveUpOnGrid() {
newY := sq.y - GameGrid.squareSize - GameGrid.squareSpacing
sq.y = newY
}

17
go.mod Normal file
View File

@@ -0,0 +1,17 @@
module src.robn.tv/MrDonuts/RGB
go 1.21.3
require github.com/hajimehoshi/ebiten/v2 v2.6.2
require (
github.com/ebitengine/oto/v3 v3.1.0 // indirect
github.com/ebitengine/purego v0.5.0 // indirect
github.com/jezek/xgb v1.1.0 // indirect
golang.org/x/exp/shiny v0.0.0-20230817173708-d852ddb80c63 // indirect
golang.org/x/image v0.14.0
golang.org/x/mobile v0.0.0-20230922142353-e2f452493d57 // indirect
golang.org/x/sync v0.3.0 // indirect
golang.org/x/sys v0.12.0 // indirect
golang.org/x/text v0.14.0 // indirect
)

22
go.sum Normal file
View File

@@ -0,0 +1,22 @@
github.com/ebitengine/oto/v3 v3.1.0 h1:9tChG6rizyeR2w3vsygTTTVVJ9QMMyu00m2yBOCch6U=
github.com/ebitengine/oto/v3 v3.1.0/go.mod h1:IK1QTnlfZK2GIB6ziyECm433hAdTaPpOsGMLhEyEGTg=
github.com/ebitengine/purego v0.5.0 h1:JrMGKfRIAM4/QVKaesIIT7m/UVjTj5GYhRSQYwfVdpo=
github.com/ebitengine/purego v0.5.0/go.mod h1:ah1In8AOtksoNK6yk5z1HTJeUkC1Ez4Wk2idgGslMwQ=
github.com/hajimehoshi/bitmapfont/v3 v3.0.0 h1:r2+6gYK38nfztS/et50gHAswb9hXgxXECYgE8Nczmi4=
github.com/hajimehoshi/bitmapfont/v3 v3.0.0/go.mod h1:+CxxG+uMmgU4mI2poq944i3uZ6UYFfAkj9V6WqmuvZA=
github.com/hajimehoshi/ebiten/v2 v2.6.2 h1:tVa3ZJbp4Uz/VSjmpgtQIOvwd7aQH290XehHBLr2iWk=
github.com/hajimehoshi/ebiten/v2 v2.6.2/go.mod h1:TZtorL713an00UW4LyvMeKD8uXWnuIuCPtlH11b0pgI=
github.com/jezek/xgb v1.1.0 h1:wnpxJzP1+rkbGclEkmwpVFQWpuE2PUGNUzP8SbfFobk=
github.com/jezek/xgb v1.1.0/go.mod h1:nrhwO0FX/enq75I7Y7G8iN1ubpSGZEiA3v9e9GyRFlk=
golang.org/x/exp/shiny v0.0.0-20230817173708-d852ddb80c63 h1:3AGKexOYqL+ztdWdkB1bDwXgPBuTS/S8A4WzuTvJ8Cg=
golang.org/x/exp/shiny v0.0.0-20230817173708-d852ddb80c63/go.mod h1:UH99kUObWAZkDnWqppdQe5ZhPYESUw8I0zVV1uWBR+0=
golang.org/x/image v0.14.0 h1:tNgSxAFe3jC4uYqvZdTr84SZoM1KfwdC9SKIFrLjFn4=
golang.org/x/image v0.14.0/go.mod h1:HUYqC05R2ZcZ3ejNQsIHQDQiwWM4JBqmm6MKANTp4LE=
golang.org/x/mobile v0.0.0-20230922142353-e2f452493d57 h1:Q6NT8ckDYNcwmi/bmxe+XbiDMXqMRW1xFBtJ+bIpie4=
golang.org/x/mobile v0.0.0-20230922142353-e2f452493d57/go.mod h1:wEyOn6VvNW7tcf+bW/wBz1sehi2s2BZ4TimyR7qZen4=
golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E=
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o=
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=

60
main.go Normal file
View File

@@ -0,0 +1,60 @@
package main
import (
"log"
"github.com/hajimehoshi/ebiten/v2"
"src.robn.tv/MrDonuts/RGB/assets"
geom "src.robn.tv/MrDonuts/RGB/geometry"
"src.robn.tv/MrDonuts/RGB/states"
score "src.robn.tv/MrDonuts/RGB/tools"
)
func init() {
numRows := 3
numColumns := 6
geom.BuildGrid(numRows, numColumns)
states.SetupStateMachine()
//some audio testing
for i, song := range assets.SongTracks {
song.Play()
if i != 1 {
song.SetVolume(0)
} else {
song.SetVolume(0.7)
}
}
}
type Game struct{}
func (g *Game) Update() error {
states.SM.Update()
score.ScoreMngr.Update()
return nil
}
func (g *Game) Draw(screen *ebiten.Image) {
states.SM.Draw(screen)
}
func (g *Game) Layout(outsideWidth, outsideHeight int) (screenWidth, screenHeight int) {
return 640, 480
}
func main() {
ebiten.SetWindowSize(640, 480)
ebiten.SetWindowTitle("RGB")
if err := ebiten.RunGame(&Game{}); err != nil {
log.Fatal(err)
}
}

57
states/gameOverState.go Normal file
View File

@@ -0,0 +1,57 @@
package states
import (
"fmt"
"image/color"
"math/rand"
"github.com/hajimehoshi/ebiten/v2"
"github.com/hajimehoshi/ebiten/v2/inpututil"
"github.com/hajimehoshi/ebiten/v2/text"
"golang.org/x/image/font"
"src.robn.tv/MrDonuts/RGB/assets"
geom "src.robn.tv/MrDonuts/RGB/geometry"
)
type GameOverState struct {
}
func (st *GameOverState) Enter() {
fmt.Println("Entering Game Over State")
assets.SilenceSongTracks()
assets.SFXLibrary["gameOver"].Rewind()
assets.SFXLibrary["gameOver"].Play()
}
func (st *GameOverState) Exit() {
fmt.Println("Exiting Game OverState")
}
func (st *GameOverState) Update() {
if inpututil.IsKeyJustPressed(ebiten.KeyN) {
geom.ResetPlayerValues()
geom.BuildGrid(rand.Intn(5+geom.CurrentLevel)+2, rand.Intn(5+geom.CurrentLevel)+2)
CurrTrack = 1
assets.SongTracks[CurrTrack].SetVolume(0.7) //turn up track 1
SM.Transition("load")
}
}
func (st *GameOverState) Draw(screen *ebiten.Image) {
w, h := ebiten.WindowSize()
gameOverStr := "Game Over"
face := assets.LoadFontFace("fonts/robot.otf", 30)
stringWidth := font.MeasureString(face, gameOverStr).Ceil()
text.Draw(screen, gameOverStr, face, w/2-stringWidth/2, h/2, color.White)
newGameStr := "(press N for new game)"
face = assets.LoadFontFace("fonts/robot.otf", 12)
stringWidth = font.MeasureString(face, newGameStr).Ceil()
text.Draw(screen, newGameStr, face, w/2-stringWidth/2, h-int(0.1*float64(h)), color.White)
}

52
states/loadLevelState.go Normal file
View File

@@ -0,0 +1,52 @@
package states
import (
"fmt"
"math"
"github.com/hajimehoshi/ebiten/v2"
geom "src.robn.tv/MrDonuts/RGB/geometry"
score "src.robn.tv/MrDonuts/RGB/tools"
)
var currentEnd = 1 //used for animating squares
var secondsPerUpdate = 0.02
var ticksPerSecond = 60.0
var deltaSeconds = 1.0 / ticksPerSecond
var secondsCounter = 0.0
type LoadLevelState struct {
}
func (s *LoadLevelState) Enter() {
fmt.Println("Entering Loading State")
currentEnd = 1
}
func (s *LoadLevelState) Exit() {
fmt.Println("Exiting Loading State")
}
func (s *LoadLevelState) Update() {
secondsCounter += deltaSeconds
//determine how much to jump by on each draw
totalSquares := geom.GameGrid.NumSquares()
jumpAmount := math.Ceil(float64(totalSquares) / ticksPerSecond)
if secondsCounter >= float64(secondsPerUpdate) {
secondsCounter = 0
currentEnd += int(jumpAmount)
}
if currentEnd > geom.GameGrid.NumSquares() {
SM.Transition("play")
}
}
func (s *LoadLevelState) Draw(screen *ebiten.Image) {
geom.GameGrid.DrawUpTo(currentEnd, screen)
score.ScoreMngr.Draw(screen)
}

71
states/playLevelState.go Normal file
View File

@@ -0,0 +1,71 @@
package states
import (
"fmt"
"math/rand"
"github.com/hajimehoshi/ebiten/v2"
"github.com/hajimehoshi/ebiten/v2/inpututil"
"src.robn.tv/MrDonuts/RGB/assets"
geom "src.robn.tv/MrDonuts/RGB/geometry"
score "src.robn.tv/MrDonuts/RGB/tools"
)
var CurrTrack = 1
type PlayLevelState struct {
}
func (s *PlayLevelState) Enter() {
fmt.Println("Entering Play State")
geom.SetupPlayer()
fmt.Println(geom.GameGrid.ColouredSquaresRemaining())
}
func (s *PlayLevelState) Exit() {
fmt.Println("Exiting Play State")
geom.PrepareForNextLevel()
if CurrTrack < len(assets.SongTracks) {
if geom.CurrentLevel%3 == 0 {
CurrTrack++
assets.SongTracks[CurrTrack].SetVolume(0.7)
}
}
}
func (s *PlayLevelState) Update() {
if inpututil.IsKeyJustPressed(ebiten.KeyN) {
newRowSize := min(rand.Intn(5+geom.CurrentLevel)+2, geom.MaxGridDimension)
newColSize := min(rand.Intn(5+geom.CurrentLevel)+2, geom.MaxGridDimension)
geom.BuildGrid(newRowSize, newColSize)
SM.Transition("load")
assets.SFXLibrary["newLevel"].Rewind()
assets.SFXLibrary["newLevel"].Play()
}
geom.MainPlayer.Update()
if geom.CurrentEnergy == 0 {
SM.Transition("game over")
}
if geom.GameGrid.ColouredSquaresRemaining() == 0 {
//go to next level
newRowSize := min(rand.Intn(5+geom.CurrentLevel)+2, geom.MaxGridDimension)
newColSize := min(rand.Intn(5+geom.CurrentLevel)+2, geom.MaxGridDimension)
geom.BuildGrid(newRowSize, newColSize)
SM.Transition("load")
assets.SFXLibrary["newLevel"].Rewind()
assets.SFXLibrary["newLevel"].Play()
}
}
func (s *PlayLevelState) Draw(screen *ebiten.Image) {
geom.GameGrid.Draw(screen)
geom.MainPlayer.Draw(screen)
score.ScoreMngr.Draw(screen)
}

54
states/statemachine.go Normal file
View File

@@ -0,0 +1,54 @@
package states
import (
"github.com/hajimehoshi/ebiten/v2"
)
var SM StateMachine
var StateMap map[string]State
type State interface {
Enter()
Exit()
Update()
Draw(screen *ebiten.Image)
}
type StateMachine struct {
CurrentState State
}
func NewStateMachine(initialState State) *StateMachine {
sm := &StateMachine{CurrentState: initialState}
sm.CurrentState.Enter()
return sm
}
func (sm *StateMachine) Transition(newState string) {
sm.CurrentState.Exit()
sm.CurrentState = StateMap[newState]
sm.CurrentState.Enter()
}
func (sm *StateMachine) Update() {
sm.CurrentState.Update()
}
func (sm *StateMachine) Draw(screen *ebiten.Image) {
sm.CurrentState.Draw(screen)
}
func SetupStateMachine() {
loadState := &LoadLevelState{}
playState := &PlayLevelState{}
gameOverState := &GameOverState{}
StateMap = make(map[string]State)
StateMap["load"] = loadState
StateMap["play"] = playState
StateMap["game over"] = gameOverState
SM = *NewStateMachine(loadState)
}

45
tools/scoreManager.go Normal file
View File

@@ -0,0 +1,45 @@
package score
import (
"fmt"
"image/color"
"github.com/hajimehoshi/ebiten/v2"
"github.com/hajimehoshi/ebiten/v2/text"
"golang.org/x/image/font"
//"golang.org/x/image/font/gofont/gobold"
"src.robn.tv/MrDonuts/RGB/assets"
geom "src.robn.tv/MrDonuts/RGB/geometry"
)
var ScoreMngr ScoreManager
type ScoreManager struct{}
func (sm *ScoreManager) Update() {
}
func (sm *ScoreManager) Draw(screen *ebiten.Image) {
w, h := ebiten.WindowSize()
//highScoreStr := fmt.Sprintf("High Score: %v", highScore)
levelStr := fmt.Sprintf("Level: %v", geom.CurrentLevel)
face := assets.LoadFontFace("fonts/robot.otf", 12)
//draw high score (i.e. best level)
//stringWidth := font.MeasureString(face, highScoreStr).Ceil()
//text.Draw(screen, highScoreStr, face, w-stringWidth-geom.HighScoreOffset, h-geom.HighScoreOffset, color.White)
//draw current level
//stringWidth = font.MeasureString(face, levelStr).Ceil()
text.Draw(screen, levelStr, face, geom.HighScoreOffset, h-geom.HighScoreOffset, color.White)
//draw energy at the top
energyStr := fmt.Sprintf("Energy: %v", geom.CurrentEnergy)
face = assets.LoadFontFace("fonts/robot.otf", 20)
stringWidth := font.MeasureString(face, energyStr).Ceil()
text.Draw(screen, energyStr, face, w/2-stringWidth/2, geom.ScoreOffset, color.White)
}