Keep improving dice roll animation logic

This commit is contained in:
CypherPoet 2020-02-12 18:10:20 -06:00
parent 582321930b
commit 4ce8accdc5
6 changed files with 90 additions and 98 deletions

View File

@ -10,8 +10,19 @@ import SwiftUI
import CypherPoetSwiftUIKit_BindingUtils
struct VerticalDiceRollView {
var diceCollection: [Dice] = []
struct VerticalDiceRollView<Content: View> {
var diceCollection: [Dice]
let content: (Int, Dice, CGPoint, CGFloat) -> Content
init(
diceCollection: [Dice] = [],
@ViewBuilder content: @escaping ((Int, Dice, CGPoint, CGFloat) -> Content)
) {
self.diceCollection = diceCollection
self.content = content
}
}
@ -22,12 +33,21 @@ extension VerticalDiceRollView: View {
GeometryReader { geometry in
ZStack {
ForEach(self.diceCollection.indexed(), id: \.0.self) { (index, dice) in
DiceView(dice: dice)
.frame(
width: self.sideLength(forDiceIn: geometry),
height: self.sideLength(forDiceIn: geometry)
)
.position(self.position(forDiceAt: index, in: geometry))
// EmptyView()
self.content(
index,
dice,
self.position(forDiceAt: index, in: geometry),
self.sideLength(forDiceIn: geometry)
)
// DiceView(dice: dice)
// .frame(
// width: self.sideLength(forDiceIn: geometry),
// height: self.sideLength(forDiceIn: geometry)
// )
// .position(self.position(forDiceAt: index, in: geometry))
// .animation(Animation.linear(duration: 0.3).delay(1.0 * Double(index)))
// .animation(Animation.linear.delay(1.0 * index))
}
}
.frame(
@ -131,7 +151,14 @@ struct VerticalDiceRollView_Previews: PreviewProvider {
// diceCollection: [.one, .two,]
// diceCollection: [.one]
diceCollection: [.one, .two, .three]
)
) { (index, dice, position, sideLength) in
DiceView(dice: dice)
.frame(
width: sideLength,
height: sideLength
)
.position(position)
}
Spacer()

View File

@ -1,73 +0,0 @@
//
// VerticalDiceSetView.swift
// Dicey
//
// Created by CypherPoet on 2/2/20.
//
//
import SwiftUI
struct VerticalDiceSetView {
var diceCount: Int = 1
var diceSideLength: CGFloat = 40.0
}
// MARK: - View
extension VerticalDiceSetView: View {
var body: some View {
GeometryReader { geometry in
Rectangle()
.fill(Color.purple)
.frame(
width: (geometry.size.width / CGFloat(self.columnCount)) - (self.columnSpacing * (CGFloat(self.columnCount - 1))),
height: (geometry.size.height / CGFloat(self.rowCount)) - (self.rowSpacing * CGFloat((self.rowCount - 1)))
)
}
}
}
// MARK: - Computeds
extension VerticalDiceSetView {
var rowSpacing: CGFloat { 16.0 }
var columnSpacing: CGFloat { 20.0 }
var rowCount: Int { ((diceCount - 1) / 2) + 1 }
var columnCount: Int { (diceCount / 2) + 1 }
// var rowCount: Int { 1 }
// var columnCount: Int { 1 }
}
// MARK: - View Variables
extension VerticalDiceSetView {
}
// MARK: - Private Helpers
private extension VerticalDiceSetView {
func diceSideLength(in geometry: GeometryProxy) {
let maxDimension = max(geometry.size.width, geometry.size.height)
}
}
// MARK: - Preview
struct DiceSetView_Previews: PreviewProvider {
static var previews: some View {
VStack {
VerticalDiceSetView(
diceCount: 4
)
}
// .environment(\.managedObjectContext, CurrentApp.coreDataManager.mainContext)
}
}

View File

@ -14,15 +14,15 @@ struct DiceGeneratorView {
@Environment(\.verticalSizeClass) var verticalSizeClass
private let diceCountRange = 1...6
private let diceRollAnimationDuration = 0.76
@ObservedObject var viewModel: ViewModel
let onDiceRolled: ((DiceRoll) -> Void)?
// @State private var diceShakeCompletionPercentage: CGFloat = 0.0
@State private var hasDiceRolledAtLeastOnce = false
@State private var isShakingDice = false
@State private var diceCollectionViewID = 1
@State private var isShowingDice = true
@State private var diceRollCompletion: CGFloat = 1.0
}
@ -35,8 +35,6 @@ extension DiceGeneratorView: View {
if isShowingDice {
diceCollectionSection
// .id(self.diceCollectionViewID)
.transition(self.diceCollectionTransition)
} else {
Color.clear
}
@ -61,11 +59,30 @@ extension DiceGeneratorView {
var diceCollectionTransition: AnyTransition {
.asymmetric(
insertion: AnyTransition
.move(edge: .bottom).combined(with: .scale(scale: 0, anchor: .top)),
.move(edge: .bottom)
.combined(with: .scale(scale: 0, anchor: .top)),
removal: AnyTransition
.opacity
)
}
var diceRollAnimation: Animation {
Animation.spring(
response: diceRollAnimationDuration,
dampingFraction: 0.635,
blendDuration: 0.0
)
}
var diceRollRotation: Angle {
.radians(
(1.0 - Double(self.diceRollCompletion))
* (.pi * Double.random(in: 0...1))
)
}
// TODO: Improve this logic
@ -88,7 +105,25 @@ extension DiceGeneratorView {
if self.isShowingHorizontalDiceLayout {
HorizontalDiceRollView(diceCollection: self.viewModel.diceCollection)
} else {
VerticalDiceRollView(diceCollection: self.viewModel.diceCollection)
VerticalDiceRollView(diceCollection: self.viewModel.diceCollection) { (index, dice, position, sideLength) in
DiceView(dice: dice)
.frame(
width: sideLength,
height: sideLength
)
.position(position)
.rotation3DEffect(
self.diceRollRotation,
axis: (x: 0.0, y: 0.0, z: 1.0)
)
.offset(
x: 0,
y: (
(-1.0 * (1.0 - self.diceRollCompletion) * CGFloat(geometry.size.height))
- ((1.0 - self.diceRollCompletion) * position.y)
)
)
}
}
}
.offset(self.offsetFromShake(in: geometry))
@ -100,28 +135,31 @@ extension DiceGeneratorView {
private var rollButton: some View {
Button(action: {
// self.onDiceRolled?(viewModel.diceRollFromForm)
self.hasDiceRolledAtLeastOnce = true
// Shake the current set
withAnimation(
Animation
.timingCurve(0.3, 0.3, 0.7, 2.7, duration: 0.07)
.repeatCount(10, autoreverses: true)
.timingCurve(0.3, 0.3, 0.7, 2.7, duration: 0.11)
.repeatCount(8, autoreverses: true)
) {
self.isShakingDice = true
}
DispatchQueue.main.asyncAfter(deadline: .now() + (0.07 * 10)) {
// self.diceCollectionViewID += 1
// Roll in the new set
DispatchQueue.main.asyncAfter(deadline: .now() + (0.11 * 8)) {
self.isShakingDice = false
self.isShowingDice = false
self.diceRollCompletion = 0.0
DispatchQueue.main.async {
withAnimation(.linear(duration: 2)) {
self.isShowingDice = true
self.isShowingDice = true
// 📝 TODO: Compute and set the new dice values here
withAnimation(self.diceRollAnimation) {
self.diceRollCompletion = 1.0
}
}
// self.isShowingDice = true
}
}) {
Image("roll-dice")

Binary file not shown.

After

Width:  |  Height:  |  Size: 501 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1004 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB