diff --git a/assets/imagebank.go b/assets/imagebank.go index fd675a5..bb16b46 100644 --- a/assets/imagebank.go +++ b/assets/imagebank.go @@ -30,6 +30,7 @@ const ( Splash ImgAssetName = "Splash" LaserBeam ImgAssetName = "LaserBeam" ItemLaser ImgAssetName = "ItemLaser" + RainSplash ImgAssetName = "RainSplash" ) var ( @@ -69,6 +70,8 @@ var ( laserbeam_img []byte //go:embed item-laser.png itemlaser_img []byte + //go:embed rain-splash.png + rainsplash_img []byte ) func LoadImages() { @@ -91,6 +94,7 @@ func LoadImages() { ImageBank[Splash] = LoadImagesFatal(splash_img) ImageBank[LaserBeam] = LoadImagesFatal(laserbeam_img) ImageBank[ItemLaser] = LoadImagesFatal(itemlaser_img) + ImageBank[RainSplash] = LoadImagesFatal(rainsplash_img) } diff --git a/assets/rain-splash.png b/assets/rain-splash.png new file mode 100644 index 0000000..c74acec Binary files /dev/null and b/assets/rain-splash.png differ diff --git a/elements/raindrop.go b/elements/raindrop.go new file mode 100644 index 0000000..d14f666 --- /dev/null +++ b/elements/raindrop.go @@ -0,0 +1,46 @@ +package elements + +import ( + "image/color" + "math/rand/v2" + "mover/gamedata" + + "github.com/hajimehoshi/ebiten/v2" +) + +type RainDrop struct { + Sprite *ebiten.Image + position gamedata.Coordinates + cycle int +} + +func NewRainDrop() *RainDrop { + rd := &RainDrop{ + Sprite: ebiten.NewImage(2, 10), + cycle: rand.IntN(30), + } + return rd +} + +func (rd *RainDrop) Update() error { + rd.position.Y += 5 + rd.cycle++ + return nil +} + +func (rd *RainDrop) Draw() { + rd.Sprite.Clear() + rd.Sprite.Fill(color.White) +} + +func (rd *RainDrop) GetPosition() gamedata.Coordinates { + return rd.position +} + +func (rd *RainDrop) SetPosition(pos gamedata.Coordinates) { + rd.position = pos +} + +func (rd *RainDrop) Expired() bool { + return rd.cycle > 30 +} diff --git a/elements/rainsplash.go b/elements/rainsplash.go new file mode 100644 index 0000000..8aff0fe --- /dev/null +++ b/elements/rainsplash.go @@ -0,0 +1,58 @@ +package elements + +import ( + "image" + "math/rand/v2" + "mover/assets" + "mover/gamedata" + + "github.com/hajimehoshi/ebiten/v2" +) + +type RainSplash struct { + Sprite *ebiten.Image + position gamedata.Coordinates + cycle int + counter int +} + +func NewRainSplash() *RainSplash { + rd := &RainSplash{ + Sprite: ebiten.NewImage(10, 4), + cycle: rand.IntN(4), + counter: 0, + } + return rd +} + +func (rd *RainSplash) Update() error { + rd.counter++ + rd.cycle++ + return nil +} + +func (rd *RainSplash) Draw() { + rd.Sprite.Clear() + //rd.Sprite.Fill(color.White) + + idx := (rd.cycle / 8) % 4 + x0 := idx * 10 + y0 := 0 + x1 := x0 + 10 + y1 := 4 + + rd.Sprite.DrawImage(assets.ImageBank[assets.RainSplash].SubImage(image.Rect(x0, y0, x1, y1)).(*ebiten.Image), nil) + +} + +func (rd *RainSplash) GetPosition() gamedata.Coordinates { + return rd.position +} + +func (rd *RainSplash) SetPosition(pos gamedata.Coordinates) { + rd.position = pos +} + +func (rd *RainSplash) Expired() bool { + return rd.counter > 30 +} diff --git a/elements/splash.go b/elements/splash.go index 854e380..5b2cd5d 100644 --- a/elements/splash.go +++ b/elements/splash.go @@ -77,6 +77,26 @@ func (sp *Splash) Draw() { sp.Sprite.DrawImage(assets.ImageBank[assets.Splash], op) } + for i := 0; i < 5; i++ { + + percent := float64(5-i) / 5 + + a := 9.8 + time := float64(sp.cycle) / 8 + v0 := 10. + dy := 1/2.*a*math.Pow(time-float64(i), 2) - v0*time + dx := -float64(sp.cycle) + + op := &ebiten.DrawImageOptions{} + op.GeoM.Translate(-48/2, -48/2) + op.GeoM.Scale(percent, percent) + op.GeoM.Rotate(-float64(sp.cycle) / (math.Pi * 4)) + op.GeoM.Translate(SPLASH_DIM/2, SPLASH_DIM/2) + op.GeoM.Translate(dx, dy) + sp.Sprite.DrawImage(assets.ImageBank[assets.Splash], op) + op.GeoM.Translate(-2*dx, 0) + sp.Sprite.DrawImage(assets.ImageBank[assets.Splash], op) + } } func (sp *Splash) GetPosition() gamedata.Coordinates { diff --git a/gameelement/canvas.go b/gameelement/canvas.go index 1ec7c12..f1834ea 100644 --- a/gameelement/canvas.go +++ b/gameelement/canvas.go @@ -984,4 +984,5 @@ func (c *Canvas) ResetWeaponDrops() { c.wpdrops[i] = nil } c.wpdrops = c.wpdrops[:0] + c.holster = weapons.NewHolster() } diff --git a/gameelement/rainlayer.go b/gameelement/rainlayer.go new file mode 100644 index 0000000..9bfc0d3 --- /dev/null +++ b/gameelement/rainlayer.go @@ -0,0 +1,149 @@ +package gameelement + +import ( + "math/rand/v2" + "mover/elements" + "mover/gamedata" + + "github.com/hajimehoshi/ebiten/v2" +) + +type RainLayer struct { + Sprite *ebiten.Image + lastInputs gamedata.GameInputs + raindrops []*elements.RainDrop + nextsplashes []gamedata.Coordinates + rainsplashes []*elements.RainSplash + dimensions gamedata.Area + cycle int +} + +func NewRainLayer(a gamedata.Area) *RainLayer { + rl := &RainLayer{ + Sprite: ebiten.NewImage(a.Width, a.Height), + dimensions: a, + } + + for i := 0; i < 50; i++ { + nrd := elements.NewRainDrop() + nrd.SetPosition(gamedata.Coordinates{X: rand.Float64() * float64(a.Width), Y: rand.Float64() * float64(a.Height)}) + rl.raindrops = append(rl.raindrops, nrd) + } + + for i := 0; i < 50; i++ { + nrd := elements.NewRainSplash() + nrd.SetPosition(gamedata.Coordinates{X: rand.Float64() * float64(a.Width), Y: rand.Float64() * float64(a.Height)}) + rl.rainsplashes = append(rl.rainsplashes, nrd) + } + return rl +} + +func (r *RainLayer) SetInputs(inputs gamedata.GameInputs) { + r.lastInputs = inputs +} + +func (r *RainLayer) Update() error { + + r.UpdateDrops() + r.UpdateSplashes() + + r.cycle++ + return nil +} + +func (r *RainLayer) Draw(drawimg *ebiten.Image) { + r.Sprite.Clear() + + for _, drop := range r.raindrops { + drop.Draw() + + op := &ebiten.DrawImageOptions{} + op.GeoM.Translate(drop.GetPosition().X, drop.GetPosition().Y) + op.ColorScale.ScaleAlpha(0.5) + r.Sprite.DrawImage(drop.Sprite, op) + } + + for _, drop := range r.rainsplashes { + drop.Draw() + + op := &ebiten.DrawImageOptions{} + op.GeoM.Translate(drop.GetPosition().X, drop.GetPosition().Y) + op.ColorScale.ScaleAlpha(0.5) + r.Sprite.DrawImage(drop.Sprite, op) + } + + drawimg.DrawImage(r.Sprite, nil) + +} + +func (r *RainLayer) Initialize() { + +} + +func (r *RainLayer) RegisterEvents(e gamedata.GameEvent, f func()) { + +} + +func (r *RainLayer) UpdateDrops() { + i := 0 + for _, drop := range r.raindrops { + drop.Update() + + if !drop.Expired() { + r.raindrops[i] = drop + i++ + } else { + r.nextsplashes = append(r.nextsplashes, drop.GetPosition()) + } + } + + var j int = i + var newdrops int = 0 + for ; j < len(r.raindrops); j++ { + r.raindrops[j] = nil + } + newdrops = len(r.raindrops) - i + r.raindrops = r.raindrops[:i] + + for k := 0; k < newdrops; k++ { + nrd := elements.NewRainDrop() + nrd.SetPosition(gamedata.Coordinates{X: rand.Float64() * float64(r.dimensions.Width), Y: rand.Float64() * float64(r.dimensions.Height)}) + r.raindrops = append(r.raindrops, nrd) + } +} + +func (r *RainLayer) UpdateSplashes() { + i := 0 + for _, drop := range r.rainsplashes { + drop.Update() + + if !drop.Expired() { + r.rainsplashes[i] = drop + i++ + } + } + + var j int = i + //var newdrops int = 0 + for ; j < len(r.rainsplashes); j++ { + r.rainsplashes[j] = nil + } + //newdrops = len(r.rainsplashes) - i + r.rainsplashes = r.rainsplashes[:i] + + /* + for k := 0; k < newdrops; k++ { + nrd := elements.NewRainSplash() + nrd.SetPosition(gamedata.Coordinates{X: rand.Float64() * float64(r.dimensions.Width), Y: rand.Float64() * float64(r.dimensions.Height)}) + r.rainsplashes = append(r.rainsplashes, nrd) + }*/ + + for _, splashloc := range r.nextsplashes { + nrd := elements.NewRainSplash() + nrd.SetPosition(splashloc) + r.rainsplashes = append(r.rainsplashes, nrd) + } + + r.nextsplashes = r.nextsplashes[:0] + +} diff --git a/screenmanager/manager.go b/screenmanager/manager.go index 48f018c..cc49002 100644 --- a/screenmanager/manager.go +++ b/screenmanager/manager.go @@ -26,7 +26,7 @@ func NewManager() Manager { return Manager{ Info: gamedata.GameInfo{ Name: "survive", - Version: "0.32", + Version: "0.34", Dimensions: gamedata.Area{ Width: defaultWidth, Height: defaultHeight, diff --git a/screens/primary.go b/screens/primary.go index 647d862..da21ca1 100644 --- a/screens/primary.go +++ b/screens/primary.go @@ -50,6 +50,11 @@ func NewPrimary() *Primary { canvas.RegisterEvents(gamedata.GameEventFireball, p.EventHandlerFireball) p.elements = append(p.elements, canvas) + //rainlayer + rain := gameelement.NewRainLayer(gamearea) + rain.Initialize() + p.elements = append(p.elements, rain) + //create foreground cloud layer clouds := gameelement.NewCloudLayer(gamearea) clouds.Initialize()