Compare commits

..

6 Commits

4 changed files with 317 additions and 11 deletions

View File

@@ -37,7 +37,8 @@ func loadScenes(m *groovy.Manager) {
//loadMenu(m) //loadMenu(m)
//loadNoise(m) //loadNoise(m)
//loadSplashpad(m) //loadSplashpad(m)
loadParallax(m) //loadParallax(m)
loadRays(m)
//reset the manager to start scene 1 //reset the manager to start scene 1
m.ResetScenes() m.ResetScenes()
@@ -95,3 +96,8 @@ func loadParallax(m *groovy.Manager) {
m.AddScene(&sceneParallax) m.AddScene(&sceneParallax)
sceneParallax.InitializeParallax() sceneParallax.InitializeParallax()
} }
func loadRays(m *groovy.Manager) {
sceneRays := splashmenu.NewRays()
m.AddScene(&sceneRays)
}

View File

@@ -106,9 +106,6 @@ func NewParallax() Parallax {
func (p *Parallax) Update() error { func (p *Parallax) Update() error {
p.increment++ p.increment++
var keysPressed []ebiten.Key
keysPressed = inpututil.AppendJustPressedKeys(keysPressed[:0])
//check for user input to transition scene //check for user input to transition scene
if inpututil.IsKeyJustPressed(ebiten.KeyQ) { if inpututil.IsKeyJustPressed(ebiten.KeyQ) {
if p.events[groovy.COMPLETED] != nil { if p.events[groovy.COMPLETED] != nil {
@@ -175,6 +172,13 @@ func (p *Parallax) DrawDynamicBackground(screen *ebiten.Image) {
xd := (x0-float64(x))/DEBRIS_SCALE_DIST*float64(k+1) + x0 - float64(p.increment*k)/FLOAT_SCALE 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 yd := (y0-float64(y))/DEBRIS_SCALE_DIST*float64(k+1) + y0 - float64(p.increment*k)/FLOAT_SCALE
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
op = &ebiten.DrawImageOptions{} op = &ebiten.DrawImageOptions{}
op.GeoM.Translate(xd, yd) op.GeoM.Translate(xd, yd)
//op.GeoM.Rotate(math.Pi / 180 * float64(p.increment)) //op.GeoM.Rotate(math.Pi / 180 * float64(p.increment))
@@ -239,8 +243,10 @@ func (p *Parallax) RepositionTest(screen *ebiten.Image) {
x0 := float32(p.Dimensions.Width / 2) x0 := float32(p.Dimensions.Width / 2)
y0 := float32(p.Dimensions.Height / 2) y0 := float32(p.Dimensions.Height / 2)
xd := float32(100.0) adjustment := float32(400.0)
yd := float32(100.0)
xd := adjustment / 4.0
yd := adjustment / 4.0
//connect the dots //connect the dots
path.MoveTo(x0-xd, y0-yd) path.MoveTo(x0-xd, y0-yd)
@@ -272,11 +278,10 @@ func (p *Parallax) RepositionTest(screen *ebiten.Image) {
roX := float64(178 / 4) roX := float64(178 / 4)
roY := float64(229 / 4) roY := float64(229 / 4)
startX := float64(maxX) + roX startX := float64(maxX) + roX*2
startY := float64(y0) + roY/2 startY := float64(y0) + roY/2
adjustment := 400.0 currentX := startX - float64(p.increment) + float64(adjustment)*math.Floor(float64(p.increment)/float64(adjustment))
currentX := startX - float64(p.increment) + adjustment*math.Floor(float64(p.increment)/adjustment)
op := &ebiten.DrawImageOptions{} op := &ebiten.DrawImageOptions{}
op.GeoM.Scale(.5, .5) op.GeoM.Scale(.5, .5)

View File

@@ -0,0 +1,294 @@
package splashmenu
import (
"cosmos/diego/groovy"
splashmenu "cosmos/diego/groovy/examples/splashmenu/fonts"
"fmt"
"image/color"
"math"
"strconv"
"github.com/hajimehoshi/ebiten/v2"
"github.com/hajimehoshi/ebiten/v2/inpututil"
"github.com/hajimehoshi/ebiten/v2/text"
"github.com/hajimehoshi/ebiten/v2/vector"
)
const (
BGCOLOR = 0xCCCCCC
LINECOLOR = 0x8a8a8a
SQUARECOLOR = 0x199a19
RADIUSCOLOR = 0xFF0000
AXISCOLOR = 0xf100c1
SEMIAXISCOLOR = 0x178fc5 //0x1e1e1e //0xdccdFF
)
type ColorData struct {
selectionColor color.RGBA
squareColor color.RGBA
radiusColor color.RGBA
axisColor color.RGBA
semiAxisColor color.RGBA
}
type Coords struct {
X float32
Y float32
}
func (c Coords) DistanceFrom(pos Coords) float32 {
return float32(math.Sqrt(float64((pos.X-c.X)*(pos.X-c.X) + (pos.Y-c.Y)*(pos.Y-c.Y))))
}
func (c Coords) SignedDistanceFrom(pos Coords) Coords {
return Coords{X: pos.X - c.X, Y: pos.Y - c.Y}
}
func (c Coords) Magnitude() float32 {
return float32(math.Sqrt(float64(c.X*c.X + c.Y*c.Y)))
}
type Rays struct {
events map[groovy.SceneEvent]func()
increment int
Dimensions groovy.Area
coordinates Coords
selection Coords
interacting bool
bgcolor color.RGBA
colorData ColorData
}
func hexToRGBA(hexcolor int) color.RGBA {
return color.RGBA{
R: uint8(hexcolor >> 0x10 & 0xff),
G: uint8(hexcolor >> 0x08 & 0xff),
B: uint8(hexcolor >> 0x00 & 0xff),
A: 0xff,
}
}
func NewRays() Rays {
r := Rays{
events: make(map[groovy.SceneEvent]func()),
increment: 0,
bgcolor: hexToRGBA(BGCOLOR),
coordinates: Coords{X: 0, Y: 0},
selection: Coords{X: 0, Y: 0},
}
r.colorData.selectionColor = hexToRGBA(LINECOLOR)
r.colorData.squareColor = hexToRGBA(SQUARECOLOR)
r.colorData.radiusColor = hexToRGBA(RADIUSCOLOR)
r.colorData.axisColor = hexToRGBA(AXISCOLOR)
r.colorData.semiAxisColor = hexToRGBA(SEMIAXISCOLOR)
return r
}
func gimmeFloatCursor() (float32, float32) {
x, y := ebiten.CursorPosition()
return float32(x), float32(y)
}
func (r *Rays) Update() error {
r.increment++
x, y := gimmeFloatCursor()
mouseCoords := Coords{X: x, Y: y}
newRad := mouseCoords.DistanceFrom(r.selection)
xMin := r.selection.X - newRad
xMax := r.selection.X + newRad
yMin := r.selection.Y - newRad
yMax := r.selection.Y + newRad
if 0 <= xMin && xMax < float32(r.Dimensions.Width) &&
0 <= yMin && yMax < float32(r.Dimensions.Height) {
r.coordinates = mouseCoords
}
if inpututil.IsMouseButtonJustPressed(ebiten.MouseButtonLeft) {
r.selection = mouseCoords
r.interacting = true
}
if inpututil.IsMouseButtonJustReleased(ebiten.MouseButtonLeft) {
//r.selection = r.coordinates
r.interacting = false
}
if !r.interacting {
r.selection = r.coordinates
}
return nil
}
func (r *Rays) Draw(screen *ebiten.Image) {
screen.Fill(r.bgcolor)
r.DrawTheAngleBits(screen)
x, y := gimmeFloatCursor()
text.Draw(screen, fmt.Sprintf("Mouse x, y: (%.1f, %.1f)", x, y), splashmenu.SplashFont.Menu, 20, 20, color.White)
text.Draw(screen, fmt.Sprintf("Selection x, y: (%.1f, %.1f)", r.selection.X, r.selection.Y), splashmenu.SplashFont.Menu, 20, 40, color.White)
text.Draw(screen, fmt.Sprintf("Radius: %.1f", r.GetPrimaryRadius()), splashmenu.SplashFont.Menu, 20, 60, color.White)
text.Draw(screen, fmt.Sprintf("Interaction: %s", strconv.FormatBool(r.interacting)), splashmenu.SplashFont.Menu, 20, 80, color.White)
}
func (r *Rays) SetDimensions(a groovy.Area) {
r.Dimensions = a
}
func (r *Rays) SetEventHandler(event groovy.SceneEvent, f func()) {
r.events[event] = f
}
func (r *Rays) DrawTheAngleBits(screen *ebiten.Image) {
if r.interacting {
r.DrawTrigElementAxis(screen, r.selection, r.coordinates, r.colorData)
r.DrawTrigElement(screen, r.selection, r.coordinates, r.colorData)
r.DrawCircleElement(screen, r.selection, r.coordinates, r.colorData)
dist := r.coordinates.SignedDistanceFrom(r.selection)
angle := math.Atan2(float64(dist.Y), float64(dist.X))
for i := 0; i < 4; i++ {
var xSpot Coords
xSpot.X = r.selection.X + float32(math.Cos(angle))*dist.Magnitude()*float32(i)
xSpot.Y = r.selection.Y + float32(math.Sin(angle))*dist.Magnitude()*float32(i)
var nSpot Coords
//our limit is pi/2, but we want to stretch this out over 30 frames
u := (math.Pi / 2) * 30
v := float64(r.increment)
//our angular frequency is simply the remainder of our current frame count / our limit
w := (v/u - math.Floor(v/u))
//now scale the circles
nSpot.X = xSpot.X + float32(math.Cos(angle))*dist.Magnitude()*float32(math.Sin(w))
nSpot.Y = xSpot.Y + float32(math.Sin(angle))*dist.Magnitude()*float32(math.Sin(w))
r.DrawCircleElement(screen, xSpot, nSpot, r.colorData)
}
}
}
// Returns the primary circle radius value of the current scene
func (r *Rays) GetPrimaryRadius() float32 {
return r.coordinates.DistanceFrom(r.selection)
}
// draws circle
func (r *Rays) DrawCircleElement(img *ebiten.Image, origin Coords, dest Coords, colorData ColorData) {
dist := dest.SignedDistanceFrom(origin)
vector.StrokeCircle(img, origin.X, origin.Y, dist.Magnitude(), 2, colorData.selectionColor, true)
}
// draws circle trig relationships with the x/y axis of the circles origin and a radius indicator
func (r *Rays) DrawTrigElement(img *ebiten.Image, origin Coords, dest Coords, colorData ColorData) {
dist := dest.SignedDistanceFrom(origin)
//circle and radius marker
vector.StrokeCircle(img, origin.X, origin.Y, dist.Magnitude(), 2, colorData.selectionColor, true)
vector.StrokeLine(img, origin.X, origin.Y, dest.X, dest.Y, 1, colorData.radiusColor, true)
//draw rectangle from origin to dest
vector.StrokeRect(img, origin.X, origin.Y, dest.X-origin.X, dest.Y-origin.Y, 1, colorData.squareColor, true)
//compute directionality (1)
dirX := dist.X / float32(math.Abs(float64(dist.X)))
dirY := dist.Y / float32(math.Abs(float64(dist.Y)))
//semi-axis within circle
vector.StrokeLine(img, origin.X, origin.Y, origin.X-dirX*dist.Magnitude(), origin.Y, 1, colorData.axisColor, true)
vector.StrokeLine(img, origin.X, origin.Y, origin.X, origin.Y-dirY*dist.Magnitude(), 1, colorData.axisColor, true)
}
func (r *Rays) DrawTrigElementAxis(img *ebiten.Image, origin Coords, dest Coords, colorData ColorData) {
dist := dest.SignedDistanceFrom(origin)
//origin to BORDER
// case 1. origin.x = destination.x, means intercept should be vertical line
// case 2. we have a slope
if dist.X == 0 {
vector.StrokeLine(img, origin.X, 0, origin.X, float32(r.Dimensions.Height), 1, colorData.semiAxisColor, true)
} else {
m := dist.Y / dist.X
/*
y - y1 = m(x - x1)
y = m(x - x1) + y1
x = (y - y1)/m + x1
find the intercepts:
x = Dimensions.Width
x = 0
y = 0
y = Dimensions.Height
*/
//find our y intercept for the start of our segment
var xZero Coords
xZero.X = 0
xZero.Y = m*(xZero.X-origin.X) + origin.Y
//in the even our point lies outside the visible screen boundaries,
//we can save some pixel operations by restricting to the bounds
if xZero.Y > float32(r.Dimensions.Height) {
xZero.Y = float32(r.Dimensions.Height)
xZero.X = (xZero.Y-origin.Y)/m + origin.X
}
if xZero.Y < 0 {
xZero.Y = 0
xZero.X = (xZero.Y-origin.Y)/m + origin.X
}
var xMax Coords
xMax.X = float32(r.Dimensions.Width)
xMax.Y = m*(xMax.X-origin.X) + origin.Y
if xMax.Y > float32(r.Dimensions.Height) {
xMax.Y = float32(r.Dimensions.Height)
xMax.X = (xMax.Y-origin.Y)/m + origin.X
}
if xMax.Y < 0 {
xMax.Y = 0
xMax.X = (xMax.Y-origin.Y)/m + origin.X
}
var slashLineOrigin Coords
var slashLineDest Coords
slashLineOrigin = xZero
slashLineDest = xMax
var xSpot Coords
angle := math.Atan2(float64(dist.Y), float64(dist.X))
xSpot.X = origin.X + float32(math.Cos(angle))*dist.Magnitude()
xSpot.Y = origin.Y + float32(math.Sin(angle))*dist.Magnitude()
vector.StrokeLine(img, slashLineOrigin.X, slashLineOrigin.Y, slashLineDest.X, slashLineDest.Y, 1, colorData.semiAxisColor, true)
text.Draw(img, fmt.Sprintf("%0.1f : (%0.1f, %0.1f) (%0.1f, %0.1f)", m, slashLineOrigin.X, slashLineOrigin.Y, slashLineDest.X, slashLineDest.Y), splashmenu.SplashFont.Menu, 20, 100, color.White)
//text.Draw(img, "x", splashmenu.SplashFont.Title, int(xSpot.X), int(xSpot.Y), color.Black)
vector.DrawFilledCircle(img, xSpot.X, xSpot.Y, 5, color.Black, true)
vector.DrawFilledCircle(img, origin.X, origin.Y, 5, colorData.radiusColor, true)
}
}

View File

@@ -10,7 +10,8 @@ import (
) )
const ( const (
splashText = "schmoopysoft" splashText = "schmoopysoft®"
splashSubtext = "\"how was the gravy\"\n- christorpher hollick"
) )
type Splash struct { type Splash struct {
@@ -53,7 +54,7 @@ func (s *Splash) Draw(screen *ebiten.Image) {
y := s.Dimensions.Height / 2 y := s.Dimensions.Height / 2
text.Draw(screen, splashText, splashmenu.SplashFont.MegaTitle, x, y, color.White) text.Draw(screen, splashText, splashmenu.SplashFont.MegaTitle, x, y, color.White)
text.Draw(screen, "\"how was the gravy\"\n- christorpher hollick", splashmenu.SplashFont.Title, x, y+40, color.White) text.Draw(screen, splashSubtext, splashmenu.SplashFont.Title, x, y+40, color.White)
} }
func (s *Splash) SetEventHandler(event groovy.SceneEvent, f func()) { func (s *Splash) SetEventHandler(event groovy.SceneEvent, f func()) {