我想让SKSpriteNodes沿着字母轮廓移动。我有很多信,但这里有一个例子:
我希望精灵遵循红线。我发现这个答案主要涵盖了我的问题:Get path to trace out a character in an 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])")
}
但是我仍遇到问题,因为我的精灵没有完成所有字母的字母周围的完整路径,而是例如“P”停在这里(并从底部开始):
我尝试向path
添加一些点,如下所示:
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}>
答案 0 :(得分:2)
首先,您需要一种方法来检索CGPath
中的所有元素。
我已经翻译成 Swift 这个method(你也找到了一个如何使用它的例子)。
正如我在您的代码中看到的那样,您还需要了解构成路径的元素类型,但CGPathElement
使用UnsafeMutablePointer<CGPoint>
(它可能不舒适),因此您可以修改我的翻译是通过创建一个具有两个输出数组的函数,如下所示:
//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)
}
}
之后你有一个点数组和一个类型的镜面数组,它解释了我们列表中每个点的类型。这次删除了所有closePath
。
现在是时候为你的情况重新创建路径广告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
}
启动此方法后,您将清除所有closePath
的路径,并准备好根据需要添加新行。