微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

使用 JSON 和 sprite kit 设置可以升级的玩家

如何解决使用 JSON 和 sprite kit 设置可以升级的玩家

我是 swift/spritekit 的新手,我 8 岁的孩子要求我为他制作一款基本游戏,所以我答应了(现在几乎后悔了,哈哈)

我想要实现的目标:能够根据获得的经验值“升级”的角色 - 我使用 JSON 文件来描述级别

JSON 文件

[
    {
        "id": 1,"spriteTexture": "playerL1","weapon": "playerL1Weapon","expToLvlUp": 50,"health": 2,"attack": 1,"defense": 1,},{
        "id": 2,"spriteTexture": "playerL2","weapon": "playerL2Weapon","expToLvlUp": 60,"health": 7,"attack": 2,"defense": 2,{
        "id": 3,"spriteTexture": "playerL3","weapon": "playerL3Weapon","expToLvlUp": 100,"health": 10,"attack": 5,"defense": 5,}
]

可解码文件

import Foundation


extension Bundle{
    func decode<T: Decodable>(_ Type: T.Type,from file: String) -> T {
        guard let url = self.url(forResource: file,withExtension: nil) else {
            fatalError("Failed to locate \(file) in bundle")
        }
        guard let data = try? Data(contentsOf: url) else{
            fatalError("Failed to load \(file) from bundle")
        }
        let decoder = JSONDecoder()
        
        guard let loaded = try? decoder.decode(T.self,from: data) else {
            fatalError("Failed to decode /(file) from bundle")
        }
        
        return loaded
    }
}

我已经设置了一个结构来从 JSON 文件获取值:

import SpriteKit

struct PlayerLevel: Codable {
    let id: Int
    let spriteTexture: String
    let weapon: String
    let expToLvlUp: Int
    let health: Int
    let attack: Int
    let defense: Int
}

这是我的课:

import Foundation
import SpriteKit

class Player: SKSpriteNode {
    var type: PlayerLevel
    {
        didSet{
            levelUp()
        }
    }
    
    init(type: PlayerLevel){
        self.type = type
        
        let texture = SKTexture(imageNamed: type.spriteTexture)
        super.init(texture: texture,color: .clear,size: texture.size())

        position.x = -900
        physicsBody = SKPhysicsBody(texture: texture,size: texture.size())
        physicsBody?.categoryBitMask = CollisionType.player.rawValue
        physicsBody?.collisionBitMask = CollisionType.enemy.rawValue | CollisionType.enemyWeapon.rawValue
        physicsBody?.contactTestBitMask = CollisionType.enemy.rawValue | CollisionType.enemyWeapon.rawValue
        zPosition = 5
        name = "player"
    }
    
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    func shoot(){
        let shot = SKSpriteNode(imageNamed: type.weapon)
        shot.name = self.type.weapon
        shot.size = CGSize(width: 50,height: 50)
        shot.physicsBody = SKPhysicsBody(rectangleOf: shot.size)
        shot.physicsBody?.categoryBitMask = CollisionType.playerWeapon.rawValue
        shot.physicsBody?.collisionBitMask = CollisionType.enemy.rawValue | CollisionType.enemyWeapon.rawValue
        shot.physicsBody?.contactTestBitMask = CollisionType.enemy.rawValue | CollisionType.enemyWeapon.rawValue

        addChild(shot)
        shot.zPosition = 3

        shot.physicsBody?.affectedByGravity = false

        let movement = SKAction.move(to: CGPoint(x: 4000,y: shot.position.y),duration: 1)
        let sequence = SKAction.sequence([movement,.removeFromParent()])
        shot.run(sequence)
    }
    func levelUp(){
        self.texture = SKTexture(imageNamed: type.spriteTexture)
        let texture = SKTexture(imageNamed: type.spriteTexture)
        self.physicsBody = SKPhysicsBody(texture: texture,size: texture.size())
    }
}

首先,我想知道我的设置是否正确。 在我的游戏场景中:


import SpriteKit
import GameplayKit

enum CollisionType: UInt32 {
    case player = 1
    case playerWeapon = 2
    case enemy = 4
    case enemyWeapon = 8
    case ground = 16
}

class GameScene: SKScene,SKPhysicsContactDelegate {
    
    // Properties
    var isPlayerAlive = true
    var playerLevels = Bundle.main.decode([PlayerLevel].self,from: "player-levels.json")
    let enemyTypes = Bundle.main.decode([EnemyType].self,from: "enemies.json")
    var currentEnemy = 0
    var currentLevel = 0 {
        didSet {
            player.type = playerLevels[currentLevel]
        }
    }
    var player: Player!
    var enemy: Enemy!
    var levelUp: SKSpriteNode!
    var healthLabel: SKLabelNode!

    var scoreLabel: SKLabelNode!
    let playerLevelLabel = SKLabelNode(fontNamed: "Chalkduster")
    
    var score = 0 {
        didSet{
            scoreLabel.text = "score: \(score)"
            
        }
    }
    let ground = SKSpriteNode(imageNamed: "groundBottom")
    let groundT = SKSpriteNode(imageNamed: "gameGroundTop")
    var expLabel: SKLabelNode!
    var exp = 0 {
        didSet{
            expLabel.text = "Experience Points: \(exp) / \(playerLevels[currentLevel].expToLvlUp)"
        }
    }
    var health = 0 {
        didSet{
            healthLabel.text = "Health: \(playerLevels[currentLevel].health)"
        }
    }
    override func didMove(to view: SKView) {
        physicsWorld.contactDelegate = self

        makeGround()
        initializePlayer()
        spawnEnemy()
        makescoreLabel()
        makeExpLabel()
        makeHealthLabel()
        
    }
    
    func initializePlayer(){
        player = Player(type: playerLevels[currentLevel])
        addChild(player)
        playerLevelLabel.text = "Details: \(player.type)"
        playerLevelLabel.fontSize = 40
        playerLevelLabel.position = CGPoint(x: 0,y: self.frame.minY + 200)
    }
    func makescoreLabel(){
        scoreLabel = SKLabelNode(fontNamed: "Chalkduster")
        scoreLabel.position = CGPoint(x:self.frame.maxX - 250,y:self.frame.maxY - 100)
        scoreLabel.horizontalAlignmentMode = .right
        scoreLabel.fontSize = 40
        scoreLabel.zPosition = 5
        scoreLabel.text = "score: 0"
        scoreLabel.name = "score"
        addChild(scoreLabel)
    }
    func makeExpLabel(){
        expLabel = SKLabelNode(fontNamed: "Chalkduster")
        expLabel.position = CGPoint(x:self.frame.minX + 500,y:self.frame.maxY - 110)
        scoreLabel.fontSize = 40
        expLabel.zPosition = 5
        expLabel.text = "Expereience Points: 0 / \(playerLevels[currentLevel].expToLvlUp)"
        expLabel.name = "exp"
        addChild(expLabel)
    }
    func makeHealthLabel(){
    
        healthLabel = SKLabelNode(fontNamed: "Chalkduster")
        healthLabel.position = CGPoint(x:self.frame.minX + 1200,y:self.frame.maxY - 110)
        healthLabel.fontSize = 40
        healthLabel.zPosition = 5

        healthLabel.text = "Health: \(playerLevels[currentLevel].health)"
        healthLabel.name = "health"
        addChild(healthLabel)
    }
    func makeGround(){
        ground.name = "ground"
        ground.position.x = frame.midX
        ground.position.y = frame.minY
        ground.zPosition = 1
        addChild(ground)
        ground.physicsBody = SKPhysicsBody(texture: ground.texture!,size: ground.texture!.size())
        ground.physicsBody?.affectedByGravity = false
        ground.physicsBody?.isDynamic  = false

        groundT.position.x = frame.midX
        groundT.position.y = ground.position.y + 50
        groundT.physicsBody?.isDynamic = false

        addChild(groundT)

    }
    override func touchesBegan(_ touches: Set<UITouch>,with event: UIEvent?) {
        let touch = touches.first
        let location = touch?.location(in: self)
        let nodesAtLocation = nodes(at: location!)
        for node in nodesAtLocation {
            if node.name == "score"{
                score += 10
                exp += 5
                
                upgrade()
            }
            if node.name == "attack"{
                attack()
            }
        }
    }
    
    
    func upgrade() {
        if exp < playerLevels[currentLevel].expToLvlUp { return }
        if currentLevel + 1 > playerLevels.count - 1 {
            gameOver()
            return
        }
        if let explosion = SKEmitterNode(fileNamed: "Explosion") {
            explosion.position = player.position
            addChild(explosion)
        }
        //charLevelUp()
        
        currentLevel += 1
        playerLevelLabel.text = "Details: \(player.type)"
    }
    
    func didBegin(_ contact: SKPhysicsContact) {
        guard let nodeA = contact.bodyA.node else { return }
        guard let nodeB = contact.bodyB.node else { return }
        
        let sortednodes = [nodeA,nodeB].sorted { $0.name ?? "" < $1.name ?? ""}
        
        let firstNode = sortednodes[0]
        let secondNode = sortednodes[1]
        
        if firstNode.name == "ground" { return }
        if secondNode.name == "ground" { return }
        if secondNode.name == "player" {
            guard isPlayerAlive else { return }
            
            if let explosion = SKEmitterNode(fileNamed: "explosion"){
                explosion.position = firstNode.position
                addChild(explosion)
            }
            
            //health -= 1
            
            if playerLevels[currentLevel].health == 0{
                gameOver()
                secondNode.removeFromParent()
            }
            firstNode.removeFromParent()
        } else if let enemy = firstNode as? Enemy {
            enemy.health -= 1
            
            if enemy.health == 0 {
                if let explosion = SKEmitterNode(fileNamed: "Explosion") {
                    expLabel.position = enemy.position
                    addChild(explosion)
                }
                
                enemy.removeFromParent()
                score += 50
                exp  = enemy.expGive
            }
            if let explosion = SKEmitterNode(fileNamed: "Explosion") {
                explosion.position = enemy.position
                addChild(explosion)
                
            }
            
            secondNode.removeFromParent()
        } else {
            if let explosion = SKEmitterNode(fileNamed: "Explosion") {
                explosion.position = secondNode.position
                addChild(explosion)
            }
            
            firstNode.removeFromParent()
            secondNode.removeFromParent()
        }
        
    }

我已经设法让精灵改变纹理和物理身体,expReq 指向根据玩家级别改变,但是,我似乎无法更新健康属性或任何其他属性。任何帮助将不胜感激 - 我不确定我是否正确设置 - 请告知:)

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。