gpt4 book ai didi

arrays - SpriteKit & Swift,是否可以使用数组来汇集 SKSpritenodes?

转载 作者:行者123 更新时间:2023-11-28 12:18:42 25 4
gpt4 key购买 nike

我正在开发一个带有平台、障碍物等的 2d siderunner 游戏。平台正在创建,然后从右向左移动,然后再次移除。这就是我的问题,因为每次创建和删除节点都不是很有效,我有时会看到 fps 下降 1-3 帧,尤其是当创建的节点超过 +15 个时。所以我认为池节点对于良好的性能至关重要。

这是我到目前为止的尝试:

创建全局数组变量:

var smallPlArray = [SKSpriteNode]() 
var midPlArray = [SKSpriteNode]()
var bigPlArray = [SKSpriteNode]()
var groundPlArray = [SKSpriteNode]()

// small, middle and big refers to the platforms size's not the array size

创建 SKSpritenode 并将它们添加到数组的函数:

// Gets called in didMoveToView

func fillSpriteArrays() {

var smallPlCount:Int = 0
var groundPlCount:Int = 0

for _ in 0..<10 {

let smallPlatform = SKSpriteNode(texture: platform_Small_Texture)
smallPlatform.zPosition = 4
smallPlatform.size = CGSize(width: 509.5, height: 55.8)
smallPlatform.isHidden = true

smallPlatform.physicsBody = SKPhysicsBody(rectangleOf: smallPlatform.size)
smallPlatform.physicsBody?.categoryBitMask = PhysicsCatagory.platforms
smallPlatform.physicsBody?.contactTestBitMask = 0
smallPlatform.physicsBody?.isDynamic = false
smallPlatform.physicsBody?.affectedByGravity = false
smallPlatform.physicsBody?.friction = 0.0
smallPlatform.physicsBody?.restitution = 0.0

smallPlArray.append(smallPlatform)
groundPair.addChild(smallPlArray[smallPlCount])

smallPlCount += 1
}


for _ in 0..<10 {

let groundPlatform = SKSpriteNode(texture: middle_Ground_Platform_Texture)
groundPlatform.zPosition = 4
groundPlatform.size = CGSize(width: 898.4, height: 255.5)
groundPlatform.isHidden = true

groundPlatform.physicsBody = SKPhysicsBody(rectangleOf: groundPlatform.size)
groundPlatform.physicsBody?.categoryBitMask = PhysicsCatagory.groundPlatform
groundPlatform.physicsBody?.contactTestBitMask = 0
groundPlatform.physicsBody?.isDynamic = false
groundPlatform.physicsBody?.affectedByGravity = false
groundPlatform.physicsBody?.friction = 0.0
groundPlatform.physicsBody?.restitution = 0.0

groundPlArray.append(groundPlatform)
groundPair.addChild(groundPlArray[groundPlCount])

groundPlCount += 1
}

// Same for the other array's...
}

尝试从数组中获取 SKSpritenodes 并使用它们:

func platforms1() {

let ground1 = groundPlArray[0]
ground1.position = CGPoint(x: 3800, y: 375)
ground1.isHidden = false

let ground2 = groundPlArray[1]
ground2.position = CGPoint(x: 7000, y: 375)
ground2.isHidden = false

let smallPl1 = smallPlArray[0]
smallPl1.position = CGPoint(x: 4350, y: 720)
smallPl1.isHidden = false

let smallPl2 = smallPlArray[1]
smallPl1.position = CGPoint(x: 5600, y: 720)
smallPl2.isHidden = false

// Other nodes not in connection with the array's

createSpring(position: CGPoint(x: 2500, y: 337))
createCrate(position: CGPoint(x: 5000, y: 350))
createCrate(position: CGPoint(x: 5600, y: 350))
createJelly(position: CGPoint(x: 7000, y: 330))
createRoundWoodSpike(position: CGPoint(x: 7300, y: 550))
createPlatformEndNode(position: CGPoint(x: 8500, y: 788))
createDiamond(position: CGPoint(x: 2800, y: 800))
createDiamond(position: CGPoint(x: 2880, y: 800))
createDiamond(position: CGPoint(x: 4070, y: 575))
}

所以,这就是我失败的地方。不知何故只有来自 smallPlArray 的一个节点被显示,但在 groundPlArray 上所有两个节点都被显示。这些节点的父节点 (groundPair) 被移动,当某个点通过时(屏幕上没有节点),父节点位置被重置并且 platforms1() 被再次调用并且节点再次出现。这适用于所有其他节点,如 Spring 、 crate 等,但阵列中的节点不会再次返回。仅当第一次调用 platforms1() 时,数组中 4 个节点中的 3 个才会出现。显然我在这方面失败了。我究竟做错了什么?是否有另一种或更好的汇集方式?不幸的是,我对阵列的经验不多,但如果有必要,我可以学习。

编辑

调用代码的方式如下:

    func diceRollPlatforms() {

platformSpawnCount = 0

let shuffled = GKRandomDistribution(lowestValue: 1, highestValue: 15)
var number = shuffled.nextInt()

// Repeat one platform sequence over and over instead of a random int
if number != 1 || number == 1 {
platforms1()
}

然后:

func platforms_1() {

shouldMovePlatforms = true // Just triggers the moving of groundPair in update

createSpring(position: CGPoint(x: 2500, y: 337))
createCrate(position: CGPoint(x: 5000, y: 350))
createCrate(position: CGPoint(x: 5600, y: 350))
createJelly(position: CGPoint(x: 7000, y: 330))
createRoundWoodSpike(position: CGPoint(x: 7300, y: 550))
createPlatformEndNode(position: CGPoint(x: 8500, y: 788)) // On contact with the player,groundPair(parent) gets reseted and diceRollPlatforms() is called again.
//BUT the children are not removed. Children like spring etc are removed with the physics engine when they contact a node
//on the near outside left of the screen which does not affect the platforms, only obstacles like said before spring, crate...


let ground1 = groundPlArray[0]
ground1.position = CGPoint(x: 3800, y: 375)
ground1.isHidden = false


let ground2 = groundPlArray[1]
ground2.position = CGPoint(x: 7000, y: 375)
ground2.isHidden = false

let smallPl1 = smallPlArray[0]
smallPl1.position = CGPoint(x: 4350, y: 720)
smallPl1.isHidden = false

let smallPl2 = smallPlArray[1]
smallPl2.position = CGPoint(x: 5600, y: 720)
smallPl2.isHidden = false

// How the array is being filled is already explained above
}

createSpring等函数内部,基本都是一样的:

func createSpring(position: CGPoint) {
let spring = SKSpriteNode(texture: spring_Texture3)
spring.size = CGSize(width: 230.9, height: 151.0)
spring.zPosition = 4
spring.position = position

spring.physicsBody = SKPhysicsBody(rectangleOf: spring.size)
spring.physicsBody?.categoryBitMask = PhysicsCatagory.spring
spring.physicsBody?.contactTestBitMask = 0
spring.physicsBody?.isDynamic = false
spring.physicsBody?.affectedByGravity = false
spring.physicsBody?.friction = 0.0
spring.physicsBody?.restitution = 0.0

groundPair.addChild(spring)
}

@Knight0fDragon 如果有什么不清楚的地方请告诉我。

第二次编辑

    func createPlatformEndNode(position: CGPoint) {
let platformEndNode = SKSpriteNode()
platformEndNode.position = position
platformEndNode.zPosition = 4
platformEndNode.size = CGSize(width: 30, height: 1536)

platformEndNode.physicsBody = SKPhysicsBody(rectangleOf: platformEndNode.size)
platformEndNode.physicsBody?.categoryBitMask = PhysicsCatagory.platformEndNode
platformEndNode.physicsBody?.contactTestBitMask = PhysicsCatagory.platforms | PhysicsCatagory.obstacle | PhysicsCatagory.obstacleDeathObject | PhysicsCatagory.enemy | PhysicsCatagory.collidablePlatforms | PhysicsCatagory.spring | PhysicsCatagory.breakAbleObstacle | PhysicsCatagory.triggerEnemyNode | PhysicsCatagory.platformEndNode | PhysicsCatagory.groundPlatform | PhysicsCatagory.collidableGroundPlatform | PhysicsCatagory.breakAblePlatformsNotcollidable | PhysicsCatagory.breakAblePlatforms | PhysicsCatagory.cherry
platformEndNode.physicsBody?.isDynamic = false
platformEndNode.physicsBody?.affectedByGravity = false

groundPair.addChild(platformEndNode)
}

func didEnd(_ contact: SKPhysicsContact) {
// Check if contact ended with platformEndNode
if firstBody.categoryBitMask == PhysicsCatagory.platformEndNode && secondBody.categoryBitMask == PhysicsCatagory.dragon || firstBody.categoryBitMask == PhysicsCatagory.dragon && secondBody.categoryBitMask == PhysicsCatagory.platformEndNode {
spawnPlatformsAgain()

if firstBody.categoryBitMask == PhysicsCatagory.platformEndNode {
firstBody.node!.removeFromParent()
} else {
secondBody.node!.removeFromParent()
}
}
// Check if contact ended with platformStartNode
if firstBody.categoryBitMask == PhysicsCatagory.triggerPlatformStartNode && secondBody.categoryBitMask == PhysicsCatagory.dragon || firstBody.categoryBitMask == PhysicsCatagory.dragon && secondBody.categoryBitMask == PhysicsCatagory.triggerPlatformStartNode {
if firstBody.categoryBitMask == PhysicsCatagory.triggerPlatformStartNode {
firstBody.node!.removeFromParent()
} else {
secondBody.node!.removeFromParent()
}
if platformSpawnCount == 0 { platformSpawnCount = 1; prepareGroundPair(); diceRollPlatforms() }
}
}
func spawnPlatformsAgain() {

if !wasWaterHere {

timeToIncreaseGameSpeed = true; platformSpawnCount = 0
prepareForNextPlatforms(); increaseGameSpeed()
if addRollingWoodEnemy == true { spawnRollingWoodEnemyAfterPlatforms() }
isCollidingWithBreakAblePlatforms = false

createPlatformStartNode(position: CGPoint(x: 1024, y: 768))

} else {

timeToIncreaseGameSpeed = true; platformSpawnCount = 0
prepareForNextPlatforms(); increaseGameSpeed()
if addRollingWoodEnemy == true { spawnRollingWoodEnemyAfterPlatforms() }
isCollidingWithBreakAblePlatforms = false

wasWaterHere = false
bigGroundAndWaterTileNode.removeAllChildren()
bigGroundAndWaterTileNode.removeAllActions()
bigGroundAndWaterTileNode.position = CGPoint(x: 0, y: 0)
bigGroundAndWaterTileNode.isHidden = true

createPlatformStartNode(position: CGPoint(x: 1536, y: 768))
}
}
func prepareGroundPair() {

shouldMovePlatforms = false
groundPair.position.x = 0
}

func prepareForNextPlatforms() {

groundPair.position.x = 0

enemyParent.removeAllChildren(); enemyParent.removeAllActions()
enemyParent.position.x = 0

}

第三次编辑

groundPair 的移动:

    // Runs in Update
func moveWorldObjects() {
if shouldMovePlatforms == true {
groundPair.position = CGPoint(x: groundPair.position.x - CGFloat(xPosition), y: groundPair.position.y)
}

最佳答案

是的,有可能,您的问题是复制和粘贴失败。你从来没有设置 smallPl2 的位置,而是你不小心设置了两次 smallPl1。

不过,我会完全避免这种方法。只有当你受到严重的性能限制时,我才会建议做这样的池(你不是,你的代码效率不高)。创建一个新对象每次都会让您重新开始,因此您无需担心重置节点的属性。

相反,回到您正在做的事情,每次都创建一个新平台。

不过这一次,创建一系列在后台线程中排队的保留节点以实现您的目标。然后,您可以在更新或更新阶段的 didFinish 部分将它们添加到您的场景中,以避免任何冲突。

这里是一个如何创建一些保留节点的例子

var reservedNodes = SKNode()  //This SKNode is going to house all of our reserves,  I prefer it over [SKNode]().

func spawnReserves()
{
if reservedNodes.children.count < 5
{
DispatchQueue.global(qos: .background).async
{
[weak self] in
//before this point if self does not exist then safely exit
guard let strongSelf = self else {return}
//beyond this point we do not want self to die
let node = strongSelf.createNode()
DispatchQueue.main.async
{
[weak self] in
//before this point if self does not exist then safely exit
//now because we use `node`, strongSelf should not even be needed, since the background thread should be retained, but I threw it in just in case
guard let strongSelf = self else {return}
//beyond this point we do not want self to die
//As long as reservedNodes is not added to the scene, this should not cause problems, never add it to the scene.
strongSelf.reservedNodes.addChild(node)
}
}
}

}


func update(currentTime: TimeInterval)
{
//If I need nodes grab from reserve
//what is nice about .first is the where feature, so you can say first(where:{$0.isKind(of:PlatformNode)})
if let node = reserveNodes.children.first
{
node.moveToParent(self) //this will remove them from the array for us
}
}

func didFinishUpdate()
{
spawnReserves()
}

现在有了子类化,您可以更进一步,检查何时移除子节点以生成新节点,这样您就可以始终创建节点,但我将把更高级的工作留给您。这至少应该可以帮助您从概念上开始使用池

关于arrays - SpriteKit & Swift,是否可以使用数组来汇集 SKSpritenodes?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45553161/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com