【问题标题】:How do i make a circular view collide with the paddle我如何使圆形视图与桨发生碰撞
【发布时间】:2016-07-06 17:48:20
【问题描述】:

每当圆形视图与情节提要上的桨碰撞时,它实际上与视图的矩形框架发生碰撞。我该如何解决这个问题。我也试过UIBezierPathCAShapeLayer,但似乎没有用。

红色箭头是碰撞点,因为它似乎没有与球碰撞,而是与视图的框架发生碰撞。一次,框架被它反弹回来的桨触摸等等。

【问题讨论】:

  • 如何检测碰撞?编辑您的问题以包含代码。
  • 我没用过 Collision,写了一个函数,它检查桨的 y 轴和视图的 y 轴,一旦它们相等,球反弹回来我已经使用 NS Timer 来更新像 0 - 20- 40- 60 等一样以 20px 的 View 帧
  • 你应该看看 UI Dynamics 和/或 SpriteKit。
  • @dasdom - 我已经尝试过 UI Dynamics,同样情况下,桨和球之间的间隙仍然可见。我只能在故事板本身上创建这个应用程序,不允许使用游戏场景或 SpriteKit。
  • 但在 iOS 9 中,您可以为动态元素定义任意形状。设置圆角半径只会改变外观。

标签: ios swift uiview storyboard uikit-dynamics


【解决方案1】:

如果您使用UIDynamicAnimator,您可以为将发生碰撞的项目定义collisionBoundsTypecollisionBoundingPath,例如:

@IBDesignable public class BallView : UIView {

    @IBInspectable public var fillColor: UIColor = UIColor.blackColor() {
        didSet { setNeedsLayout() }
    }

    override public var collisionBoundsType: UIDynamicItemCollisionBoundsType {
        return .Path
    }

    override public var collisionBoundingPath: UIBezierPath {
        let radius = min(bounds.size.width, bounds.size.height) / 2.0

        return UIBezierPath(arcCenter: CGPointZero, radius: radius, startAngle: 0, endAngle: CGFloat(M_PI * 2.0), clockwise: true)
    }

    private var shapeLayer: CAShapeLayer!

    public override func layoutSubviews() {
        if shapeLayer == nil {
            shapeLayer = CAShapeLayer()
            shapeLayer.strokeColor = UIColor.clearColor().CGColor
            layer.addSublayer(shapeLayer)
        }

        let radius = min(bounds.size.width, bounds.size.height) / 2.0

        shapeLayer.fillColor = fillColor.CGColor
        shapeLayer.path = UIBezierPath(arcCenter: CGPoint(x: bounds.size.width / 2.0, y: bounds.size.height / 2.0), radius: radius, startAngle: 0, endAngle: CGFloat(M_PI * 2.0), clockwise: true).CGPath
    }
}

@IBDesignable public class PaddleView : UIView {

    @IBInspectable public var cornerRadius: CGFloat = 5 {
        didSet { setNeedsLayout() }
    }

    @IBInspectable public var fillColor: UIColor = UIColor.blackColor() {
        didSet { setNeedsLayout() }
    }

    override public var collisionBoundsType: UIDynamicItemCollisionBoundsType {
        return .Path
    }

    override public var collisionBoundingPath: UIBezierPath {
        return UIBezierPath(roundedRect: CGRect(x: -bounds.size.width / 2.0, y: -bounds.size.height / 2.0, width: bounds.width, height: bounds.height), cornerRadius: cornerRadius)
    }

    private var shapeLayer: CAShapeLayer!

    public override func layoutSubviews() {
        if shapeLayer == nil {
            shapeLayer = CAShapeLayer()
            shapeLayer.strokeColor = UIColor.clearColor().CGColor
            layer.addSublayer(shapeLayer)
        }

        shapeLayer.fillColor = fillColor.CGColor
        shapeLayer.path = UIBezierPath(roundedRect: CGRect(x: 0, y: 0, width: bounds.width, height: bounds.height), cornerRadius: cornerRadius).CGPath
    }
}

如果您这样做,然后将这些项目添加到您的UICollisionBehavior,它将尊重您为项目定义的冲突边界。例如:


上图说明了一个扫视,就像您的原始图像一样。如果你想让它即使碰到桨的边缘也能弹起来,你可以为UICollisionBehavior指定collisionDelegate并给它一个新的方向:

let collision = UICollisionBehavior(items: [paddleView, ballView])
collision.translatesReferenceBoundsIntoBoundary = true
collision.collisionDelegate = self
self.animator.addBehavior(collision)

并符合UICollisionBehaviorDelegate再执行collisionBehavior(beganContactForItem:withItem:atPoint:)

func collisionBehavior(behavior: UICollisionBehavior, beganContactForItem item1: UIDynamicItem, withItem item2: UIDynamicItem, atPoint p: CGPoint) {
    let postCollisionDirection = UIDynamicItemBehavior(items: [ballView])
    postCollisionDirection.addLinearVelocity(CGPoint(x: ballView.center.x - paddleView.center.x, y: -200), forItem: ballView)
    animator.addBehavior(postCollisionDirection)
}

这会产生如下内容:

显然,您必须花很多时间才能获得所需的效果,但它说明了检测碰撞并相应地为球添加线速度的基本思想。

【讨论】:

  • 感谢 Rob,对于我已经应用 UIPanGesture 水平移动一次的 Paddle,它碰到了它反弹回来的球,Paddle 根本不动,似乎没有碰撞。这是为什么呢?
  • 看看你的原始图像:如果一个真正的球碰到像你这样的球拍,它会从侧面向下扫视,而不是反弹回来。
  • 太完美了,因为您已经展示了球与 Paddle 的边缘发生碰撞,但它必须再次弹回顶部并击中屏幕。 Collisions & Gravity 有可能吗?
  • 如何水平移动 Paddle,我已将 Pan Gesture 应用到 PaddleView 并给出 x 坐标,它仅在球在触摸屏幕后完成弹跳时移动。虽然弹跳它不会做我遵循错误的事情吗?
  • @govindkumar - 我更新了说明添加向上反弹的答案。重新手势处理程序,我可能会将UISnapBehavior 添加到桨中,然后在手势处理程序中更新snapPoint。顺便说一句,我们已经远远超出了您最初的问题,所以您应该 accept my answer 然后如果您有其他问题,请在堆栈溢出上发布新问题,而不是在这里用与原始问题无关的 cmets 淹没我。
【解决方案2】:

比公认的答案更简单的答案是将边界设置为椭圆而不是定义的路径:

 override public var collisionBoundsType: UIDynamicItemCollisionBoundsType {
        return .Elliptical
 }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-09-03
    • 2014-04-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多