Skip to content

Instantly share code, notes, and snippets.

@maiyama18
Last active May 29, 2022 03:44
Show Gist options
  • Save maiyama18/1d25f90deadcf775fa274176c5d79d82 to your computer and use it in GitHub Desktop.
Save maiyama18/1d25f90deadcf775fa274176c5d79d82 to your computer and use it in GitHub Desktop.
import SwiftUI
class Particle {
var position: CGPoint
var velocity: CGPoint
var color: Color
var size: CGFloat
init(position: CGPoint, velocity: CGPoint, color: Color, size: CGFloat) {
self.position = position
self.velocity = velocity
self.color = color
self.size = size
}
func update(size: CGSize) {
// update x
position.x += velocity.x
if position.x < 0.5 * self.size {
position.x = self.size - position.x
velocity.x *= -1
}
if position.x > (size.width - 0.5 * self.size) {
position.x = 2 * (size.width - 0.5 * self.size) - position.x
velocity.x *= -1
}
// update y
position.y += velocity.y
if position.y < 0.5 * self.size {
position.y = self.size - position.y
velocity.y *= -1
}
if position.y > (size.height - 0.5 * self.size) {
position.y = 2 * (size.height - 0.5 * self.size) - position.y
velocity.y *= -1
}
velocity.y += 0.1
}
static func random(in frame: CGSize, maxVelocity: CGFloat = 3, maxSize: CGFloat = 20) -> Particle {
let positionX = Double.random(in: 0...1) * frame.width
let positionY = Double.random(in: 0...1) * frame.height
let velocity = Double.random(in: maxVelocity * 0.1...maxVelocity)
let theta = Double.random(in: 0..<360) * Double.pi / 180
let velocityX = velocity * cos(theta)
let velocityY = velocity * sin(theta)
let color = [Color.white, Color.teal, Color.purple, Color.cyan, Color.black, Color.indigo].randomElement()!
let size = Double.random(in: maxSize * 0.1...maxSize)
return .init(
position: .init(x: positionX, y: positionY),
velocity: .init(x: velocityX, y: velocityY),
color: color,
size: size
)
}
}
class Model {
private let particleCount = 500
var particles: [Particle] = []
var contexts: [GraphicsContext] = []
func initializeIfNeeded(size: CGSize) {
guard particles.isEmpty else { return }
for _ in 0..<particleCount {
particles.append(Particle.random(in: size))
}
}
func update(size: CGSize, date: TimeInterval) {
for particle in particles {
particle.update(size: size)
}
}
}
struct ContentView: View {
@State private var model: Model = .init()
var body: some View {
TimelineView(.animation) { timeline in
Canvas { context, size in
model.initializeIfNeeded(size: size)
model.update(size: size, date: timeline.date.timeIntervalSince1970)
context.blendMode = .plusLighter
for particle in model.particles {
context.fill(
Path(
ellipseIn: .init(
x: particle.position.x - 0.5 * particle.size,
y: particle.position.y - 0.5 * particle.size,
width: particle.size,
height: particle.size
)
),
with: .color(particle.color.opacity(0.5))
)
}
}
}
.ignoresSafeArea()
.background(.black)
}
}
@maiyama18
Copy link
Author

canvas

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment