progressive refactor

This commit is contained in:
Maas Lalani 2021-08-08 21:06:10 -04:00
parent d4669cfdd0
commit c5f3d26331
No known key found for this signature in database
GPG Key ID: F53774FA051C052A
2 changed files with 93 additions and 95 deletions

View File

@ -3,16 +3,13 @@
package fireworks package fireworks
import ( import (
"fmt"
"math" "math"
"math/rand" "math/rand"
"strings"
"time" "time"
"github.com/maaslalani/confetty/array" "github.com/maaslalani/confetty/array"
"github.com/maaslalani/confetty/physics" "github.com/maaslalani/confetty/physics"
"github.com/charmbracelet/bubbles/viewport"
tea "github.com/charmbracelet/bubbletea" tea "github.com/charmbracelet/bubbletea"
"github.com/charmbracelet/lipgloss" "github.com/charmbracelet/lipgloss"
"golang.org/x/term" "golang.org/x/term"
@ -26,10 +23,10 @@ const (
var ( var (
colors = []string{"#fdff6a", "#ff718d"} colors = []string{"#fdff6a", "#ff718d"}
characters = []string{"+", "*", "•"} characters = []string{"+", "*", "•"}
// characters = []string{"▄", "▀"}
) )
type frameMsg time.Time type frameMsg time.Time
type fireworkMsg time.Time
func animate() tea.Cmd { func animate() tea.Cmd {
return tea.Tick(time.Second/framesPerSecond, func(t time.Time) tea.Msg { return tea.Tick(time.Second/framesPerSecond, func(t time.Time) tea.Msg {
@ -37,63 +34,52 @@ func animate() tea.Cmd {
}) })
} }
func wait(d time.Duration) tea.Cmd {
return func() tea.Msg {
time.Sleep(d)
return nil
}
}
// Fireworks model
type model struct { type model struct {
particles []*Particle system *System
viewport viewport.Model
}
type Particle struct {
char string
physics *physics.Physics
}
func spawn() []*Particle {
width, height, err := term.GetSize(0)
if err != nil {
panic(err)
} }
func spawn(width, height int) []Particle {
color := lipgloss.Color(array.Sample(colors)) color := lipgloss.Color(array.Sample(colors))
v := float64(rand.Intn(10) + 20.0) v := float64(rand.Intn(10) + 20.0)
particles := []*Particle{} particles := []Particle{}
x := rand.Float64() * float64(width) x := rand.Float64() * float64(width)
y := rand.Float64() * float64(height) y := rand.Float64() * float64(height)
for i := 0; i < numParticles; i++ { for i := 0; i < numParticles; i++ {
p := &Particle{ p := Particle{
physics: physics.New( Physics: physics.New(
physics.Point{X: x, Y: y}, physics.Point{X: x, Y: y},
physics.Vector{X: math.Cos(float64(i)) * v, Y: math.Sin(float64(i)) * v / 2}, physics.Vector{X: math.Cos(float64(i)) * v, Y: math.Sin(float64(i)) * v / 2},
physics.Vector(physics.Gravity), physics.Vector(physics.Gravity),
framesPerSecond, framesPerSecond,
), ),
char: lipgloss.NewStyle(). Char: lipgloss.NewStyle().Foreground(color).Render(array.Sample(characters)),
Foreground(color).
Render(array.Sample(characters)),
} }
particles = append(particles, p) particles = append(particles, p)
} }
return particles return particles
} }
func InitialModel() model { func InitialModel() model {
return model{particles: spawn()} width, height, err := term.GetSize(0)
if err != nil {
panic(err)
}
return model{system: &System{
Particles: spawn(width, height),
Frame: Frame{
Width: width,
Height: height,
},
}}
} }
// Init initializes the confetti after a small delay // Init initializes the confetti after a small delay
func (m model) Init() tea.Cmd { func (m model) Init() tea.Cmd {
return tea.Sequentially(wait(time.Second/2), animate()) return animate()
} }
// Update updates the model every frame, it handles the animation loop and // Update updates the model every frame, it handles the animation loop and
@ -102,34 +88,13 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
switch msg := msg.(type) { switch msg := msg.(type) {
case tea.KeyMsg: case tea.KeyMsg:
return m, tea.Quit return m, tea.Quit
// frame animation
case frameMsg: case frameMsg:
particlesVisible := numParticles m.system.Update()
for _, p := range m.particles {
p.physics.Update()
y := p.physics.PosY()
x := p.physics.PosX()
// Particle is out of view
if y < 0 || y >= m.viewport.Height-1 || x < 0 || x >= m.viewport.Width-1 {
particlesVisible -= 1
continue
}
}
if particlesVisible <= 0 {
m.particles = spawn()
}
return m, animate() return m, animate()
case tea.WindowSizeMsg: case tea.WindowSizeMsg:
m.viewport.Width = msg.Width m.system.Frame.Width = msg.Width
m.viewport.Height = msg.Height m.system.Frame.Height = msg.Height
return m, nil return m, nil
default: default:
return m, nil return m, nil
} }
@ -137,41 +102,5 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
// View displays all the particles on the screen // View displays all the particles on the screen
func (m model) View() string { func (m model) View() string {
height := m.viewport.Height return m.system.Render()
width := m.viewport.Width
if height <= 0 || width <= 0 {
return ""
}
var out strings.Builder
grid := make([][]string, m.viewport.Height)
for i := range grid {
grid[i] = make([]string, m.viewport.Width)
}
for _, p := range m.particles {
y := p.physics.PosY()
x := p.physics.PosX()
if y < 0 || x < 0 || y >= height-1 || x >= width-1 {
continue
}
grid[y][x] = p.char
}
// Print out grid
for i := range grid {
for _, col := range grid[i] {
if col == "" {
fmt.Fprint(&out, " ")
} else {
fmt.Fprint(&out, col)
}
}
fmt.Fprint(&out, "\n")
}
return out.String()
} }

69
fireworks/system.go Normal file
View File

@ -0,0 +1,69 @@
package fireworks
import (
"fmt"
"strings"
"github.com/maaslalani/confetty/physics"
)
type System struct {
Frame Frame
Particles []Particle
}
type Particle struct {
Char string
Physics *physics.Physics
Hidden bool
}
type Frame struct {
Width int
Height int
}
func (s *System) Update() {
for _, p := range s.Particles {
if p.Hidden {
continue
}
if !s.Visible(p) {
p.Hidden = true
continue
}
p.Physics.Update()
}
}
func (s *System) Visible(p Particle) bool {
y := p.Physics.PosY()
x := p.Physics.PosX()
return y >= 0 && y < s.Frame.Height-1 && x >= 0 && x < s.Frame.Width-1
}
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) {
plane[p.Physics.PosY()][p.Physics.PosX()] = p.Char
}
}
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()
}