Files
fluids/game/game.go

263 lines
5.2 KiB
Go
Raw Normal View History

2025-11-27 22:50:36 -05:00
package game
import (
"fluids/elements"
"fluids/gamedata"
"fmt"
"math"
"github.com/hajimehoshi/ebiten/v2"
"github.com/hajimehoshi/ebiten/v2/ebitenutil"
2025-11-27 22:50:36 -05:00
"github.com/hajimehoshi/ebiten/v2/inpututil"
)
const (
GameWidth = 640
GameHeight = 360
GameFSDW = 200
GameFSDH = 100
2025-11-27 22:50:36 -05:00
)
type Game struct {
//control data
cycle int
paused bool
fluidsimidx int
//key elements
fluidsimd *elements.FluidSimD
fluidsim10 []*elements.FluidSim10
alertbox *elements.Alert
//cache elements
fluidsim10width float64
fluidsim10height float64
//other
fluidsim10angle float64 //purely for debugging
mdown bool
mdx, mdy int
2025-11-27 22:50:36 -05:00
}
func NewGame() *Game {
g := &Game{
paused: false,
fluidsimidx: 0,
alertbox: elements.NewAlert(),
fluidsimd: elements.NewFluidSimD(),
//fluidsim10: elements.NewFluidSim10(gamedata.Vector{X: GameFSDW, Y: GameFSDH}),
//fluidsimgpt: elements.NewFlipFluidEntity(640, 480, 2, 1, 100),
//fluidsim10: elements.NewFluidSim10(),
2025-11-27 22:50:36 -05:00
}
g.Initialize()
2025-11-27 22:50:36 -05:00
return g
}
func (g *Game) Update() error {
g.ParseInputs()
if !g.paused {
switch g.fluidsimidx {
case 0:
g.fluidsimd.Update()
case 1:
//g.fluidsimgpt.Update()
g.UpdateFluidsim10()
default:
break
}
2025-11-27 22:50:36 -05:00
}
g.cycle++
return nil
}
func (g *Game) UpdateFluidsim10() {
for _, sim := range g.fluidsim10 {
sim.Update()
}
}
2025-11-27 22:50:36 -05:00
func (g *Game) Draw(screen *ebiten.Image) {
screen.Clear()
switch g.fluidsimidx {
case 0:
g.RenderFluidSimD(screen)
case 1:
g.RenderFluidSim10(screen)
default:
break
2025-11-27 22:50:36 -05:00
}
2025-11-28 18:10:37 -05:00
if g.paused {
op := &ebiten.DrawImageOptions{}
op.GeoM.Translate(50, 50)
screen.DrawImage(g.alertbox.Sprite, op)
}
2025-11-27 22:50:36 -05:00
}
func (g *Game) RenderFluidSimD(img *ebiten.Image) {
g.fluidsimd.Draw()
pos := g.fluidsimd.GetPosition()
op := &ebiten.DrawImageOptions{}
op.GeoM.Translate(pos.X, pos.Y)
img.DrawImage(g.fluidsimd.GetSprite(), op)
2025-11-27 22:50:36 -05:00
}
func (g *Game) RenderFluidSim10(img *ebiten.Image) {
2025-11-27 22:50:36 -05:00
for _, sim := range g.fluidsim10 {
sim.Draw()
angle := sim.GetAngle()
pos := sim.GetPosition()
2025-11-27 22:50:36 -05:00
op := &ebiten.DrawImageOptions{}
op.GeoM.Translate(-g.fluidsim10width/2, -g.fluidsim10height/2)
op.GeoM.Scale(1, -1)
op.GeoM.Rotate(angle)
// op.GeoM.Translate(g.fluidsim10width/2, g.fluidsim10height/2)
op.GeoM.Translate(pos.X, pos.Y)
img.DrawImage(sim.GetSprite(), op)
2025-11-27 22:50:36 -05:00
}
//debug info
x, y := ebiten.CursorPosition()
deg := g.fluidsim10angle * 180 / math.Pi
2025-11-27 22:50:36 -05:00
str := fmt.Sprintf("Mouse (x: %d, y: %d) Origin (x: %d, y: %d) Angle (%f)", x, y, GameWidth/2, GameHeight/2, deg)
ebitenutil.DebugPrint(img, str)
2025-11-27 22:50:36 -05:00
}
func (g *Game) Layout(x, y int) (int, int) {
return GameWidth, GameHeight
2025-11-27 22:50:36 -05:00
}
func (g *Game) ParseInputs() {
2025-11-27 22:50:36 -05:00
//simulation specific updates
switch g.fluidsimidx {
case 0:
g.ManageFluidSimDInputs()
case 1:
//g.ManageFluidSimGPTInputs()
g.ManageFluidSim10Inputs()
default:
break
2025-11-27 22:50:36 -05:00
}
//common updates
if inpututil.IsKeyJustPressed(ebiten.KeyP) {
g.paused = !g.paused
g.alertbox.SetText("PAUSED")
g.alertbox.Draw()
2025-11-27 22:50:36 -05:00
}
//swap fluid simulations
if inpututil.IsKeyJustPressed(ebiten.KeyPageUp) {
g.fluidsimidx = (g.fluidsimidx + 1) % 2
2025-11-27 22:50:36 -05:00
}
if inpututil.IsKeyJustPressed(ebiten.KeyPageDown) {
g.fluidsimidx = g.fluidsimidx - 1
if g.fluidsimidx < 0 {
g.fluidsimidx = 1
}
2025-11-27 22:50:36 -05:00
}
}
func (g *Game) ManageFluidSimDInputs() {
2025-11-28 18:10:37 -05:00
//refresh particles
2025-11-27 22:50:36 -05:00
if inpututil.IsKeyJustPressed(ebiten.KeyR) {
g.fluidsimd.InitializeParticles()
2025-11-27 22:50:36 -05:00
}
2025-11-28 18:10:37 -05:00
//pause simulation
2025-11-27 22:50:36 -05:00
if inpututil.IsKeyJustPressed(ebiten.KeyP) {
g.fluidsimd.SetPaused(!g.fluidsimd.Paused())
2025-11-27 22:50:36 -05:00
}
2025-11-28 18:10:37 -05:00
//show quadtree quadrants
2025-11-27 22:50:36 -05:00
if inpututil.IsKeyJustPressed(ebiten.KeyQ) {
g.fluidsimd.SetRenderQuads(!g.fluidsimd.RenderQuads())
2025-11-27 22:50:36 -05:00
}
2025-11-28 18:10:37 -05:00
//enable collision resolution
2025-11-27 22:50:36 -05:00
if inpututil.IsKeyJustPressed(ebiten.KeyC) {
g.fluidsimd.SetResolveCollisions(!g.fluidsimd.ResolveCollisions())
2025-11-27 22:50:36 -05:00
}
2025-11-28 18:10:37 -05:00
//switch between collision resolvers
if inpututil.IsKeyJustPressed(ebiten.KeyLeft) {
g.fluidsimd.PreviousSolver()
}
if inpututil.IsKeyJustPressed(ebiten.KeyRight) {
g.fluidsimd.NextSolver()
}
2025-11-27 22:50:36 -05:00
}
func (g *Game) ManageFluidSim10Inputs() {
//refresh particles
if inpututil.IsKeyJustPressed(ebiten.KeyR) {
for _, sim := range g.fluidsim10 {
sim.Initialize()
g.fluidsim10angle = 0
2025-11-27 22:50:36 -05:00
}
}
if inpututil.IsMouseButtonJustPressed(ebiten.MouseButtonLeft) {
g.mdown = true
g.mdx, g.mdy = ebiten.CursorPosition()
2025-11-27 22:50:36 -05:00
}
if ebiten.IsMouseButtonPressed(ebiten.MouseButtonLeft) {
if g.mdown {
mx, my := ebiten.CursorPosition()
2025-11-27 22:50:36 -05:00
for _, sim := range g.fluidsim10 {
dx := float64(mx) - sim.GetPosition().X
dy := float64(my) - sim.GetPosition().Y
angle := math.Atan2(dy, dx)
g.fluidsim10angle = angle
sim.SetAngle(angle)
}
2025-11-27 22:50:36 -05:00
}
}
if inpututil.IsMouseButtonJustReleased(ebiten.MouseButtonLeft) {
g.mdown = false
}
}
func (g *Game) ManageFluidSimGPTInputs() {
}
func (g *Game) Initialize() {
g.fluidsim10 = append(g.fluidsim10, elements.NewFluidSim10())
g.fluidsim10 = append(g.fluidsim10, elements.NewFluidSim10())
g.fluidsim10width = float64(g.fluidsim10[0].GetSprite().Bounds().Dx())
g.fluidsim10height = float64(g.fluidsim10[0].GetSprite().Bounds().Dy())
x0 := float64(GameWidth / (len(g.fluidsim10) + 1))
for i, sim := range g.fluidsim10 {
pos := gamedata.Vector{
X: x0 * float64(i+1),
Y: GameHeight / 2.,
}
sim.SetPosition(pos)
}
}