2023-08-31 17:01:21 -04:00
|
|
|
package splashmenu
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"bytes"
|
|
|
|
|
"cosmos/diego/groovy"
|
|
|
|
|
"image"
|
|
|
|
|
"image/color"
|
|
|
|
|
"log"
|
|
|
|
|
"math"
|
|
|
|
|
"math/rand"
|
|
|
|
|
|
|
|
|
|
"github.com/hajimehoshi/ebiten/v2"
|
2023-09-05 07:54:59 -04:00
|
|
|
"github.com/hajimehoshi/ebiten/v2/inpututil"
|
2023-08-31 17:01:21 -04:00
|
|
|
"github.com/hajimehoshi/ebiten/v2/vector"
|
|
|
|
|
|
|
|
|
|
_ "embed"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
const (
|
|
|
|
|
GALAXY_SCALE_DIST = 50
|
|
|
|
|
DEBRIS_SCALE_DIST = 10
|
|
|
|
|
FLOAT_SCALE = 8
|
|
|
|
|
ASTEROID_COUNT = 14
|
|
|
|
|
MAX_ROTATION_SPEED = 3
|
|
|
|
|
MIN_ROTATION_SPEED = 1
|
|
|
|
|
OFF_SCREEN_SCALE = 2 // number of parallax dimension screens for the logical game display area
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
var (
|
|
|
|
|
//go:embed assets/galaxy4.jpg
|
|
|
|
|
galaxyImg_jpg []byte
|
|
|
|
|
|
|
|
|
|
//go:embed assets/debris_00.png
|
|
|
|
|
debrisImg_png []byte
|
|
|
|
|
|
|
|
|
|
//go:embed assets/roid1.png
|
|
|
|
|
roid1Img_png []byte
|
|
|
|
|
|
|
|
|
|
//go:embed assets/roid2.png
|
|
|
|
|
roid2Img_png []byte
|
|
|
|
|
|
|
|
|
|
//go:embed assets/blend.png
|
|
|
|
|
blendImg_png []byte
|
|
|
|
|
|
|
|
|
|
galaxyBackground *ebiten.Image
|
|
|
|
|
debrisImage *ebiten.Image
|
|
|
|
|
blendImage *ebiten.Image
|
|
|
|
|
blendTmp *ebiten.Image
|
|
|
|
|
roids []*ebiten.Image
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
type Asteroid struct {
|
|
|
|
|
cX int
|
|
|
|
|
cY int
|
|
|
|
|
rotationSpeed float64
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func init() {
|
|
|
|
|
// Load up images
|
|
|
|
|
img, _, err := image.Decode(bytes.NewReader(galaxyImg_jpg))
|
|
|
|
|
if err != nil {
|
|
|
|
|
log.Fatal(err)
|
|
|
|
|
}
|
|
|
|
|
galaxyBackground = ebiten.NewImageFromImage(img)
|
|
|
|
|
|
|
|
|
|
img, _, err = image.Decode(bytes.NewReader(debrisImg_png))
|
|
|
|
|
if err != nil {
|
|
|
|
|
log.Fatal(err)
|
|
|
|
|
}
|
|
|
|
|
debrisImage = ebiten.NewImageFromImage(img)
|
|
|
|
|
|
|
|
|
|
//asteroids!
|
|
|
|
|
img, _, err = image.Decode(bytes.NewReader(roid1Img_png))
|
|
|
|
|
if err != nil {
|
|
|
|
|
log.Fatal(err)
|
|
|
|
|
}
|
|
|
|
|
roids = append(roids, ebiten.NewImageFromImage(img))
|
|
|
|
|
|
|
|
|
|
img, _, err = image.Decode(bytes.NewReader(roid2Img_png))
|
|
|
|
|
if err != nil {
|
|
|
|
|
log.Fatal(err)
|
|
|
|
|
}
|
|
|
|
|
roids = append(roids, ebiten.NewImageFromImage(img))
|
|
|
|
|
|
|
|
|
|
img, _, err = image.Decode(bytes.NewReader(blendImg_png))
|
|
|
|
|
if err != nil {
|
|
|
|
|
log.Fatal(err)
|
|
|
|
|
}
|
|
|
|
|
blendImage = ebiten.NewImageFromImage(img)
|
|
|
|
|
blendTmp = ebiten.NewImageFromImage(blendImage)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type Parallax struct {
|
|
|
|
|
events map[groovy.SceneEvent]func()
|
|
|
|
|
Dimensions groovy.Area
|
|
|
|
|
increment int
|
|
|
|
|
asteroids []Asteroid
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func NewParallax() Parallax {
|
|
|
|
|
return Parallax{
|
|
|
|
|
events: make(map[groovy.SceneEvent]func()),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (p *Parallax) Update() error {
|
|
|
|
|
p.increment++
|
2023-09-05 07:54:59 -04:00
|
|
|
|
|
|
|
|
var keysPressed []ebiten.Key
|
|
|
|
|
keysPressed = inpututil.AppendJustPressedKeys(keysPressed[:0])
|
|
|
|
|
|
|
|
|
|
//check for user input to transition scene
|
|
|
|
|
if inpututil.IsKeyJustPressed(ebiten.KeyQ) {
|
|
|
|
|
if p.events[groovy.COMPLETED] != nil {
|
|
|
|
|
p.events[groovy.COMPLETED]()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-08-31 17:01:21 -04:00
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (p *Parallax) Draw(screen *ebiten.Image) {
|
|
|
|
|
|
|
|
|
|
p.DrawDynamicBackground(screen)
|
|
|
|
|
p.DrawObstacles(screen)
|
|
|
|
|
//p.DrawObstaclesWithShamLighting(screen)
|
|
|
|
|
|
|
|
|
|
p.RepositionTest(screen)
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (p *Parallax) SetDimensions(a groovy.Area) {
|
|
|
|
|
p.Dimensions = a
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (p *Parallax) SetEventHandler(event groovy.SceneEvent, f func()) {
|
|
|
|
|
p.events[event] = f
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (p *Parallax) InitializeParallax() {
|
|
|
|
|
|
|
|
|
|
if p.Dimensions.Area() <= 0 {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for i := 0; i < ASTEROID_COUNT; i++ {
|
|
|
|
|
newX := rand.Intn(p.Dimensions.Width) * OFF_SCREEN_SCALE
|
|
|
|
|
newY := rand.Intn(p.Dimensions.Height) * OFF_SCREEN_SCALE
|
|
|
|
|
rS := rand.Float64()*MAX_ROTATION_SPEED + MIN_ROTATION_SPEED
|
|
|
|
|
p.asteroids = append(p.asteroids, Asteroid{cX: newX, cY: newY, rotationSpeed: rS})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
whiteImage.Fill(color.White)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (p *Parallax) DrawDynamicBackground(screen *ebiten.Image) {
|
|
|
|
|
x, y := ebiten.CursorPosition()
|
|
|
|
|
|
|
|
|
|
op := &ebiten.DrawImageOptions{}
|
|
|
|
|
op.GeoM.Translate(float64(-x-p.Dimensions.Width)/GALAXY_SCALE_DIST, float64(-y-p.Dimensions.Height)/GALAXY_SCALE_DIST)
|
|
|
|
|
screen.DrawImage(galaxyBackground, op)
|
|
|
|
|
|
|
|
|
|
//debris layers
|
|
|
|
|
const DEBRIS_QTY = 3
|
|
|
|
|
const DEBRIS_WIDTH = 640 / 3 * 2
|
|
|
|
|
const DEBRIS_HEIGHT = 480 / 3 * 2
|
|
|
|
|
const TOTAL_LAYERS = 2
|
|
|
|
|
for k := 0; k < TOTAL_LAYERS; k++ {
|
|
|
|
|
for i := 0; i < DEBRIS_QTY; i++ {
|
|
|
|
|
for j := 0; j < DEBRIS_QTY; j++ {
|
|
|
|
|
//compute object origins (pre-shifts)
|
|
|
|
|
x0 := float64(j*DEBRIS_WIDTH) + float64(p.increment/640)
|
|
|
|
|
y0 := float64(i*DEBRIS_HEIGHT) + float64(p.increment/480)
|
|
|
|
|
//now compute delta with parallax effect
|
|
|
|
|
xd := (x0-float64(x))/DEBRIS_SCALE_DIST*float64(k+1) + x0 - float64(p.increment*k)/FLOAT_SCALE
|
|
|
|
|
yd := (y0-float64(y))/DEBRIS_SCALE_DIST*float64(k+1) + y0 - float64(p.increment*k)/FLOAT_SCALE
|
|
|
|
|
|
2023-09-05 19:27:53 -04:00
|
|
|
adjustX := float64(p.Dimensions.Width)
|
|
|
|
|
adjustY := float64(p.Dimensions.Height)
|
|
|
|
|
intX := adjustX * math.Floor(float64(p.increment)/adjustX)
|
|
|
|
|
intY := adjustY * math.Floor(float64(p.increment)/adjustY)
|
|
|
|
|
xd = xd + intX
|
|
|
|
|
yd = yd + intY
|
|
|
|
|
|
2023-08-31 17:01:21 -04:00
|
|
|
op = &ebiten.DrawImageOptions{}
|
|
|
|
|
op.GeoM.Translate(xd, yd)
|
|
|
|
|
//op.GeoM.Rotate(math.Pi / 180 * float64(p.increment))
|
|
|
|
|
|
|
|
|
|
op.Blend = ebiten.BlendSourceOver
|
|
|
|
|
screen.DrawImage(debrisImage, op)
|
|
|
|
|
//log.Printf("%d, %d", xoffset, yoffset)
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (p *Parallax) DrawObstacles(screen *ebiten.Image) {
|
|
|
|
|
|
|
|
|
|
x, y := ebiten.CursorPosition()
|
|
|
|
|
|
|
|
|
|
for _, a := range p.asteroids {
|
|
|
|
|
cx := float64(a.cX)
|
|
|
|
|
cy := float64(a.cY)
|
|
|
|
|
|
|
|
|
|
op := &ebiten.DrawImageOptions{}
|
|
|
|
|
op.GeoM.Translate(-100, -66)
|
|
|
|
|
op.GeoM.Rotate(-float64(p.increment) * a.rotationSpeed / (math.Pi * 120))
|
|
|
|
|
op.GeoM.Translate(cx-float64(x), cy-float64(y))
|
|
|
|
|
screen.DrawImage(roids[0], op)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (p *Parallax) DrawObstaclesWithShamLighting(screen *ebiten.Image) {
|
|
|
|
|
|
|
|
|
|
x, y := ebiten.CursorPosition()
|
|
|
|
|
|
|
|
|
|
for _, a := range p.asteroids {
|
|
|
|
|
cx := float64(a.cX)
|
|
|
|
|
cy := float64(a.cY)
|
|
|
|
|
|
|
|
|
|
op := &ebiten.DrawImageOptions{}
|
|
|
|
|
op.GeoM.Translate(-100, -66)
|
|
|
|
|
op.GeoM.Rotate(-float64(p.increment) * a.rotationSpeed / (math.Pi * 120))
|
|
|
|
|
op.GeoM.Translate(100, 66)
|
|
|
|
|
|
|
|
|
|
//draw roid to temporary location
|
|
|
|
|
blendTmp.DrawImage(roids[0], op)
|
|
|
|
|
|
|
|
|
|
op = &ebiten.DrawImageOptions{}
|
|
|
|
|
op.Blend = ebiten.BlendSourceAtop
|
|
|
|
|
blendTmp.DrawImage(blendImage, op)
|
|
|
|
|
|
|
|
|
|
op = &ebiten.DrawImageOptions{}
|
|
|
|
|
op.GeoM.Translate(cx-float64(x), cy-float64(y))
|
|
|
|
|
screen.DrawImage(blendTmp, op)
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (p *Parallax) RepositionTest(screen *ebiten.Image) {
|
|
|
|
|
|
|
|
|
|
var path vector.Path
|
|
|
|
|
|
|
|
|
|
//set up origin and boundaries
|
|
|
|
|
x0 := float32(p.Dimensions.Width / 2)
|
|
|
|
|
y0 := float32(p.Dimensions.Height / 2)
|
|
|
|
|
|
2023-09-05 19:27:53 -04:00
|
|
|
adjustment := float32(400.0)
|
|
|
|
|
|
|
|
|
|
xd := adjustment / 4.0
|
|
|
|
|
yd := adjustment / 4.0
|
2023-08-31 17:01:21 -04:00
|
|
|
|
|
|
|
|
//connect the dots
|
|
|
|
|
path.MoveTo(x0-xd, y0-yd)
|
|
|
|
|
path.LineTo(x0+xd, y0-yd)
|
|
|
|
|
path.LineTo(x0+xd, y0+yd)
|
|
|
|
|
path.LineTo(x0-xd, y0+yd)
|
|
|
|
|
path.LineTo(x0-xd, y0+yd)
|
|
|
|
|
path.Close()
|
|
|
|
|
|
|
|
|
|
var vs []ebiten.Vertex
|
|
|
|
|
var is []uint16
|
|
|
|
|
|
|
|
|
|
vs, is = path.AppendVerticesAndIndicesForFilling(nil, nil)
|
|
|
|
|
for i := range vs {
|
|
|
|
|
vs[i].SrcX = 1
|
|
|
|
|
vs[i].SrcY = 1
|
|
|
|
|
vs[i].ColorR = float32(0xff) / 0xFF
|
|
|
|
|
vs[i].ColorG = float32(0x00) / 0xFF
|
|
|
|
|
vs[i].ColorB = float32(0x00) / 0xFF
|
|
|
|
|
vs[i].ColorA = 1
|
|
|
|
|
}
|
|
|
|
|
screen.DrawTriangles(vs, is, whiteSubImage, nil)
|
2023-09-05 07:54:59 -04:00
|
|
|
|
|
|
|
|
//minX := x0 - xd
|
|
|
|
|
maxX := x0 + xd
|
|
|
|
|
//minY := y0 - yd
|
|
|
|
|
//maxY := y0 + yd
|
|
|
|
|
//178x229
|
|
|
|
|
|
|
|
|
|
roX := float64(178 / 4)
|
|
|
|
|
roY := float64(229 / 4)
|
2023-09-05 19:27:53 -04:00
|
|
|
startX := float64(maxX) + roX*2
|
2023-09-05 07:54:59 -04:00
|
|
|
startY := float64(y0) + roY/2
|
|
|
|
|
|
2023-09-05 19:27:53 -04:00
|
|
|
currentX := startX - float64(p.increment) + float64(adjustment)*math.Floor(float64(p.increment)/float64(adjustment))
|
2023-09-05 07:54:59 -04:00
|
|
|
|
|
|
|
|
op := &ebiten.DrawImageOptions{}
|
|
|
|
|
op.GeoM.Scale(.5, .5)
|
|
|
|
|
op.GeoM.Translate(-roX, -roY)
|
|
|
|
|
op.GeoM.Rotate(-float64(p.increment) / (math.Pi * 12.0))
|
|
|
|
|
op.GeoM.Translate(currentX, startY)
|
|
|
|
|
|
|
|
|
|
screen.DrawImage(roids[1], op)
|
|
|
|
|
|
2023-08-31 17:01:21 -04:00
|
|
|
}
|