0

Hi I have an app where the user can draw a bezier path with finger and it assigns this as a collision boundary for falling objects. It works!... But! It appears the Bézier curves are closing the path (hidden) and this also becomes a boundary.

So if I draw a convex curve it works perfect. But if I draw a concave curve the object will not enter the curve. Any help appreciated. I need to open the curves somehow! code below

override func draw(_ rect: CGRect) {
         super.draw(rect)
         
       guard let context = UIGraphicsGetCurrentContext() else {
             return
         }
         
         animator = UIDynamicAnimator(referenceView: self)
         gravity = UIGravityBehavior()
         animator.addBehavior(gravity)
         gravity.gravityDirection = CGVector(dx: 0, dy: 0.1)
         collision = UICollisionBehavior(items: [hamburger])
         collision.collisionDelegate = self
         collision.addBoundary(withIdentifier: "belt" as NSCopying, for: UIBezierPath(rect: belt.frame))
         
         animator.addBehavior(collision)

     
         
         collision.addItem(hamburger)
         gravity.addItem(hamburger)
         
         collision.translatesReferenceBoundsIntoBoundary = true
         
         let itemBehaviour = UIDynamicItemBehavior(items: [hamburger])
         itemBehaviour.elasticity = 0.1
         animator.addBehavior(itemBehaviour)
         
         
         lines.forEach { (line) in
             for (i, p) in (line.points?.enumerated())! {
                 if i == 0 {
                     context.move(to: p)
                 } else {
                     context.addLine(to: p)
                 }
                 context.setStrokeColor(line.color?.withAlphaComponent(line.opacity ?? 1.0).cgColor ?? UIColor.systemBlue.cgColor)
                 context.setLineWidth(line.width ?? 10.0)
                 lineboundary = UIBezierPath(cgPath: context.path!)
                 collision.addBoundary(withIdentifier: "linedrawn" as NSCopying, for: lineboundary)
             }
             context.setLineCap(.round)
             context.strokePath()
        
         }
         
         
         
     }
Guitarman4
  • 33
  • 5
  • As an aside, `draw(_:)` is the wrong place to be configuring the UIKit Dynamics. Do it where you capture the stroke, not where you render the view… – Rob Apr 14 '22 at 00:39

1 Answers1

0

UIKit Dynamics does not permit concave paths. But you can add them as separate UICollisionBehavior instances:

for index in points.indices.dropFirst() {
    let path = UIBezierPath()
    path.move(to: points[index-1])
    path.addLine(to: points[index])

    let collision = UICollisionBehavior(items: [droppedView])
    collision.addBoundary(withIdentifier: "\(index)" as NSString, for: path)
    animator.addBehavior(collision)
}

That results in:

enter image description here

Rob
  • 415,655
  • 72
  • 787
  • 1,044
  • Hi Rob. Still can't get this to work as your animation shows. Can you show the code in full? As I must be missing something. Is points a [TouchPointsAndColor]() or CGPoint()? @Rob – Guitarman4 Apr 17 '22 at 19:28
  • See https://github.com/robertmryan/ConcaveCollision – Rob Apr 17 '22 at 20:06
  • Thanks for link to github. Got it working now, thank you. However i’m using images with a rectangular imageView which interact strangely with the concave collision boundary. How you you make UIimageView circular? I see you created a CircleView. How do you do this? Many thanks, @Rob – Guitarman4 Apr 18 '22 at 11:41
  • See https://stackoverflow.com/a/45019297/1271826. tl;dr: Create a `UIImageView` subclass that overrides `collisionBoundsType` and `collisionBoundingPath`. – Rob Apr 18 '22 at 15:34
  • Thanks so much for all your advice. All working great now. If you get a moment can you look at this question as not had any answers @Rob. https://stackoverflow.com/questions/71903781/swift-uikit-dynamics-add-collision-boundary-after-rotation-does-not-work-correc – Guitarman4 Apr 20 '22 at 21:11
  • Hi again Rob.For several reasons I have converted my project from UIKit Dynamics to SpriteKit. With the path boundary advice you kindly gave above which worked great. How would you implement this in SpriteKit? especially the line .addBoundary(withIdentifier: "\(index)" as NSString, for: path). Would you add multiple nodes? what's the simplest way to do this? Regards, Colin @Rob – Guitarman4 Jun 03 '22 at 18:51