268 lines
5.9 KiB
Go
268 lines
5.9 KiB
Go
package game
|
|
|
|
import (
|
|
"ducky/assets"
|
|
"ducky/elements"
|
|
"ducky/fonts"
|
|
"ducky/gamedata"
|
|
"fmt"
|
|
"image/color"
|
|
"math"
|
|
"math/rand"
|
|
|
|
"github.com/hajimehoshi/ebiten/v2"
|
|
"github.com/hajimehoshi/ebiten/v2/audio"
|
|
"github.com/hajimehoshi/ebiten/v2/inpututil"
|
|
"github.com/hajimehoshi/ebiten/v2/text/v2"
|
|
)
|
|
|
|
const (
|
|
screenWidth = 640
|
|
screenHeight = 480
|
|
|
|
duckyWidth = 32
|
|
duckyHeight = duckyWidth
|
|
|
|
spotResetDuration = 120
|
|
duckySpottedTextOffsetX = 120
|
|
duckySpottedTextOffsetY = 32
|
|
duckySpottedTextSize = 30
|
|
toastCount = 120
|
|
)
|
|
|
|
var (
|
|
audioContext = audio.NewContext(assets.SampleRate)
|
|
)
|
|
|
|
type Game struct {
|
|
initialized bool
|
|
reducky *elements.Ducky
|
|
ducky *elements.Ducky
|
|
spotlight *elements.Spotlight
|
|
cycle int
|
|
mousepos gamedata.Coordinates
|
|
|
|
darkness *ebiten.Image
|
|
offscreen *ebiten.Image
|
|
|
|
reduckycol int
|
|
reduckyrow int
|
|
|
|
spottedticks int
|
|
spotted bool
|
|
toast bool
|
|
toastcounter int
|
|
disabledarkness bool
|
|
|
|
sliders []*elements.Slider
|
|
|
|
reachcount int
|
|
|
|
musicInitialized bool
|
|
audioplayer *audio.Player
|
|
}
|
|
|
|
func (g *Game) Update() error {
|
|
|
|
g.HandleInput()
|
|
|
|
if !g.initialized {
|
|
g.Initialize()
|
|
}
|
|
|
|
g.UpdateDuck()
|
|
g.UpdateDetection()
|
|
//g.UpdateSliders()
|
|
|
|
g.cycle++
|
|
|
|
return nil
|
|
}
|
|
|
|
func (g *Game) Draw(screen *ebiten.Image) {
|
|
screen.Clear()
|
|
g.darkness.Clear()
|
|
|
|
if g.initialized {
|
|
|
|
//g.darkness.Fill(color.RGBA{R: 0xff, G: 0x00, B: 0x00, A: 0xff})
|
|
g.darkness.Fill(color.Black)
|
|
g.ducky.Draw()
|
|
g.reducky.Draw()
|
|
|
|
op := &ebiten.DrawImageOptions{}
|
|
for x := 0; x < screenWidth/duckyWidth; x++ {
|
|
for y := 0; y < screenHeight/duckyWidth; y++ {
|
|
op.GeoM.Reset()
|
|
op.GeoM.Translate(float64(x)*duckyWidth, float64(y)*duckyHeight)
|
|
if !(x == g.reduckycol && y == g.reduckyrow) {
|
|
screen.DrawImage(g.ducky.Sprite, op)
|
|
}
|
|
}
|
|
}
|
|
|
|
op = &ebiten.DrawImageOptions{}
|
|
op.GeoM.Translate(float64(g.reduckycol)*duckyWidth, float64(g.reduckyrow)*duckyHeight)
|
|
screen.DrawImage(g.reducky.Sprite, op)
|
|
|
|
op = &ebiten.DrawImageOptions{}
|
|
op.GeoM.Translate(-duckyWidth/2, -duckyHeight/2)
|
|
op.GeoM.Translate(g.mousepos.X, g.mousepos.Y)
|
|
//screen.DrawImage(assets.ImageBank[assets.Orb], op)
|
|
|
|
g.spotlight.Draw()
|
|
|
|
g.offscreen.Clear()
|
|
op = &ebiten.DrawImageOptions{}
|
|
|
|
spotlight_w := float64(g.spotlight.Sprite.Bounds().Dx())
|
|
spotlight_h := float64(g.spotlight.Sprite.Bounds().Dy())
|
|
|
|
op.GeoM.Translate(-spotlight_w/2, -spotlight_h/2)
|
|
op.GeoM.Translate(g.mousepos.X, g.mousepos.Y)
|
|
//g.offscreen.DrawImage(assets.ImageBank[assets.Orb], op)
|
|
g.offscreen.DrawImage(g.spotlight.Sprite, op)
|
|
|
|
op.GeoM.Reset()
|
|
op.Blend = ebiten.BlendXor
|
|
g.offscreen.DrawImage(g.darkness, op)
|
|
|
|
if !g.disabledarkness {
|
|
op = &ebiten.DrawImageOptions{}
|
|
if g.toast {
|
|
op.GeoM.Translate(-screenWidth/2, -screenHeight/2)
|
|
op.GeoM.Rotate(float64(g.toastcounter) / (math.Pi * 2))
|
|
op.GeoM.Translate(screenWidth/2, screenHeight/2)
|
|
}
|
|
screen.DrawImage(g.offscreen, op)
|
|
}
|
|
|
|
if g.spotted && !g.toast {
|
|
font := &text.GoTextFace{
|
|
Source: fonts.DuckyFont.Karen,
|
|
Size: duckySpottedTextSize,
|
|
}
|
|
top := &text.DrawOptions{}
|
|
top.GeoM.Translate(screenWidth/2-duckySpottedTextOffsetX, screenHeight/2-duckySpottedTextOffsetY)
|
|
if g.cycle%30 < 15 {
|
|
text.Draw(screen, "DUCKY SPOTTED", font, top)
|
|
}
|
|
}
|
|
|
|
for _, s := range g.sliders {
|
|
s.Draw()
|
|
op = &ebiten.DrawImageOptions{}
|
|
op.GeoM.Translate(s.GetPosition().X, s.GetPosition().Y)
|
|
screen.DrawImage(s.Sprite, op)
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
func (g *Game) Layout(outsideWidth, outsideHeight int) (screenwidth, screenheight int) {
|
|
return screenWidth, screenHeight
|
|
}
|
|
|
|
func (g *Game) Initialize() {
|
|
assets.LoadImages()
|
|
|
|
g.offscreen = ebiten.NewImage(screenWidth, screenHeight)
|
|
g.darkness = ebiten.NewImage(screenWidth, screenHeight)
|
|
|
|
g.spotlight = elements.NewSpotlight(assets.ImageBank[assets.Orb])
|
|
g.ducky = elements.NewDucky(assets.ImageBank[assets.Ducky])
|
|
g.reducky = elements.NewDucky(assets.ImageBank[assets.ReDucky])
|
|
|
|
for i := 0; i < 5; i++ {
|
|
slider := elements.NewSlider()
|
|
g.sliders = append(g.sliders, slider)
|
|
}
|
|
|
|
g.initialized = true
|
|
|
|
if !g.musicInitialized {
|
|
//s := audio.NewInfiniteLoop(assets.SoundBank[assets.MainLoop], assets.SoundBank[assets.MainLoop].Length())
|
|
s := audio.NewInfiniteLoop(assets.SoundBankOgg[assets.MainLoopOgg], assets.SoundBankOgg[assets.MainLoopOgg].Length())
|
|
g.audioplayer, _ = audioContext.NewPlayer(s)
|
|
g.audioplayer.Play()
|
|
g.musicInitialized = true
|
|
}
|
|
|
|
g.Reset()
|
|
}
|
|
|
|
func (g *Game) UpdateDuck() {
|
|
g.ducky.Update()
|
|
g.reducky.Update()
|
|
|
|
x, y := ebiten.CursorPosition()
|
|
g.mousepos.X = float64(x)
|
|
g.mousepos.Y = float64(y)
|
|
}
|
|
|
|
func (g *Game) Reset() {
|
|
g.reduckycol = rand.Intn(screenWidth / duckyHeight)
|
|
g.reduckyrow = rand.Intn(screenHeight / duckyWidth)
|
|
|
|
for i, slider := range g.sliders {
|
|
var yoffset float64
|
|
|
|
if i%2 == 0 {
|
|
yoffset = screenHeight
|
|
} else {
|
|
yoffset = -screenHeight
|
|
}
|
|
|
|
slider.SetPosition(gamedata.Coordinates{X: float64(i) * screenWidth / 5, Y: yoffset})
|
|
slider.SetTargetPosition(gamedata.Coordinates{X: float64(i) * screenWidth / 5, Y: 0})
|
|
slider.Reset()
|
|
}
|
|
|
|
//fmt.Printf("Ducky Position: %d, %d\n", g.reduckycol, g.reduckyrow)
|
|
g.spottedticks = 0
|
|
g.toast = false
|
|
g.reachcount = 0
|
|
g.toastcounter = 0
|
|
}
|
|
|
|
func (g *Game) HandleInput() {
|
|
if inpututil.IsKeyJustPressed(ebiten.KeyR) {
|
|
g.Reset()
|
|
}
|
|
|
|
g.disabledarkness = ebiten.IsKeyPressed(ebiten.KeySpace)
|
|
}
|
|
|
|
func (g *Game) UpdateDetection() {
|
|
x, y := ebiten.CursorPosition()
|
|
|
|
if g.reduckycol*duckyWidth <= x && x <= (g.reduckycol+1)*duckyWidth &&
|
|
g.reduckyrow*duckyHeight <= y && y <= (g.reduckyrow+1)*duckyHeight && !g.toast {
|
|
g.spottedticks++
|
|
g.spotted = true
|
|
fmt.Println("ducky spotted!")
|
|
} else {
|
|
g.spotted = false
|
|
}
|
|
|
|
if g.spottedticks > spotResetDuration {
|
|
g.toast = true
|
|
}
|
|
|
|
if g.toast {
|
|
g.UpdateSliders()
|
|
g.toastcounter++
|
|
}
|
|
|
|
if g.toastcounter > toastCount {
|
|
g.Reset()
|
|
}
|
|
|
|
}
|
|
|
|
func (g *Game) UpdateSliders() {
|
|
for _, s := range g.sliders {
|
|
s.Update()
|
|
}
|
|
}
|