package elements import ( "fluids/fluid" "fluids/gamedata" "image/color" "github.com/hajimehoshi/ebiten/v2" "github.com/hajimehoshi/ebiten/v2/vector" ) const ( FS10PixelWidth = 100 FS10PixelHeight = 100 FS10FluidWidth = 1.0 //meters FS10FluidHeight = 1.0 //meters FS10Resolution = 20 //need to workshop this ) type FluidSim10 struct { MappedEntityBase fluid *fluid.Fluid angle float64 particlebuff *ebiten.Image renderparticles bool renderfield bool fieldscale gamedata.Vector } func NewFluidSim10() *FluidSim10 { fsim := &FluidSim10{ fluid: fluid.NewFluid(fluid.FieldVector{X: FS10FluidWidth, Y: FS10FluidHeight}, FS10FluidHeight/FS10Resolution), particlebuff: ebiten.NewImage(1, 1), renderfield: true, //false, renderparticles: false, //true, } fsim.Initialize() return fsim } func (f *FluidSim10) Initialize() { f.Sprite = ebiten.NewImage(FS10PixelWidth, FS10PixelHeight) f.particlebuff.Fill(color.White) f.fluid.Initialize() //fieldscale for rendering purposes f.fieldscale = gamedata.Vector{ X: FS10PixelWidth / float64(f.fluid.Field.Nx-1), Y: FS10PixelHeight / float64(f.fluid.Field.Ny-1), } } func (f *FluidSim10) SetAngle(angle float64) { f.angle = angle f.fluid.SetAngle(float32(angle)) } func (f *FluidSim10) GetAngle() float64 { return f.angle } func (f *FluidSim10) Draw() { f.Sprite.Clear() if f.renderfield { /* alternatively, single loop (not nested) with x/y cell coordinates given by xi := i % f.fluid.Field.Ny yi := i / f.fluid.Field.Ny */ for i := range f.fluid.Field.Nx { for j := range f.fluid.Field.Ny { idx := i*f.fluid.Field.Ny + j if f.fluid.Field.CellType[idx] != fluid.CellTypeFluid { continue } celldensity := f.fluid.ParticleDensity[idx] / f.fluid.ParticleRestDensity if celldensity > 0.8 { celldensity = 1 } ox := float64(i) * f.fieldscale.X oy := float64(j) * f.fieldscale.Y op := &ebiten.DrawImageOptions{} op.GeoM.Translate(-.5, -.5) op.GeoM.Scale(f.fieldscale.X, f.fieldscale.Y) op.GeoM.Translate(ox, oy) op.ColorScale.ScaleAlpha(celldensity) op.ColorM.Scale(0, 0, 1, 1) f.Sprite.DrawImage(f.particlebuff, op) } } } if f.renderparticles { for i := range f.fluid.Particles { //for each particle, compute its relative position based on its //position within the fluid field p := &f.fluid.Particles[i] percentx := (p.Position.X - f.fluid.Field.H/2) / f.fluid.Field.Dimensions.X percenty := (p.Position.Y - f.fluid.Field.H/2) / f.fluid.Field.Dimensions.Y ox := float64(percentx * FS10PixelWidth) oy := float64(percenty * FS10PixelHeight) op := &ebiten.DrawImageOptions{} op.GeoM.Translate(ox, oy) f.Sprite.DrawImage(f.particlebuff, op) } } if f.fluid.Block { vector.StrokeRect(f.Sprite, 0, 0, FS10PixelWidth, FS10PixelHeight, 2, color.White, true) } else { radius := float32(f.fluid.Field.Nx) * f.fluid.Field.H / 2 pixelradius := radius/f.fluid.Field.Dimensions.X*FS10PixelWidth - 4 vector.StrokeCircle(f.Sprite, FS10PixelWidth/2, FS10PixelHeight/2, pixelradius, 2, color.White, true) } } func (f *FluidSim10) Update() { if f.paused { return } f.fluid.Step() } func (f *FluidSim10) EnableParticleRender(v bool) { f.renderparticles = v } func (f *FluidSim10) EnableFieldRender(v bool) { f.renderfield = v } func (f *FluidSim10) ToggleShape() { f.fluid.ToggleShape() } func (f *FluidSim10) ToggleParticles() { f.renderparticles = !f.renderparticles }