Iphone 我如何检测到在UIBezierPath上的触摸并沿着该路径移动球?

Iphone 我如何检测到在UIBezierPath上的触摸并沿着该路径移动球?,iphone,objective-c,cocoa-touch,Iphone,Objective C,Cocoa Touch,如何沿特定路径移动球?可能吗 我尝试了所有的方法,包括使用 -(BOOL)containsPoint:(CGPoint)point onPath:(UIBezierPath*)path inFillArea:(BOOL)inFill 如何检测路径上的触摸 这真是个难题。您需要确定路径上最靠近接触点的点,这是一个复杂的数学问题。这是我能用谷歌快速搜索找到的最好的东西。(注意:代码是用BASIC编写的。) 我承认,我很想自己写这篇文章。这将非常有用,我喜欢挑战。首先。。。绝对事实是: 苹果绝对没

如何沿特定路径移动球?可能吗

我尝试了所有的方法,包括使用

-(BOOL)containsPoint:(CGPoint)point onPath:(UIBezierPath*)path inFillArea:(BOOL)inFill

如何检测路径上的触摸

这真是个难题。您需要确定路径上最靠近接触点的点,这是一个复杂的数学问题。这是我能用谷歌快速搜索找到的最好的东西。(注意:代码是用BASIC编写的。)


我承认,我很想自己写这篇文章。这将非常有用,我喜欢挑战。

首先。。。绝对事实是:

苹果绝对没有提供任何方法,
从UIBezierPath提取点的步骤

截至2011年2月,在最新的操作系统中,这是一个绝对的事实,一切都在地平线上。我已经和苹果的相关工程师谈过这个问题。在许多游戏编程环境中,这很烦人,但这是事实。那么,这可能是你的问题的答案

第二:别忘了沿着UIBezier路径为某个对象设置动画非常简单。例如,在这方面有很多答案

第三:关于找出触碰发生在哪里,如果这是你要问的,正如科里所说,这是一个困难的问题!但是您可以使用CGContextPathContainsPoint来确定点(或触摸)是否位于给定厚度的路径上

然后,假设我们讨论的是立方体,你需要沿着贝塞尔曲线找到点和可能的速度(又称切线)

下面是执行此操作的完整代码:。我也把它贴在下面

根据您的情况,您必须实现自己的MCsim或迭代以找到它的作用点。这并不难

(第四,作为一个脚注,有一个新东西,你可以逐步画出一条路径,可能与你的问题无关,只是一个注释。)


为了方便将来的读者阅读,这里是两个“方便”程序的链接问题的摘要

最后,这里以最简单的方式提供了两个例程,用于计算等距点(事实上,近似等距点)及其沿贝塞尔立方的切线:

四个预先计算的值C1 C2 C3 C4有时称为贝塞尔系数。(回想一下,bcd通常被称为四个控制点。)当然,t从0到1运行,例如每0.05运行一次只需为X调用这些例程一次,为Y单独调用一次
希望它能帮助别人

从数学上讲,您无法确定曲线内的点是否为纯数学点,因为曲线没有曲面。您可以做的是,测试该点是否位于由
CGPathCreateCopyByStrokingPath
使用
CGPathContainsPoint
创建的闭合曲线边界定义的曲面内。它将创建填充的曲线,以便在屏幕上渲染曲线

如果使用参数调用
CGPathCreateCopyByStrokingPath
:CGFloat lineWidth小于或等于原始曲线的最小曲率半径,则它将不会自相交。此外,原始曲线不应自交


如果
CGPathContainsPoint
返回true,并且我提到的两个条件都满足,则可以保证在曲线上找到距离
lineWidth
的唯一点。这个问题没有代数解,因此您必须使用此处描述的方法在曲线上找到接近接触点的近似点:

bezierpath类中有一个名为containsPoint的方法:。。参考:

您可以检测触摸点是否位于bezier路径对象中。我将其与我自己的方法结合使用,通过这种方法,用户可以很容易地检测到贝塞尔路径上的触摸(如果存在圆形或闭合路径,则不在内侧或外侧)

此代码允许用户在触摸贝塞尔路径图形对象时选择它,并在其上显示带动画的虚线。希望它能帮助别人。 以下是我自己项目的代码:

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{

    if([[self tapTargetForPath:path] containsPoint:startPoint])  // 'path' is bezier path object
          {

                [self selectShape:currentSelectedPath];// now select a new/same shape

                NSLog(@"selectedShapeIndex: %d", selectedShapeIndex);

                break;
            }
}

// this method will let you easily select a bezier path ( 15 px up and down of a path drawing)
- (UIBezierPath *)tapTargetForPath:(UIBezierPath *)path
{
    if (path == nil) {
        return nil;
    }

    CGPathRef tapTargetPath = CGPathCreateCopyByStrokingPath(path.CGPath, NULL, fmaxf(35.0f, path.lineWidth), path.lineCapStyle, path.lineJoinStyle, path.miterLimit);
    if (tapTargetPath == NULL) {
        return nil;
    }

    UIBezierPath *tapTarget = [UIBezierPath bezierPathWithCGPath:tapTargetPath];
    CGPathRelease(tapTargetPath);
    return tapTarget;
}

-(void)selectShape:(UIBezierPath *)pathToSelect
{
    centerline = [CAShapeLayer layer];
    centerline.path = pathToSelect.CGPath;
    centerline.strokeColor = [UIColor whiteColor].CGColor;
    centerline.fillColor = [UIColor clearColor].CGColor;
    centerline.lineWidth = 1.0;
    centerline.lineDashPattern = [NSArray arrayWithObjects:[NSNumber numberWithInt:10], [NSNumber numberWithInt:5], nil];
    [self.layer addSublayer:centerline];

    // showing animation on line
    CABasicAnimation *dashAnimation;
    dashAnimation = [CABasicAnimation animationWithKeyPath:@"lineDashPhase"];

    [dashAnimation setFromValue:[NSNumber numberWithFloat:0.0f]];
    [dashAnimation setToValue:[NSNumber numberWithFloat:30.0f]];
    [dashAnimation setDuration:1.0f];
    [dashAnimation setRepeatCount:10000];

    [centerline addAnimation:dashAnimation forKey:@"linePhase"];
}

Swit:关于@rakesh的答案

 func tapTargetForPath(_ path: CGPath) -> UIBezierPath? {
    let path = UIBezierPath(cgPath: path)
   guard let tapTargetPath = CGPath(__byStroking: path.cgPath,
           transform: nil,
           lineWidth: CGFloat(fmaxf(35.0, Float(path.lineWidth))),
           lineCap: path.lineCapStyle,
           lineJoin: path.lineJoinStyle,
           miterLimit: path.miterLimit) else {
            return nil
    }

    return UIBezierPath(cgPath: tapTargetPath)
}

bezierpath是一个只绘制对象的类。它将无法响应任何事件。没错,但CGContextPathContainsPoint是一个令人惊叹的工程,Antwan。它在任何一条bez路径上都会为你而存在!运气好吗?你们有解决方案吗?(1)这是一个绝对的事实:不幸的是,绝对没有方法(由苹果提供)从UIBezierPath提取点。要进行估算,请使用:Cory的可能副本!这比在Mac电脑上容易得多。您只需使用CGContextPathContainsPoint。在那之后,需要三行代码来迭代并找到它接触的地方。我假设他想把球放在离手指最近的路径上。也许我弄错了。路径上的触碰发生在哪里是个问题。但如果我们知道路径上的每个点,就可以在路径上的点上预定位,并在“隐藏”动画中开始逐点移动。回答不错。你的数学看起来比我发现的要简单得多。难道不能用
CGPathApply
从UIBezierPath提取点吗?例如:
CGPath应用([myBezierPath CGPath]、myPointArray、myElementProcessorFunction)
@EFC Hi-EFC。不,CGPathApply完全不相关。CGPathApply为您提供了构成路径概念的各种“元素”(换句话说,您的“说明”如:从这里开始,画一条到这里的直线,画一个到某某的二次曲线,在这里画一个圆)。它与沿着数学创建的结果提取点毫无关系。悲哀地在bezier路径中,并不意味着在bezier路径上,当您触摸远离圆周线的bezier曲线内侧时,它会检测到误报。从上面的代码中,它会检测到圆周线上的正确触摸
 func tapTargetForPath(_ path: CGPath) -> UIBezierPath? {
    let path = UIBezierPath(cgPath: path)
   guard let tapTargetPath = CGPath(__byStroking: path.cgPath,
           transform: nil,
           lineWidth: CGFloat(fmaxf(35.0, Float(path.lineWidth))),
           lineCap: path.lineCapStyle,
           lineJoin: path.lineJoinStyle,
           miterLimit: path.miterLimit) else {
            return nil
    }

    return UIBezierPath(cgPath: tapTargetPath)
}