简体   繁体   English

未调用UICollisionBehaviorDelegate方法

[英]UICollisionBehaviorDelegate methods not called

I worked on an app and implemented collision detection using UIKitDynamics. 我使用UIKitDynamics开发应用程序并实现碰撞检测。

Collision detection is working. 碰撞检测正在发挥作用。 But somehow the UICollisionBehaviorDelegate methods are not called. 但不知何故,没有调用UICollisionBehaviorDelegate方法。 No warnings or errors are shown. 没有显示警告或错误。

I created an example project to demonstrate the issue: 我创建了一个示例项目来演示该问题:

  import UIKit

  class ViewController: UIViewController {
    private var dynamicAnimator: UIDynamicAnimator?

    override func viewDidLoad() {
      super.viewDidLoad()
      // Do any additional setup after loading the view, typically from a nib.
    }

    override func viewDidAppear(_ animated: Bool) {
      super.viewDidAppear(animated)

      self.initPhysics()
    }

    fileprivate var initalized = false
    fileprivate func initPhysics() {
      if initalized {
        return
      }
      initalized = true

      let physicsView = UIView(frame: view.bounds.insetBy(dx: 40, dy: 40))
      physicsView.backgroundColor = UIColor.black

      self.dynamicAnimator = UIDynamicAnimator(referenceView: physicsView)

      physicsView.isUserInteractionEnabled = false
      view.addSubview(physicsView)

      //Create ball
      let frame = CGRect(x: 0, y: 0, width: 40, height: 40)

      let rect = UIView(frame: frame)
      rect.backgroundColor = UIColor.red
      physicsView.addSubview(rect)

      let behavior = UIDynamicItemBehavior(items: [rect])
      behavior.elasticity = 1.0
      behavior.resistance = 0.0
      behavior.friction = 0.0
      behavior.allowsRotation = false
      self.dynamicAnimator?.addBehavior(behavior)

      //collision behavior setup
      let collisionBehavior = UICollisionBehavior(items: [rect])
      collisionBehavior.collisionDelegate = self
      collisionBehavior.setTranslatesReferenceBoundsIntoBoundary(with: .zero)
      collisionBehavior.collisionMode = .everything
      self.dynamicAnimator?.addBehavior(collisionBehavior)

      //Push ball
      let pushBehavior = UIPushBehavior(items: [rect], mode: UIPushBehaviorMode.instantaneous)
      pushBehavior.active = true
      pushBehavior.pushDirection = CGVector(dx: 0.5, dy: 0.5)
      self.dynamicAnimator?.addBehavior(pushBehavior)
    }
  }

  extension ViewController: UICollisionBehaviorDelegate {
    // DELEGATE METHODS NOT CALLED
    func collisionBehavior(_ behavior: UICollisionBehavior,
                           beganContactFor item: UIDynamicItem,
                           withBoundaryIdentifier identifier: NSCopying?,
                           at p: CGPoint) {
      print("began contact boundary")
    }

    func collisionBehavior(_ behavior: UICollisionBehavior,
                           endedContactFor item: UIDynamicItem,
                           withBoundaryIdentifier identifier: NSCopying?) {
      print("contact boundary ended")
    }

    func collisionBehavior(_ behavior: UICollisionBehavior,
                           endedContactFor item1: UIDynamicItem,
                           with item2: UIDynamicItem) {

      print("contact item ended")
    }

    func collisionBehavior(_ behavior: UICollisionBehavior,
                           beganContactFor item1: UIDynamicItem,
                           with item2: UIDynamicItem,
                           at p: CGPoint) {
      print("began contact item")
    }
  }

Base SDK: iOS 11.2, Xcode Version 9.2 (9C40b) 基础SDK:iOS 11.2,Xcode版本9.2(9C40b)

Thank you for your help! 谢谢您的帮助!

That's not how it works (sadly).. You have only ONE item in your collision behaviour and you are asking it to detect collision with what??? 这不是它的工作原理(可悲的是)。你的碰撞行为中只有一个项目你要求它检测碰撞与什么??? If you added a second item, you'll see the delegate get called.. 如果您添加了第二个项目,您将看到委托被调用..

The real question is why? 真正的问题是为什么? Well, collision detects if the frame of one item intersects with the frame of another.. If it did what you are asking ( rect is a child of physicsView ), then it will ALWAYS be colliding (which is not what you want).. 好吧,碰撞检测一个项目的框架是否与另一个框架的框架相交。如果它做了你要求的( rectphysicsView一个孩子),那么它总是会碰撞(这不是你想要的)。

Since your physicsView isn't part of the collision behaviour, you get nothing.. You told it to limit the item within its bounds ( setTranslatesReferenceBoundsIntoBoundary works on the items added to the behaviour itself), but not to detect collision with the bounds. 由于你的physicsView不是碰撞行为的一部分,你什么也得不到。你告诉它限制项目在其范围内( setTranslatesReferenceBoundsIntoBoundary对添加到行为本身的项目起作用),但不检测与边界的碰撞。 For example, if the item was outside the physicsView , it wouldn't be able to get in. If it's inside, it can't get out. 例如,如果项目在physicsView之外,它将无法进入。如果它在里面,它就无法离开。 But it won't be counted as a collision per say (otherwise it is always colliding). 但它不会被视为每次碰撞(否则它总是碰撞)。

In order to detect collision between your rect and your physicsView , you need to give physicsView some physical properties.. Right now it's just a regular UIView (reference view).. 为了检测rectphysicsView之间的冲突,你需要给physicsView一些物理属性..现在它只是一个普通的UIView (参考视图)..

One other way to work around having to give it physical properties is to add a boundary for it: 另一种必须为其提供物理属性的方法是为它添加边界:

collisionBehavior.addBoundary(withIdentifier: "PhysicsViewBoundary" as NSString, for: UIBezierPath(rect: physicsView.bounds))

Now it will call: 现在它将调用:

func collisionBehavior(_ behavior: UICollisionBehavior,
                       beganContactFor item: UIDynamicItem,
                       withBoundaryIdentifier identifier: NSCopying?,
                       at p: CGPoint) {
    print("began contact boundary")
}

func collisionBehavior(_ behavior: UICollisionBehavior,
                       endedContactFor item: UIDynamicItem,
                       withBoundaryIdentifier identifier: NSCopying?) {
    print("contact boundary ended")
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM