package game import ( "fluids/elements" "fluids/gamedata" "fmt" "math" "github.com/hajimehoshi/ebiten/v2" "github.com/hajimehoshi/ebiten/v2/ebitenutil" "github.com/hajimehoshi/ebiten/v2/inpututil" ) const ( GameWidth = 640 GameHeight = 360 GameFSDW = 200 GameFSDH = 100 ) 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 } 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(), } g.Initialize() 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 } } g.cycle++ return nil } func (g *Game) UpdateFluidsim10() { for _, sim := range g.fluidsim10 { sim.Update() } } func (g *Game) Draw(screen *ebiten.Image) { screen.Clear() switch g.fluidsimidx { case 0: g.RenderFluidSimD(screen) case 1: g.RenderFluidSim10(screen) default: break } if g.paused { op := &ebiten.DrawImageOptions{} op.GeoM.Translate(50, 50) screen.DrawImage(g.alertbox.Sprite, op) } } 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) } func (g *Game) RenderFluidSim10(img *ebiten.Image) { for _, sim := range g.fluidsim10 { sim.Draw() angle := sim.GetAngle() pos := sim.GetPosition() 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) } //debug info x, y := ebiten.CursorPosition() deg := g.fluidsim10angle * 180 / math.Pi 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) } func (g *Game) Layout(x, y int) (int, int) { return GameWidth, GameHeight } func (g *Game) ParseInputs() { //simulation specific updates switch g.fluidsimidx { case 0: g.ManageFluidSimDInputs() case 1: //g.ManageFluidSimGPTInputs() g.ManageFluidSim10Inputs() default: break } //common updates if inpututil.IsKeyJustPressed(ebiten.KeyP) { g.paused = !g.paused g.alertbox.SetText("PAUSED") g.alertbox.Draw() } //swap fluid simulations if inpututil.IsKeyJustPressed(ebiten.KeyPageUp) { g.fluidsimidx = (g.fluidsimidx + 1) % 2 } if inpututil.IsKeyJustPressed(ebiten.KeyPageDown) { g.fluidsimidx = g.fluidsimidx - 1 if g.fluidsimidx < 0 { g.fluidsimidx = 1 } } } func (g *Game) ManageFluidSimDInputs() { //refresh particles if inpututil.IsKeyJustPressed(ebiten.KeyR) { g.fluidsimd.InitializeParticles() } //pause simulation if inpututil.IsKeyJustPressed(ebiten.KeyP) { g.fluidsimd.SetPaused(!g.fluidsimd.Paused()) } //show quadtree quadrants if inpututil.IsKeyJustPressed(ebiten.KeyQ) { g.fluidsimd.SetRenderQuads(!g.fluidsimd.RenderQuads()) } //enable collision resolution if inpututil.IsKeyJustPressed(ebiten.KeyC) { g.fluidsimd.SetResolveCollisions(!g.fluidsimd.ResolveCollisions()) } //switch between collision resolvers if inpututil.IsKeyJustPressed(ebiten.KeyLeft) { g.fluidsimd.PreviousSolver() } if inpututil.IsKeyJustPressed(ebiten.KeyRight) { g.fluidsimd.NextSolver() } } func (g *Game) ManageFluidSim10Inputs() { //refresh particles if inpututil.IsKeyJustPressed(ebiten.KeyR) { for _, sim := range g.fluidsim10 { sim.Initialize() g.fluidsim10angle = 0 } } if inpututil.IsMouseButtonJustPressed(ebiten.MouseButtonLeft) { g.mdown = true g.mdx, g.mdy = ebiten.CursorPosition() } if ebiten.IsMouseButtonPressed(ebiten.MouseButtonLeft) { if g.mdown { mx, my := ebiten.CursorPosition() 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) } } } if inpututil.IsMouseButtonJustReleased(ebiten.MouseButtonLeft) { g.mdown = false } if inpututil.IsKeyJustPressed(ebiten.KeyB) { for _, sim := range g.fluidsim10 { sim.ToggleShape() } } if inpututil.IsKeyJustPressed(ebiten.KeyV) { for _, sim := range g.fluidsim10 { sim.ToggleParticles() } } } func (g *Game) Initialize() { g.fluidsim10 = append(g.fluidsim10, elements.NewFluidSim10()) 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) } }