Last active
May 29, 2022 03:44
-
-
Save maiyama18/1d25f90deadcf775fa274176c5d79d82 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) | |
} | |
} |
Author
maiyama18
commented
May 29, 2022
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment