【问题标题】:SKSpriteNode - create a round corner node?SKSpriteNode - 创建一个圆角节点?
【发布时间】:2014-03-08 20:27:43
【问题描述】:

有没有办法让 SKSpriteNode 圆角?我正在尝试使用填充颜色的 SKSpriteNode 创建一个 Tile likesqaure 块:

SKSpriteNode *tile = [SKSpriteNode spriteNodeWithColor:[UIColor colorWithRed:0.0/255.0
                                                                           green:128.0/255.0
                                                                            blue:255.0/255.0
                                                                           alpha:1.0] size:CGSizeMake(30, 30)];

我怎样才能让它变成圆角?

谢谢!

【问题讨论】:

标签: ios iphone objective-c sprite-kit


【解决方案1】:

来自类参考:

“SKSpriteNode 是绘制纹理图像、彩色方块或混合了颜色的纹理图像的节点。”

似乎最简单的方法是绘制一个圆角块,然后使用以下类方法之一:

  • spriteNodeWithImageNamed:
  • spriteNodeWithTexture:
  • spriteNodeWithTexture:size:

【讨论】:

  • +1:Sprite Kit 不是绘图 API。它是一个用于管理预定义像素块(又名精灵)移动的引擎。
【解决方案2】:

要获得圆角节点,您可以使用 2 种方法,每种方法都需要使用 SKShapeNode。

第一种方法是使用 SKShapeNode 并将其路径设置为圆角矩形,如下所示:

SKShapeNode* tile = [SKShapeNode node];
[tile setPath:CGPathCreateWithRoundedRect(CGRectMake(-15, -15, 30, 30), 4, 4, nil)];
tile.strokeColor = tile.fillColor = [UIColor colorWithRed:0.0/255.0
                                                    green:128.0/255.0
                                                     blue:255.0/255.0
                                                    alpha:1.0];

另一种使用精灵节点,裁剪节点和带有圆角矩形的SKShapeNode作为裁剪节点掩码:

SKSpriteNode *tile = [SKSpriteNode spriteNodeWithColor:[UIColor   colorWithRed:0.0/255.0
                                                                           green:128.0/255.0
                                                                            blue:255.0/255.0
                                                                           alpha:1.0] size:CGSizeMake(30, 30)];
SKCropNode* cropNode = [SKCropNode node];
SKShapeNode* mask = [SKShapeNode node];
[mask setPath:CGPathCreateWithRoundedRect(CGRectMake(-15, -15, 30, 30), 4, 4, nil)];
[mask setFillColor:[SKColor whiteColor]];
[cropNode setMaskNode:mask];
[cropNode addChild:tile];

如果您的瓷砖是纯色的,我建议您使用第一种方法。

【讨论】:

  • 即使 SKShapeNode 当前存在不一致的情况,第一种方法似乎可靠并且实施起来非常简单。
  • SKShapeNode 现在有一个 'rectOfSize:,cornerRadius:' 初始化器
  • 如果您的图块使用纹理,您仍然可以使用第一种方法,通过设置 SKShapeNode 的 fillTexture。
  • 如果您想让圆角矩形变成纯色,请致电setSetStrokeColor:
  • 请注意,新的cornerRadius初始化程序会使运行低于iOS 8的设备崩溃。Xcode不应该警告您这些问题吗?
【解决方案3】:

希望这会有所帮助:

SKSpriteNode *make_rounded_rectangle(UIColor *color, CGSize size, float radius)
{
    UIGraphicsBeginImageContext(size);
    [color setFill];
    CGRect rect = CGRectMake(0, 0, size.width, size.height);
    UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:rect cornerRadius:radius];
    [path fill];
    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    SKTexture *texture = [SKTexture textureWithImage:image];
    return [SKSpriteNode spriteNodeWithTexture:texture];
}

【讨论】:

    【解决方案4】:

    这在很大程度上受到了公认答案的启发,但它使用更易读的方式来创建 SKShapeNode 并修复了作物周围烦人的像素线。看起来像是一个小细节,但可能会花费一些人的时间。

    CGFloat cornerRadius = 15;
    SKCropNode *cropNode = [SKCropNode node];
    SKShapeNode *maskNode = [SKShapeNode shapeNodeWithRectOfSize:scoreNode.size cornerRadius:cornerRadius];
    [maskNode setLineWidth:0.0];
    [maskNode setFillColor:[UIColor whiteColor]];
    [cropNode setMaskNode:maskNode];
    [cropNode addChild:scoreNode];
    

    【讨论】:

    • 抱歉重复一遍,但老实说,为了任何人在这里谷歌搜索,你就是不要这样做!您只需裁剪 PNG,就这么简单
    • @Fattie 我的回答很笼统,可以裁剪任何节点。我没有使用 PNG,如果我使用了,我肯定不想碰它们中的每一个。所以还是有它的价值的。
    【解决方案5】:

    在 Swift 3 中,您可以使用以下方式创建:

    let tile = SKShapeNode(rect: CGRect(x: 0, y: 0, width: 30, height: 30), cornerRadius: 10)
    

    【讨论】:

    • 我应该如何设置这个 SKShapeNode 的物理体?
    【解决方案6】:

    这是基于已接受答案的第二个解决方案的 Swift 3 sn-p。

    func createPlayerRoundedNode(){
        let tile = SKSpriteNode(color: .white, size: CGSize(width: 30, height: 30))
        tile.zPosition = 3
        tile.name = "tile node"
        let cropNode = SKCropNode()
        cropNode.zPosition = 2
        cropNode.name = "crop node"
        let mask = SKShapeNode(rect: CGRect(x: 0, y: 0, width: 30, height: 30), cornerRadius: 10)
        mask.fillColor = SKColor.darkGray
        mask.zPosition = 2
        mask.name = "mask node"
        cropNode.maskNode = mask
        self.addChild(cropNode)
        cropNode.addChild(tile)
    }
    

    【讨论】:

      【解决方案7】:

      真的就这么简单......

      class YourSprite: SKSpriteNode {
      
          func yourSetupFunction() {
      
                texture = SKTexture( image: UIImage(named: "cat")!.circleMasked! )
      

      没有别的了。

      你真的不能用 SKShapeNode。

      就是这么简单。使用 SKShapeNode 会严重影响性能,这不是正确的解决方案,毫无意义的困难,而且 SKShapeNode 的目的与此问题无关。

      看看他们所有的小猫!

      circleMasked 的代码就是这么简单:

      (无论如何,所有处理图像的项目都需要这个。)

      extension UIImage {
          
          var isPortrait:  Bool    { return size.height > size.width }
          var isLandscape: Bool    { return size.width > size.height }
          var breadth:     CGFloat { return min(size.width, size.height) }
          var breadthSize: CGSize  { return CGSize(width: breadth, height: breadth) }
          var breadthRect: CGRect  { return CGRect(origin: .zero, size: breadthSize) }
          
          var circleMasked: UIImage? {
              
              UIGraphicsBeginImageContextWithOptions(breadthSize, false, scale)
              defer { UIGraphicsEndImageContext() }
              
              guard let cgImage = cgImage?.cropping(to: CGRect(origin:
                  CGPoint(
                      x: isLandscape ? floor((size.width - size.height) / 2) : 0,
                      y: isPortrait  ? floor((size.height - size.width) / 2) : 0),
                  size: breadthSize))
              else { return nil }
              
              UIBezierPath(ovalIn: breadthRect).addClip()
              UIImage(cgImage: cgImage, scale: 1, orientation: imageOrientation)
                  .draw(in: breadthRect)
              return UIGraphicsGetImageFromCurrentImageContext()
          }
      
      // classic 'circleMasked' stackoverflow fragment
      // courtesy Leo Dabius /a/29047372/294884
      }
      

      仅此而已。

      【讨论】:

      • 虽然这可以很好地循环,并且您似乎已经穿过一系列玻璃墙来找到这个解决方案,但这如何帮助将圆角矩形作为蒙版?
      • 嗨@Confused。我完全不知道,你的意思是什么?您能解释一下您的要求吗?我会尽力提供帮助的。
      • 您使用了一个圆形,我经常开玩笑地将其称为完全圆角的正方形。 OP正在询问圆角正方形/矩形。您将如何在圆角矩形/正方形上施展魔法?作为玻璃墙,我说的是你是如何在框架之外思考来解决问题的。
      • 嗨@Confused - 现在知道了。幸运的是,很容易修改UIBezierPath 以提供圆角而不是“圆形”。当我有机会时,我会尝试把它放进去,但这很容易:这是一些优秀作家的一个很好的例子:stackoverflow.com/a/41962342/294884
      【解决方案8】:

      斯威夫特 4:

      在你将你的精灵添加到他的父母之前,可以创建一个好的解决方案,我做了一个小扩展,你可以根据需要进行更正:

      extension SKSpriteNode {
          func addTo(parent:SKNode?, withRadius:CGFloat) {
              guard parent != nil else { return }
              guard  withRadius>0.0 else {
                  parent!.addChild(self)
                  return
              }
              let radiusShape = SKShapeNode.init(rect: CGRect.init(origin: CGPoint.zero, size: size), cornerRadius: withRadius)
              radiusShape.position = CGPoint.zero
              radiusShape.lineWidth = 2.0
              radiusShape.fillColor = UIColor.red
              radiusShape.strokeColor = UIColor.red
              radiusShape.zPosition = 2
              radiusShape.position = CGPoint.zero
              let cropNode = SKCropNode()
              cropNode.position = self.position
              cropNode.zPosition = 3
              cropNode.addChild(self)
              cropNode.maskNode = radiusShape
              parent!.addChild(cropNode)
          }
      }
      

      用法:

      let rootNode = SKSpriteNode(color: .white, size: self.size)
      rootNode.alpha = 1.0
      rootNode.anchorPoint = CGPoint.zero
      rootNode.position = CGPoint.zero
      rootNode.zPosition = 1
      rootNode.name = "rootNode"
      rootNode.addTo(parent: self, withRadius: 40.0)
      

      【讨论】:

      • 太棒了!但是当我向其添加 radiusShape 时,我的 SKSpriteNode 不会是 mySKSpriteNode 的中心!
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-11-22
      • 2014-06-25
      • 2011-06-08
      • 2021-11-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多