2021-08-09 01:08:28 +00:00
|
|
|
package simulation
|
2021-08-09 01:06:10 +00:00
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"strings"
|
2021-10-31 18:57:51 +00:00
|
|
|
"time"
|
2021-08-09 01:06:10 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
type System struct {
|
|
|
|
Frame Frame
|
2021-10-31 19:51:36 +00:00
|
|
|
Particles []*Particle
|
2021-08-09 01:06:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
type Particle struct {
|
2021-10-31 18:57:51 +00:00
|
|
|
Char string
|
|
|
|
TailChar string
|
|
|
|
Physics *Projectile
|
|
|
|
Hidden bool
|
|
|
|
Shooting bool
|
2021-10-31 19:51:36 +00:00
|
|
|
ExplosionCall func(x, y float64, width, height int) []*Particle
|
2021-08-09 01:06:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
type Frame struct {
|
|
|
|
Width int
|
|
|
|
Height int
|
|
|
|
}
|
|
|
|
|
2021-10-31 18:57:51 +00:00
|
|
|
func FPS(n int) float64 {
|
|
|
|
return (time.Second / time.Duration(n)).Seconds()
|
|
|
|
}
|
|
|
|
|
2021-10-31 19:51:36 +00:00
|
|
|
func RemoveParticleFromArray(s []*Particle, i int) []*Particle {
|
|
|
|
s[i] = nil
|
2021-10-31 17:58:01 +00:00
|
|
|
s[i] = s[len(s)-1]
|
|
|
|
return s[:len(s)-1]
|
|
|
|
}
|
|
|
|
|
2021-08-09 01:06:10 +00:00
|
|
|
func (s *System) Update() {
|
2021-10-31 18:07:22 +00:00
|
|
|
for i := len(s.Particles) - 1; i >= 0; i-- {
|
2021-10-31 18:57:51 +00:00
|
|
|
p := s.Particles[i]
|
|
|
|
pos := p.Physics.Position
|
|
|
|
|
|
|
|
// if the shooting particle is slow enough then hide it and call the explosion function
|
|
|
|
if !p.Hidden && p.Shooting && p.Physics.Velocity.Y > -3 {
|
|
|
|
p.Hidden = true
|
|
|
|
if p.ExplosionCall != nil {
|
|
|
|
s.Particles = append(s.Particles, p.ExplosionCall(p.Physics.Position.X, p.Physics.Position.Y, s.Frame.Width, s.Frame.Height)...)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// remove particles that are hidden or out of the side/bottom of the frame
|
|
|
|
if p.Hidden || pos.X > float64(s.Frame.Width) || pos.X < 0 || pos.Y > float64(s.Frame.Height) {
|
2021-10-31 18:07:22 +00:00
|
|
|
s.Particles = RemoveParticleFromArray(s.Particles, i)
|
|
|
|
} else {
|
|
|
|
s.Particles[i].Physics.Update()
|
|
|
|
}
|
2021-08-09 01:06:10 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-10-31 19:51:36 +00:00
|
|
|
func (s *System) Visible(p *Particle) bool {
|
2021-10-31 18:57:51 +00:00
|
|
|
y := int(p.Physics.Position.Y)
|
|
|
|
x := int(p.Physics.Position.X)
|
|
|
|
return !p.Hidden && y >= 0 && y < s.Frame.Height-1 && x >= 0 && x < s.Frame.Width-1
|
2021-08-09 01:06:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (s *System) Render() string {
|
|
|
|
var out strings.Builder
|
|
|
|
plane := make([][]string, s.Frame.Height)
|
|
|
|
for i := range plane {
|
|
|
|
plane[i] = make([]string, s.Frame.Width)
|
|
|
|
}
|
|
|
|
for _, p := range s.Particles {
|
|
|
|
if s.Visible(p) {
|
2021-10-31 18:57:51 +00:00
|
|
|
plane[int(p.Physics.Position.Y)][int(p.Physics.Position.X)] = p.Char
|
|
|
|
if p.Shooting {
|
|
|
|
l := -int(p.Physics.Velocity.Y)
|
|
|
|
for i := 1; i < l; i++ {
|
|
|
|
y := int(p.Physics.Position.Y) + i
|
|
|
|
if y > 0 && y < s.Frame.Height-1 {
|
|
|
|
plane[y][int(p.Physics.Position.X)] = p.TailChar
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-08-09 01:06:10 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
for i := range plane {
|
|
|
|
for _, col := range plane[i] {
|
|
|
|
if col == "" {
|
|
|
|
fmt.Fprint(&out, " ")
|
|
|
|
} else {
|
|
|
|
fmt.Fprint(&out, col)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
fmt.Fprint(&out, "\n")
|
|
|
|
}
|
|
|
|
return out.String()
|
|
|
|
}
|