Swift: как добавить очки к закрытому пути CGPath?
Я хотел бы сделать 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}>
1 ответ:
Прежде всего вам нужен метод для извлечения всех элементов из
CGPath
.Я перевел в Swift Этот метод (вы также найдете пример того, как его использовать).
Как я вижу здесь в вашем коде, вам также нужно знать, какие типы элементов составляют ваш путь, но
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
удалены.Теперь пришло время воссоздать путь ad 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
и готов к добавлению новых строк по вашему желанию.