如何在 SpriteKit 中使用 SKShapeNode 通过触摸特定路径来绘制路径

Posted

技术标签:

【中文标题】如何在 SpriteKit 中使用 SKShapeNode 通过触摸特定路径来绘制路径【英文标题】:How to draw a path by touches on a specific path using SKShapeNode in SpriteKit 【发布时间】:2018-11-24 04:55:19 【问题描述】:
    我使用 UIBezierPath 创建一个路径,然后从该路径创建一个 SKShapeNode。 我希望用户通过触摸屏幕来绘制相同的路径以匹配我的原始路径。

这是代码:

导入 SpriteKit 导入 GameplayKit

类 GameScene:SKScene

var orginalPath: UIBezierPath!

var orgialShape: SKShapeNode!
var userTouchs = [CGPoint]()
var drawingLine: SKShapeNode!


override func didMove(to view: SKView) 

    orginalPath = UIBezierPath()
    orginalPath.move(to: CGPoint(x: 170, y: 230))
    orginalPath.addLine(to: CGPoint(x: 370, y: 230))
    orginalPath.addQuadCurve(to: CGPoint(x: 480, y: 55), controlPoint: CGPoint(x: 525, y: 150))


    orgialShape = SKShapeNode(path: orginalPath.cgPath)
    orgialShape.strokeColor = UIColor.white
    orgialShape.lineWidth = 30
    orgialShape.lineCap = .round
    orgialShape.lineJoin = .round
    orgialShape.zPosition = 0
    orgialShape.name = "orginal"
    addChild(orgialShape)



func createLine() 
    if userTouchs.count > 2 
        let line = SKShapeNode(points: &userTouchs, count: userTouchs.count)
        line.strokeColor = UIColor.red
        line.lineWidth = 10
        line.lineCap = .round
        line.zPosition = 10
        line.isAntialiased = true
        line.name = "newLine"
        addChild(line)

    



override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) 
    if let touch = touches.first 
        let location = touch.location(in: self)
        let objects = nodes(at: location)
        for object in objects 
            if object.name == "orginal" 
                    userTouchs.append(location)
            
        
    


override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) 
    if let touch = touches.first 
        let location = touch.location(in: self)
        let objects = nodes(at: location)
        for object in objects 
            if object.name == "orginal" 
                    print(location)
                    userTouchs.append(location)
                    createLine()
            
        
    

这段代码应该让用户“只”在我的路径上绘制,就像我在图片中显示的那样:

但问题是,当我编写代码时,我发现我可以在路径外画一条线,实际上它看起来像一个正方形,而不仅仅是我在图片中显示的路径:

所以请任何人向我解释让用户只在我的路径上绘制的正确方法,如果他触摸了路径,他就无法绘制任何东西。

【问题讨论】:

【参考方案1】:

您可以定义允许用户绘制的路径,例如在此处查看绿色路径:

然后剪辑到这个路径:

self.currentBezierPath.addClip()

在我的回答中查看此方法的更多详细信息:How to draw inside the black edges in ios SDK with OpenGL ES?

确保用户沿一个方向跟随路径

您可以划分区域,例如成小矩形并将它们按顺序存储到数组中,请参见此处的草图:

然后确保用户从仅按升序触摸矩形(图中以红色显示)开始,并且用户不会离开外边界(在图中以绿色显示)。

要检查一个点是否在路径内,可以使用以下方法:

    let inside = bezierPath.contains(point)

这会解决您的用例吗?

【讨论】:

谢谢你的回答我看到你的作品,如果你有一张图片来填充颜色,它的工作很好,但在我的情况下,我的应用程序应该学习孩子们如何写两个字母,所以我需要用户跟随字母路径和你的解决方案,一些时间字母线相交,所以用户只是用颜色填充字母,而不是遵循正确的路径来学习如何正确书写,如果你有另一个答案我会很乐意告诉我. @AmmarAhmad 啊,好的,我明白了,我已经更新了答案。它现在应该确保用户沿着正确的方向跟随字母路径,并且根本不会离开整个路径。 实际上它的使用方法非常有趣,我认为它会解决我的问题,但是你能告诉我如何用简单的代码将路径分成一个矩形(比如分割一条简单的线)所以我能理解你是怎么做到的,再次感谢你的帮助。 这是一个聪明的解决方案:***.com/a/26131682/2331445。它在Objective-C中。如果您向下滚动并查看 ArrowView.m 的 drawRect,您可以看到 Rob_forEachPointAtInterval 方法的运行:对于每个间隔,它返回一个点和一个向量。例如,您可以创建一个矩形路径数组,而不是绘制箭头。

以上是关于如何在 SpriteKit 中使用 SKShapeNode 通过触摸特定路径来绘制路径的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Swift 和 SpriteKit 中使用 UISwipeGestureRecognizer 而不是 touchesMoved?

如何在 SpriteKit 场景编辑器中访问导航图的对象

如何在 SpriteKit 中使用 SKShapeNode 通过触摸特定路径来绘制路径

如何在 SpriteKit 中使用不同大小的纹理制作动画

SpriteKit:如何使用 blendMode 在图层中打孔

如何混合 UIKit 和 SpriteKit?