Skip to content

Instantly share code, notes, and snippets.

@Koshimizu-Takehito
Last active May 4, 2024 05:35
Show Gist options
  • Save Koshimizu-Takehito/aafe14864ef6e9a058e7a459e8fadfab to your computer and use it in GitHub Desktop.
Save Koshimizu-Takehito/aafe14864ef6e9a058e7a459e8fadfab to your computer and use it in GitHub Desktop.
SqureFlowView
import SwiftUI
struct SqureFlowView: View {
@StateObject private var holder = SquresHolder()
var body: some View {
TimelineView(.animation) { timeline in
Canvas { context, size in
holder.update(at: timeline.date, in: size)
for item in holder.squre {
let shape = item.path(in: size, date: timeline.date)
context.fill(shape, with: .color(item.color))
}
}
}
.ignoresSafeArea()
}
}
private final class SquresHolder: ObservableObject {
var squre = Set<Squre>()
var maxCount = 10
func update(at date: Date, in size: CGSize) {
squre = squre.filter { $0.isAlive(at: date, in: size) }
guard squre.count < maxCount else {
return
}
squre.insert(Squre(creationDate: date))
}
}
private struct Squre: Hashable {
static let velocities = 0.02...0.1
var x: Double
var edge: Double
var creationDate: Date
var initialY: Double = .random(in: 1.0...2.0)
var velocity: Double = .random(in: velocities)
var color = Color(red: 0.2, green: 0.3, blue: 0.8).opacity(.random(in: 0.2...0.6))
init(creationDate: Date) {
self.creationDate = creationDate
self.edge = .random(in: 0.1...0.3)
self.x = max(.random(in: 0.01...0.99) - edge, 0.01)
}
func isAlive(at date: Date, in size: CGSize) -> Bool {
let duration = date.distance(to: creationDate)
let y = size.height * (initialY + duration * velocity)
let d = size.width * sqrt(2) * edge
return y + d > 0
}
func path(in size: CGSize, date: Date) -> Path {
let duration = date.distance(to: creationDate)
let edge = edge * size.width
let rect = CGRect(
x: x * size.width,
y: size.height * (initialY + duration * velocity),
width: edge,
height: edge
)
let velocity = velocity/Squre.velocities.upperBound
return RoundedRectangle(cornerRadius: max(edge/8, 4), style: .circular)
.rotation(.radians(-velocity * duration / 2))
.path(in: rect)
}
}
#Preview {
SqureFlowView()
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment