创建多个略有变化的精灵节点?
Posted
技术标签:
【中文标题】创建多个略有变化的精灵节点?【英文标题】:creating multiple sprite nodes with slight variations? 【发布时间】:2016-07-25 09:37:52 【问题描述】:我有一个显示多个成就的游戏菜单,这些成就被定义为 SKSpriteNodes,其中有 18 个,它们的位置只有轻微的变化,这里是代码的 sn-p:
Achievement1 = SKSpriteNode(color: SKColor.whiteColor(), size: CGSize(width: 100, height: 100))
Achievement1.position = CGPointMake(-120, 100)
page1ScrollView.addChild(Achievement1)
Achievement2 = SKSpriteNode(color: SKColor.whiteColor(), size: CGSize(width: 100, height: 100))
Achievement2.position = CGPointMake(0, 100)
page1ScrollView.addChild(Achievement2)
Achievement3 = SKSpriteNode(color: SKColor.whiteColor(), size: CGSize(width: 100, height: 100))
Achievement3.position = CGPointMake(120, 100)
page1ScrollView.addChild(Achievement3)
Achievement4 = SKSpriteNode(color: SKColor.whiteColor(), size: CGSize(width: 100, height: 100))
Achievement4.position = CGPointMake(-120, -25)
page1ScrollView.addChild(Achievement4)
我还竭尽全力将它们一一定义为 vars,如下所示:
var Achievement1: SKSpriteNode!
var Achievement2 = SKSpriteNode()
var Achievement3 = SKSpriteNode()
var Achievement4 = SKSpriteNode()
var Achievement5 = SKSpriteNode()
var Achievement6 = SKSpriteNode()
var Achievement7 = SKSpriteNode()
var Achievement8 = SKSpriteNode()
它看起来一团糟,只是占用了太多空间。我希望能够定义所有精灵节点,并让它们都能够被按下以显示一个框,说明成就的用途,如下所示:
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?)
let touch: UITouch = touches.first!
let location: CGPoint = touch.locationInNode(self)
let node: SKNode = self.nodeAtPoint(location)
if (node == Achievement1)
//achievement details here
我对这种 swift 语言还很陌生,我还不是很先进,但我希望能得到帮助。
【问题讨论】:
【参考方案1】:如果您认为您的代码一团糟,请尝试在您的代码中找到模式。
看到那些Achievement1
、Achievement2
、Achievement3
、Achievement4
的东西了吗?当您看到这种模式时,您可能应该创建一个数组来存储成就。
我确定你知道如何使用数组,所以我不会过多地谈论它。有关详细信息,您可以转到 Array
类的定义。
您可能注意到的另一种模式是使用相同的参数来创建精灵节点。成就之间的唯一区别是他们的位置。
解决此问题的最佳方法是创建一个方法:
func createAchievement(location: CGPoint) -> SKSpriteNode
let node = SKSpriteNode(color: SKColor.whiteColor(), size: CGSize(width: 100, height: 100))
node.position = location
return node
您只需要一行就可以将新成就添加到上述数组中:
someArray.append(createAchievement(CGPointMake(-120, 100)))
编辑:
如果你使用indexOf(_:)
(或swift 3中的index(of:)
),你可以创建一个switch语句而不是if语句:
switch someArray.indexOf(node)
case 0:
// this means that the first achievement is tapped!
case 1:
// this means that the second achievement is tapped!
case 2:
// this means that the third achievement is tapped!
【讨论】:
这是否仍然允许我使用在我的 touchesbegan 方法中生成的节点? @Astrum 当然是的!要检查node
是否是第一个成就,请使用node == someArray[0]
!要检查第二个成就,请使用node == someArray[1]
。剩下的你自己搞定!
@Astrum 您也可以使用 Grimxn 在他的回答中提到的 index(of:)
方法。但如果您使用的是 Swift 2.x,请改用 indexOf(_:)
。
为什么我必须在我的 touchesbegan 方法中使用那个 indexof(_:) ?这是否让我不必在 touches begin 方法中单独写出它们?
如果你使用indexOf
,你可以创建一个switch语句来切换被触摸节点的索引(更优雅的IMO)而不是if语句(不太优雅)@Astrum【参考方案2】:
关于布局当你有大量的项目要显示时,你可以考虑使用表格或页面控件。因为我很懒,我不喜欢只滚动表格来查看所有游戏成就,所以通常我更喜欢使用 PageControl。
您可以在UIKit
和UIPageControl
中构建并将其集成到您的游戏菜单中。
如果你不知道如何集成UIPageControl
,你可以使用这个sprite-kit项目GBPageControl
import GBPageControl
var pageControl:PageControl!
//Add the page control to the scene. Add any content that will be paged directly to the pageControl:
override func didMoveToView(view: SKView)
pageControl = PageControl(scene: self)
addContent()
pageControl.enable(4)
private func addContent()
for var i = 0; i < 4; i++
let node = SKShapeNode(circleOfRadius: 10)
node.strokeColor = UIColor.blueColor()
let x = self.size.width / 2.0 + self.size.width * CGFloat(i)
let y = self.size.height / 2.0
node.position = CGPoint(x:x, y:y)
pageControl.addChild(node)
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?)
for touch in touches
if pageControl.handleTouch(touch)
//no op
else
//handle touch
override func willMoveFromView(view: SKView)
pageControl.willMoveFromView(view)
输出:
更新:
关于你可以尝试做的成就代码:
enum MedalType: Int
case Gold = 1
case Silver = 2
case Bronze = 3
class Achievement:SKSpriteNode
init(color:SKColor,size:CGSize,name:String,medalType:MedalType)
super.init(texture: nil,color:color,size:size)
self.name = name
required init?(coder aDecoder: NSCoder)
fatalError("init(coder:) has not been implemented")
class GameScene: SKScene
var achievements:[Achievement]!
var aNames: [String]!
var totalAchievements: Int = 45
override func didMoveToView(view: SKView)
var counter : Int = 0
let deltaX:CGFloat = 120
let deltaY:CGFloat = 10
for i in 0..<totalAchievements
var aColor = SKColor.whiteColor()
var aSize = CGSizeMake(100,100)
var medal = MedalType.Bronze
switch i
case 10:
aColor = SKColor.redColor()
aSize = CGSizeMake(100,150)
medal = MedalType.Silver
case 25:
aColor = SKColor.blueColor()
aSize = CGSizeMake(100,200)
medal = MedalType.Gold
default:
break
let name = "achievement\(i)"
let a = Achievement.init(color: aColor, size: aSize, name: name, medalType: medal)
aNames.append(name)
//handle your position has you wish with counter, deltaX e deltaY
//...
a.position = CGPointMake(deltaX, deltaY)
addChild(a)
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?)
let touch: UITouch = touches.first!
let location: CGPoint = touch.locationInNode(self)
let node: SKNode = self.nodeAtPoint(location)
if (aNames.contains(node.name!))
print("You have touch achievement \(node.name)")
let currentAchievement = achievements[aNames.indexOf(node.name!)!]
// Use your currentAchievement touched
【讨论】:
【参考方案3】:你可以使用数组...
let achievements = [SKSpriteNode](repeating: SKSpriteNode(color: SKColor.white(), size: CGSize(width: 100, height: 100)), count: 8) // Swift 3 colour name
let positions = [CGPoint(x: -120, y: 100), CGPoint(x: 0, y: 100) /* ... */]
for i in 0 ..< min(achievements.count, positions.count) // For safety - obviously these should be the same
achievements[i].position = positions[i]
// Then in your touch routine...
if let index = achievements.index(of: self.nodeAtPoint(location))
// do something with achievements[index]
...并且不要大写变量 - Swift 约定是只有类型大写...
【讨论】:
以上是关于创建多个略有变化的精灵节点?的主要内容,如果未能解决你的问题,请参考以下文章