Caemitterlayer случайным образом не испускает частицыIOS

Программируем под IOS
Ответить
Anonymous
 Caemitterlayer случайным образом не испускает частицы

Сообщение Anonymous »

Я реализую эффект конфетти с помощью частиц. Я использовал для этого CAEmitterLayer, и он работает почти хорошо, но иногда частицы не испускаются. Я старался изо всех сил и отладил его (установил цвета для слоев эмиттера) и знаю, что слои добавлены. Вот полный код:

Код: Выделить всё

import UIKit

final class ViewController: UIViewController {

// MARK: - UI

private lazy var actionButton: UIButton = { [weak self] in
let button = UIButton(type: .system)
button.translatesAutoresizingMaskIntoConstraints = false
button.setTitle("Start confetti", for: .normal)
button.setTitleColor(.white, for: .normal)
button.backgroundColor = .systemBlue
button.layer.cornerRadius = 16
button.addAction(UIAction { _ in
self?.startConfettiShow()
}, for: .touchUpInside)
return button
}()

private let confettiContainer: UIView = {
let view = UIView()
view.translatesAutoresizingMaskIntoConstraints = false
view.backgroundColor = .white
view.clipsToBounds = true
return view
}()

// MARK: - Lifecycle

override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .gray

view.addSubview(confettiContainer)
view.addSubview(actionButton)

NSLayoutConstraint.activate([
confettiContainer.centerXAnchor.constraint(equalTo: view.centerXAnchor),
confettiContainer.bottomAnchor.constraint(equalTo: actionButton.topAnchor, constant: -50),
confettiContainer.widthAnchor.constraint(equalToConstant: 300),
confettiContainer.heightAnchor.constraint(equalToConstant: 300),

actionButton.centerXAnchor.constraint(equalTo: view.centerXAnchor),
actionButton.centerYAnchor.constraint(equalTo: view.centerYAnchor, constant: 200),
actionButton.widthAnchor.constraint(equalToConstant: 150),
actionButton.heightAnchor.constraint(equalToConstant: 40),
])
}

// MARK: - Confetti Logic

private func startConfettiShow() {
// Remove old emitters
confettiContainer.layer.sublayers?.removeAll(where: { $0 is CAEmitterLayer })
view.layoutIfNeeded()

let xOffset: CGFloat = 90
let emissionOffset: CGFloat = 0.1

let left = makeEmitter(xOffset: -xOffset, emissionLongitudeOffset: emissionOffset)
let right = makeEmitter(xOffset: xOffset, emissionLongitudeOffset: -emissionOffset)

confettiContainer.layer.addSublayer(left)
confettiContainer.layer.addSublayer(right)

debugEmitter(left, color: .red)
debugEmitter(right, color: .yellow)

DispatchQueue.main.async {
CATransaction.begin()
CATransaction.setDisableActions(true)

let now = CACurrentMediaTime()
left.beginTime = now
right.beginTime = now
left.birthRate = 1
right.birthRate = 1

CATransaction.commit()
}

// Stop emission
DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) {
left.birthRate = 0
right.birthRate = 0
}

// Remove the layers
DispatchQueue.main.asyncAfter(deadline: .now() + 5.0) {
left.removeFromSuperlayer()
right.removeFromSuperlayer()
}
}

private func makeEmitter(xOffset: CGFloat,
emissionLongitudeOffset: CGFloat) ->  CAEmitterLayer {
let emitter = CAEmitterLayer()
emitter.frame = confettiContainer.bounds
emitter.emitterShape = .point
emitter.emitterPosition = CGPoint(
x: confettiContainer.bounds.midX + xOffset,
y: confettiContainer.bounds.maxY - 10
)
emitter.birthRate = 0

let cells: [CAEmitterCell] = ViewController.colors.flatMap { color in
ViewController.shapes.map { shape in
let cell = CAEmitterCell()
cell.birthRate = 15
cell.lifetime = 3.5
cell.velocity = .random(in: 250...400)
cell.velocityRange = 80
cell.emissionLongitude = -.pi / 2 + emissionLongitudeOffset
cell.emissionRange = .pi / 8
cell.yAcceleration = 200
cell.spin = .random(in: -3...3)
cell.spinRange = 4
cell.scale = .random(in: 0.08...0.14)
cell.alphaSpeed = -0.4
cell.color = color.cgColor
cell.contents = shape
return cell
}
}

emitter.emitterCells = cells
return emitter
}

private func debugEmitter(_ emitter: CAEmitterLayer, color: UIColor) {
emitter.borderColor = color.cgColor
emitter.borderWidth = 1
emitter.backgroundColor = color.withAlphaComponent(0.15).cgColor
print("Emitter frame:", emitter.frame)
print("Emitter position:", emitter.emitterPosition)
}
}

// MARK: - Static resources

private extension ViewController {
static let colors: [UIColor] = [
.systemPink, .systemYellow, .systemBlue, .systemGreen, .systemPurple
]

static let shapes: [CGImage] = [
CGImage.cgImageCircle(diameter: 36),
CGImage.cgImageSquare(side: 32),
CGImage.cgImageTriangle(size: 36),
].compactMap { $0 }
}

// MARK: - Shape generators

extension CGImage {
static func cgImageCircle(diameter: CGFloat) -> CGImage? {
let size = CGSize(width: diameter, height: diameter)
return UIGraphicsImageRenderer(size: size).image { ctx in
UIColor.white.setFill()
ctx.cgContext.fillEllipse(in: CGRect(origin: .zero, size: size))
}.cgImage
}

static func cgImageSquare(side: CGFloat) -> CGImage? {
let size = CGSize(width: side, height: side)
return UIGraphicsImageRenderer(size: size).image { ctx in
UIColor.white.setFill()
ctx.cgContext.fill(CGRect(origin: .zero, size: size))
}.cgImage
}

static func cgImageTriangle(size: CGFloat) -> CGImage? {
let s = CGSize(width: size, height: size)
return UIGraphicsImageRenderer(size: s).image { ctx in
UIColor.white.setFill()
let path = UIBezierPath()
path.move(to: CGPoint(x: s.width / 2, y: 0))
path.addLine(to: CGPoint(x: s.width, y: s.height))
path.addLine(to: CGPoint(x: 0, y: s.height))
path.close()
path.fill()
}.cgImage
}
}
Я настройка Betrintime и рождение После добавления излучателей в уровень просмотра я даже использовал catransaction.begin () и catransaction.commit () (советы CHATGPT), но это не сработало. Со всеми этими улучшениями он начал работать лучше, я вижу меньше излучателей, которые не работают, но все же иногда он не работает, поэтому элемент нестабилен. < /P>
Проверьте скриншот. Есть два излучателя, но только один излучает. Редко они не излучают оба.>

Подробнее здесь: https://stackoverflow.com/questions/797 ... -particles
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «IOS»