큰하트 애니메이션 대기열 처리 추가
This commit is contained in:
@@ -256,6 +256,15 @@ final class LiveRoomViewModel: NSObject, ObservableObject {
|
|||||||
private let sequenceMinInterval: TimeInterval = 1.0
|
private let sequenceMinInterval: TimeInterval = 1.0
|
||||||
// 마지막 폭발 후 비 시작 허용 시각(지연 0.5s 반영)
|
// 마지막 폭발 후 비 시작 허용 시각(지연 0.5s 반영)
|
||||||
private var rainEligibleAt: Date? = nil
|
private var rainEligibleAt: Date? = nil
|
||||||
|
private enum BigHeartSequenceState {
|
||||||
|
case idle
|
||||||
|
case exploding
|
||||||
|
case waitingForRain
|
||||||
|
case raining
|
||||||
|
}
|
||||||
|
private var bigHeartSequenceState: BigHeartSequenceState = .idle
|
||||||
|
private var bigHeartAnimationQueueCount: Int = 0
|
||||||
|
private var isBigHeartAnimationPlaying: Bool = false
|
||||||
|
|
||||||
var signatureImageUrls = [String]()
|
var signatureImageUrls = [String]()
|
||||||
var signatureList = [LiveRoomDonationResponse]()
|
var signatureList = [LiveRoomDonationResponse]()
|
||||||
@@ -2113,6 +2122,15 @@ final class LiveRoomViewModel: NSObject, ObservableObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private func addBigHeartAnimation() {
|
private func addBigHeartAnimation() {
|
||||||
|
if isBigHeartAnimationPlaying {
|
||||||
|
bigHeartAnimationQueueCount += 1
|
||||||
|
return
|
||||||
|
}
|
||||||
|
isBigHeartAnimationPlaying = true
|
||||||
|
startBigHeartAnimation()
|
||||||
|
}
|
||||||
|
|
||||||
|
private func startBigHeartAnimation() {
|
||||||
// 로컬 발신 직후 1회는 원격 물 채움 연출을 생략하고 바로 연쇄 폭발만 실행
|
// 로컬 발신 직후 1회는 원격 물 채움 연출을 생략하고 바로 연쇄 폭발만 실행
|
||||||
if suppressNextRemoteWaterFill {
|
if suppressNextRemoteWaterFill {
|
||||||
suppressNextRemoteWaterFill = false
|
suppressNextRemoteWaterFill = false
|
||||||
@@ -2120,10 +2138,14 @@ final class LiveRoomViewModel: NSObject, ObservableObject {
|
|||||||
startExplosionSequence()
|
startExplosionSequence()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// 스로틀: 과도한 중복 실행 방지
|
// 스로틀: 과도한 중복 실행 방지(드랍 대신 지연)
|
||||||
let now = Date()
|
let now = Date()
|
||||||
if now.timeIntervalSince(lastSequenceStartedAt) < sequenceMinInterval {
|
let elapsed = now.timeIntervalSince(lastSequenceStartedAt)
|
||||||
DEBUG_LOG("BIG_HEART: throttled to protect performance")
|
if elapsed < sequenceMinInterval {
|
||||||
|
let delay = sequenceMinInterval - elapsed
|
||||||
|
DispatchQueue.main.asyncAfter(deadline: .now() + delay) { [weak self] in
|
||||||
|
self?.startBigHeartAnimation()
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
lastSequenceStartedAt = now
|
lastSequenceStartedAt = now
|
||||||
@@ -2240,6 +2262,7 @@ final class LiveRoomViewModel: NSObject, ObservableObject {
|
|||||||
|
|
||||||
DispatchQueue.main.async { [weak self] in
|
DispatchQueue.main.async { [weak self] in
|
||||||
guard let self = self else { return }
|
guard let self = self else { return }
|
||||||
|
self.bigHeartSequenceState = .exploding
|
||||||
self.pendingExplosionBursts = 7
|
self.pendingExplosionBursts = 7
|
||||||
|
|
||||||
let bounds = UIScreen.main.bounds
|
let bounds = UIScreen.main.bounds
|
||||||
@@ -2257,8 +2280,10 @@ final class LiveRoomViewModel: NSObject, ObservableObject {
|
|||||||
self.explosionSequenceTimer = nil
|
self.explosionSequenceTimer = nil
|
||||||
|
|
||||||
// 마지막 폭발 후 0.5초 지연 뒤 비 시작
|
// 마지막 폭발 후 0.5초 지연 뒤 비 시작
|
||||||
|
self.bigHeartSequenceState = .waitingForRain
|
||||||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { [weak self] in
|
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { [weak self] in
|
||||||
guard let self = self else { return }
|
guard let self = self else { return }
|
||||||
|
self.bigHeartSequenceState = .raining
|
||||||
let rains = self.spawnHeartRainFromLastExplosion()
|
let rains = self.spawnHeartRainFromLastExplosion()
|
||||||
if !rains.isEmpty {
|
if !rains.isEmpty {
|
||||||
self.bigHeartParticles.append(contentsOf: rains)
|
self.bigHeartParticles.append(contentsOf: rains)
|
||||||
@@ -2266,6 +2291,9 @@ final class LiveRoomViewModel: NSObject, ObservableObject {
|
|||||||
self.startParticlesTimer()
|
self.startParticlesTimer()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if rains.isEmpty && self.pendingExplosionBursts == 0 && self.bigHeartParticles.isEmpty {
|
||||||
|
self.completeBigHeartAnimation()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -2404,16 +2432,35 @@ final class LiveRoomViewModel: NSObject, ObservableObject {
|
|||||||
}
|
}
|
||||||
self.bigHeartParticles = merged
|
self.bigHeartParticles = merged
|
||||||
if merged.isEmpty && self.pendingExplosionBursts == 0 {
|
if merged.isEmpty && self.pendingExplosionBursts == 0 {
|
||||||
|
switch self.bigHeartSequenceState {
|
||||||
|
case .waitingForRain, .exploding:
|
||||||
|
break
|
||||||
|
case .raining:
|
||||||
|
self.completeBigHeartAnimation()
|
||||||
|
self.bigHeartParticleTimer?.cancel()
|
||||||
|
self.bigHeartParticleTimer = nil
|
||||||
|
case .idle:
|
||||||
self.bigHeartParticleTimer?.cancel()
|
self.bigHeartParticleTimer?.cancel()
|
||||||
self.bigHeartParticleTimer = nil
|
self.bigHeartParticleTimer = nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
timer.resume()
|
timer.resume()
|
||||||
self.bigHeartParticleTimer = timer
|
self.bigHeartParticleTimer = timer
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private func completeBigHeartAnimation() {
|
||||||
|
self.bigHeartSequenceState = .idle
|
||||||
|
self.isBigHeartAnimationPlaying = false
|
||||||
|
if self.bigHeartAnimationQueueCount > 0 {
|
||||||
|
self.bigHeartAnimationQueueCount -= 1
|
||||||
|
self.isBigHeartAnimationPlaying = true
|
||||||
|
self.startBigHeartAnimation()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private func invalidateChat() {
|
private func invalidateChat() {
|
||||||
messageChangeFlag.toggle()
|
messageChangeFlag.toggle()
|
||||||
if messages.count > 100 {
|
if messages.count > 100 {
|
||||||
|
|||||||
Reference in New Issue
Block a user