Added particles on splash.

This commit is contained in:
Sander Schobers 2019-12-29 17:25:41 +01:00
parent a4ab1a265e
commit d8c0f489aa
6 changed files with 128 additions and 2 deletions

View File

@ -1,6 +1,8 @@
package main
import (
"math"
"math/rand"
"time"
"opslag.de/schobers/geom"
@ -50,3 +52,77 @@ func (a *sinkAnimation) Animate(start, now time.Duration) bool {
a.e.scr.z = progress * 80
return true
}
type splashAnimation struct {
particles []splashParticle
}
func newSplashAnimation(pos geom.Point) *splashAnimation {
pos32 := pos.ToF32()
a := &splashAnimation{}
n := rand.Intn(20) + 4
for i := 0; i < n; i++ {
angle := rand.Float32() * math.Pi * 2
a.particles = append(a.particles, splashParticle{
angle: angle,
origin: pos32.Add2D(.45*geom.Cos32(angle), .45*geom.Sin32(angle)), // [-0.45 .. 0.45]
speed: .5*math.Pi + 2*math.Pi*rand.Float32(), // [0.5*Pi .. 2.5*Pi)
height: .2 + .8*rand.Float32(), // [0.2 .. 1.0)
dist: .5 + .5*rand.Float32(), // [0.5 .. 1.0)
})
}
return a
}
func (a *splashAnimation) Animate(start, now time.Duration) bool {
const duration = 1670 * time.Millisecond
progress := float32((now-start)*1000/duration) * .001
var opaq float32 = 1
if progress > .6 {
if progress > 1 {
opaq = 0
} else {
opaq = 2.5 - 2.5*progress
}
}
for i, p := range a.particles {
progress := geom.Min32(math.Pi, progress*p.speed) / math.Pi
a.particles[i].part = particle{
opaq: opaq,
pos: p.origin.Add2D(progress*p.dist*geom.Cos32(p.angle), progress*p.dist*geom.Sin32(p.angle)),
z: 20 + p.height*-100*geom.Sin32(progress*math.Pi),
}
}
if progress > 1 {
return false
}
return true
}
type particle struct {
pos geom.PointF32
z float32
opaq float32
}
func splitParticles(y float32, particles []particle) (behind []particle, front []particle) {
for _, p := range particles {
if p.pos.Y > y {
front = append(front, p)
} else {
behind = append(behind, p)
}
}
return
}
type splashParticle struct {
origin geom.PointF32
angle float32
speed float32
height float32
dist float32
part particle
}

View File

@ -156,7 +156,8 @@ func (g *game) loadAssets() error {
"tile_lava_brick.png": "lava_brick",
"tile_magma.png": "magma",
"ui.png": "ui",
"particles.png": "particles",
"ui.png": "ui",
})
if err != nil {
return err
@ -178,7 +179,7 @@ func (g *game) loadAssets() error {
log.Printf("Loaded %d fonts.\n", g.ui.Fonts().Len())
log.Println("Loading sprites")
err = g.loadSprites("brick", "dragon", "lava_brick", "magma", "ui", "villain")
err = g.loadSprites("brick", "dragon", "lava_brick", "magma", "particles", "ui", "villain")
if err != nil {
return err
}

View File

@ -178,8 +178,21 @@ func (l *playLevel) drawSprite(name, partName string, pos entityLoc) {
l.ctx.SpriteDrawer.Draw(name, partName, l.posToScreenF32(pos.pos, pos.z), DrawSpriteOptions{Scale: l.scale})
}
func (l *playLevel) drawSpriteAlpha(name, partName string, pos entityLoc, alpha float32) {
a := byte(alpha * 255)
c := allg5.NewColorAlpha(a, a, a, a)
l.ctx.SpriteDrawer.Draw(name, partName, l.posToScreenF32(pos.pos, pos.z), DrawSpriteOptions{Scale: l.scale, Tint: &c})
}
func (l *playLevel) Render(ctx *alui.Context, bounds geom.RectangleF32) {
level := l.state.level
drawParticles := func(particles []particle) {
for _, p := range particles {
l.drawSpriteAlpha("particles", "splash", entityLoc{p.pos, p.z}, p.opaq)
}
}
for i, t := range level.tiles {
pos := geom.Pt(i%level.width, i/level.width)
scr := entityLoc{pos.ToF32(), 0}
@ -194,8 +207,11 @@ func (l *playLevel) Render(ctx *alui.Context, bounds geom.RectangleF32) {
l.drawSprite("magma", "magma", scr)
brick := l.state.FindSunkenBrick(pos)
if brick != nil {
behind, front := splitParticles(scr.pos.Y, l.state.Particles(pos))
drawParticles(behind)
l.drawSprite("brick", "brick", brick.scr)
l.drawSprite("magma", "sunken_overlay", scr)
drawParticles(front)
}
}
}

View File

@ -18,6 +18,7 @@ type playLevelState struct {
villain *entity
bricks entityList
sunken entityList
splash map[geom.Point]*splashAnimation
steps int
complete bool
@ -33,6 +34,20 @@ func (s *playLevelState) Entities() entityList {
return entities.Add(s.player).Add(s.villain).AddList(s.bricks)
}
func (s *playLevelState) Particles(at geom.Point) []particle {
var particles []particle
for pos, ani := range s.splash {
if pos != at {
continue
}
log.Println("Found particles at", at)
for _, p := range ani.particles {
particles = append(particles, p.part)
}
}
return particles
}
func (s *playLevelState) FindSunkenBrick(pos geom.Point) *entity {
return s.sunken.FindEntity(pos)
}
@ -50,6 +65,7 @@ func (s *playLevelState) Init(ctx *Context, pack, level string, onComplete func(
s.level = s.pack.levels[level]
s.bricks = nil
s.sunken = nil
s.splash = map[geom.Point]*splashAnimation{}
for i, e := range s.level.entities {
switch e {
case entityTypeBrick:
@ -116,6 +132,12 @@ func (s *playLevelState) TryPlayerMove(dir geom.Point, key allg5.Key) {
s.bricks = s.bricks.Remove(brickTo)
s.sunken = s.sunken.Add(brick)
s.ani.Start(s.ctx.Tick, newSinkAnimation(brick))
splash := newSplashAnimation(brickTo)
s.splash[brickTo] = splash
s.ani.StartFn(s.ctx.Tick, splash, func() {
delete(s.splash, brickTo)
})
}
})
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.8 KiB

View File

@ -0,0 +1,11 @@
sprite:
texture: particles
part:
name: splash
sub_texture: 0,0,96,96
anchor: 48,48
scale: 6
:part
:sprite