Swift:如何将点添加到封闭的CGPath?

我想让SKSpriteNodes沿着字母轮廓移动。 我有很多字母,但这里有一个例子:

在这里输入图像说明

我希望这个精灵跟着红线。 我发现这个答案主要涵盖了我的问题: 获取path在iOS UIFont中追踪一个字符

答案来自这个良好的工作示例代码:

let font = UIFont(name: "HelveticaNeue", size: 64)! var unichars = [UniChar]("P".utf16) var glyphs = [CGGlyph](count: unichars.count, repeatedValue: 0) let gotGlyphs = CTFontGetGlyphsForCharacters(font, &unichars, &glyphs, unichars.count) if gotGlyphs { let cgpath = CTFontCreatePathForGlyph(font, glyphs[0], nil)! let path = UIBezierPath(CGPath: cgpath) print(path) XCPlaygroundPage.currentPage.captureValue(path, withIdentifier: "glyph \(glyphs[0])") } 

然而,我仍然遇到一个问题,因为我的精灵并没有完成所有字母的字母的完整path,而是例如在这里“P”停止(从底部开始):

在这里输入图像说明

我尝试添加一些点,如下所示:

 CGPathAddLineToPoint(path, nil, 0, 0) 

但结果不起作用可能是因为添加点在<Close>语句之后:

 <UIBezierPath: 0x7889ff70; <MoveTo {25.950001, 55.800003}>, <LineTo {25.950001, 95.100006}>, <LineTo {53.850002, 95.100006}>, <QuadCurveTo {71.625, 90.075005} - {66, 95.100006}>, <QuadCurveTo {77.25, 75.450005} - {77.25, 85.050003}>, <QuadCurveTo {71.625, 60.750004} - {77.25, 65.850006}>, <QuadCurveTo {53.850002, 55.800003} - {66, 55.650002}>, <Close>, <MoveTo {11.700001, 107.10001}>, <LineTo {11.700001, 0}>, <LineTo {25.950001, 0}>, <LineTo {25.950001, 43.800003}>, <LineTo {58.650002, 43.800003}>, <QuadCurveTo {83.175003, 52.050003} - {74.850006, 43.650002}>, <QuadCurveTo {91.5, 75.450005} - {91.5, 60.450001}>, <QuadCurveTo {83.175003, 98.775002} - {91.5, 90.450005}>, <QuadCurveTo {58.650002, 107.10001} - {74.850006, 107.10001}>, <Close>, <LineTo {0, 0}> 

首先,你需要一个方法来检索CGPath所有元素。

我已经翻译成Swift这种方法 (你也可以find一个如何使用它的例子)。

正如我在你的代码中看到的那样,你也需要知道什么types的元素组成了你的path,但是CGPathElementUnsafeMutablePointer<CGPoint> CGPathElement工作(它不能被UnsafeMutablePointer<CGPoint> ),所以你可以通过创build一个带有两个输出这样的数组:

 //MARK: - CGPath extensions extension CGPath { func getPathElementsPointsAndTypes() -> ([CGPoint],[CGPathElementType]) { var arrayPoints : [CGPoint]! = [CGPoint]() var arrayTypes : [CGPathElementType]! = [CGPathElementType]() self.forEach { element in switch (element.type) { case CGPathElementType.MoveToPoint: arrayPoints.append(element.points[0]) arrayTypes.append(element.type) case .AddLineToPoint: arrayPoints.append(element.points[0]) arrayTypes.append(element.type) case .AddQuadCurveToPoint: arrayPoints.append(element.points[0]) arrayPoints.append(element.points[1]) arrayTypes.append(element.type) arrayTypes.append(element.type) case .AddCurveToPoint: arrayPoints.append(element.points[0]) arrayPoints.append(element.points[1]) arrayPoints.append(element.points[2]) arrayTypes.append(element.type) arrayTypes.append(element.type) arrayTypes.append(element.type) default: break } } return (arrayPoints,arrayTypes) } } 

之后,你有一个点arrays和一个reflectiontypes的数组,解释我们列表中的每个点是什么types。 这一次所有closePath都被删除。

现在是时候为您重新创buildpath广告HOC了:

 func createNewPath(path:CGPath) -> UIBezierPath { let (points,types) = path.getPathElementsPointsAndTypes() if points.count <= 1 { return UIBezierPath() // exit } let pathRef = UIBezierPath() var i = 0 while i < points.count { switch (types[i]) { case CGPathElementType.MoveToPoint: pathRef.moveToPoint(CGPointMake(points[i].x,points[i].y)) case .AddLineToPoint: pathRef.addLineToPoint(CGPointMake(points[i].x,points[i].y)) case .AddQuadCurveToPoint: pathRef.addQuadCurveToPoint(CGPointMake(points[i].x,points[i].y), controlPoint: CGPointMake(points[i+1].x,points[i+1].y)) i += 1 case .AddCurveToPoint: pathRef.addCurveToPoint(CGPointMake(points[i].x,points[i].y), controlPoint1: CGPointMake(points[i+1].x,points[i+1].y), controlPoint2: CGPointMake(points[i+2].x,points[i+2].y)) i += 2 default: break } i += 1 } //pathRef.closePath() if you want to add new elements dont uncomment this return pathRef } 

启动这个方法之后,你将清除所有closePathpath,并随时添加新行。