很遗憾,SKShapeNode 不适合你想要做的事情。不过,有一种方法可以优化它,尽管有一些注意事项。
首先,最大的问题之一是 fps 很低,因为每添加一个线段就会增加一次绘制计数。如果在 SKView
实例上设置 showsDrawCount
,你就会明白我的意思。
在这个答案中 Multiple skshapenode in one draw?,你可以了解到如何使用 SKEffectNode
的 shouldRasterize
属性来解决绘制一次的问题。如果你不这样做,处理器时间将花费在每一帧的众多绘制上。
所以可以看出,绘制是你无法获得想要性能的主要问题。但是,你似乎想要持续绘制,所以我要提出的建议可能是对你可行的解决方案。
我建议的解决方案的逻辑如下:
1-创建一个用作画布的 SKSpriteNode
。
2-创建一个仅用于绘制当前线段的 SKShapeNode
。
3-将那个 SKShapeNode
作为画布的子节点。
4-通过 SKShapeNode
绘制新的线段。
5-使用 SKView
方法 `textureFromNode 保存当前在画布上绘制的内容。
6-将画布的纹理设置为该纹理。
回到 #4 循环,为下一个线段创建新路径。
如有需要,请重复此过程。
结果应该是你的绘制计数永远不会超过 2 次,这将解决高绘制计数的问题。
基本上,你正在保留以前绘制的内容并将其保存为纹理,因此只需要一次 SKShapeNode
绘制最新的线段和一次 SKTexture
绘制即可。
再次说明,我还没有尝试过这个过程,如果有任何滞后,那就是每帧 textureFromNode
调用的原因。如果有任何瓶颈,那就是它!
更新
这不是完整的代码,但是这是实现所需的绘图性能(60fps)的重要部分:
基本节点元素为:
容器 -> 包含需要缓存的所有元素的 SKNode
画布 -> 显示所绘制段的缓存版本的 SKSpriteNode
线段池 -> 用于最初绘制线段,并根据需要重复使用
首先创建一个 SKShapeNodes 池:
pool = [[NSMutableArray alloc]init];
for (int index = 0; index < 5; index++)
{
SKShapeNode *segment = [[SKShapeNode alloc]init];
segment.strokeColor = [SKColor whiteColor];
segment.glowWidth = 1;
[pool addObject:segment];
}
接下来创建从池中获取SKShapeNode的方法:
-(SKShapeNode *)getShapeNode
{
if (pool.count == 0)
{
[self cacheSegments];
}
SKShapeNode *segment = pool[0];
[pool removeObjectAtIndex:0];
return segment;
}
接下来创建一个从池中获取线段并绘制直线的方法:
-(void)drawSegmentFromPoint:(CGPoint)fromPoint toPoint:(CGPoint)toPoint
{
SKShapeNode *curSegment = [self getShapeNode];
CGMutablePathRef path = CGPathCreateMutable();
curSegment.lineWidth = 3;
curSegment.strokeColor = [SKColor whiteColor];
curSegment.glowWidth = 1;
curSegment.name = @"segment";
CGPathMoveToPoint(path, NULL, fromPoint.x, fromPoint.y);
CGPathAddLineToPoint(path, NULL, toPoint.x, toPoint.y);
curSegment.path = path;
lastPoint = toPoint;
[canvas addChild:curSegment];
}
接下来是一种创建纹理并将现有片段返回到池中的方法:
-(void)cacheSegments
{
SKTexture *cacheTexture =[ self.view textureFromNode:container];
canvas.texture = cacheTexture;
[canvas setSize:CGSizeMake(canvas.texture.size.width, canvas.texture.size.height)];
canvas.anchorPoint = CGPointMake(0, 0);
[canvas enumerateChildNodesWithName:@"segment" usingBlock:^(SKNode *node, BOOL *stop)
{
[node removeFromParent];
[pool addObject:node];
}];
}
最后是触摸处理程序:
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
[self cacheSegments];
for (UITouch *touch in touches)
{
CGPoint location = [touch locationInNode:self];
lastPoint = location;
[self drawSegmentFromPoint:lastPoint toPoint:location];
}
}
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
for (UITouch *touch in touches)
{
CGPoint location = [touch locationInNode:self];
[self drawSegmentFromPoint:lastPoint toPoint:location];
}
}
就像我所说的,这并不是包罗万象的代码,我假设你对这个概念有足够的了解,可以将其实现到你的应用程序中。 这些只是我基本实现的示例。