2

将 SpriteKit 用于 iOS 9.0 应用程序/游戏(并且没有物理主体)。

我在一个场景中有几个 SpriteNode。SpriteNodes 带有奇怪形状的图像,并通过多个帧运行动画。

检测 SpriteNode 图像内容上的触摸而不是整个图像矩形的透明区域的最佳方法是什么。

我看到很多关于使用 SKCropNode / MaskImage 的帖子。在我的场景中,我为动画的每个 SpriteNode 有多个图像/帧。

请就方法提出建议或指出正确的方向。谢谢。

4

2 回答 2

2

根据上述评论的附加信息:

从 16 帧中只有 16 种形状,更有效的方法之一是在每一帧绘制大致接近角色轮廓的原始形状,然后将它们转换为CGPaths. 然后,可以根据触摸时当前显示的帧,在有触摸进行测试时适当地将它们换入和换出每个帧,或者(更好地)适当地取出。

CGPaths是非常轻量级的结构,因此这两种方法都不应该有任何性能问题。

CGPathContainsPoint是这个测试的旧名称,现在是 Swift 3 及更高版本的现代化 API:

使用 CGPathContainsPoint SWIFT 的问题

有一个名为PaintCode的应用程序,价格约为 100 美元,它可以将矢量转换为 CGPath 等,因此您可以使用它来导入您的形状。我建议您可以将矢量复制/粘贴到其中,因为您可能想在友好的绘图程序中绘图。PaintCode 没有世界上最好的绘图体验。


此外,这是一个免费的在线工具,用于从纹理创建多边形路径。可能比使用绘图应用程序和 PaintCode 更痛苦,但它是免费的!

替代方案:来自纹理的物理实体,以及与触摸的接触

您可以从此页面上的文档中自动从纹理创建物理身体形状,如下所示:

let texturedSpaceShip = SKSpriteNode(texture: spaceShipTexture)
texturedSpaceShip.physicsBody = SKPhysicsBody(texture: spaceShipTexture,
                                              size: CGSize(width: circularSpaceShip.size.width,
                                                           height: circularSpaceShip.size.height))

有报告称确定一个点是否在给定的物理体中存在问题,因此最好创建一个小型物理对象,将其放置在触摸所在的位置,然后确定它与物理体形状的接触是否合适对于当前游戏实体的当前帧。

警告:对于这些自动创建的物理形状,生成的 CGPath 有多复杂,我不知道(也没有办法控制)。

于 2016-10-21T01:52:02.713 回答
0

我个人只会检查当前纹理的像素,看看是否透明。您可以这样做来获取像素数据:

(请注意,此代码是假设您开始使用的代码,如果您无法弄清楚,我稍后会尝试为您制定一个真实的示例。)

(另请注意,如果您缩放精灵,您需要通过将触摸位置转换为纹理来处理它)

let image = sprite.texture.cgImage()
if let dataProvider = image.dataProvider, let data = dataProvider.data
{

  let screenScale = UIScreen.main.scale //let's handle retina graphics (may need work)
  //touchedLocation is the location on the sprite, if the anchor was bottom left (it may be top left, will have to verify) 
  //So if I touch the bottom left corner of the sprite, I should get (0,0)
  let x = touchedLocation.x * screenScale
  let y = touchedLocation.y * screenScale
  let width = sprite.texture.size().width * screenScale
  let bpp = 4 // 4 bytes per pixel
  let alphaChannel = 3 //Alpha channel is usually the highest byte
  let index = bpp * (y * width + x) + alphaChannel
  let byte = data.withUnsafeBytes({[UInt8](UnsafeBufferPointer(start:$0 + index,count:1))})
  print(Alpha: \(byte))
}
else
{
  //we have no data
}
于 2016-10-24T15:33:57.123 回答