4

I am using the following code to generate a random image for the player in my game.

var playerTexture = [SKTexture]()

        playerTexture.append(SKTexture(imageNamed: “red”))
        playerTexture.append(SKTexture(imageNamed: “blue”))
        playerTexture.append(SKTexture(imageNamed: “green”))


        let rand = Int(arc4random_uniform(UInt32(playerTexture.count)))
        let chosenColor = playerTexture[rand] as SKTexture
        let playerSkin = chosenColor

The code above generates a random SKTexture (red, blue or green) called playerSkin.

    player = SKSpriteNode(texture: playerSkin)
    player.size = CGSize(width: 50, height: 50)
    player.position = location
    self.addChild(player)
    player.name = chosenColor.description

Then this next part of the code creates the player as an SKSpriteNode and assigns it a random texture of red, blue or green. BUT the main things is the code assigns the player.name to the randomly chosen image using:

player.name = chosenColor.description

Then I check the name of the player using print.

 print(player.name)

However, when I check the name of the player, it appears as one of the following depending on what random image was chosen:

Optional(" \'red\' (120 x 120)")

Optional(" \'blue\' (120 x 120)")

Optional(" \'green\' (120 x 120)")

My images are called "red", "blue" and "green" and are located in Assets.xcassets folder in Xcode.

My images are 120 x 120 but why are these long random names appearing? How can I set either "red", "blue" or "green" as the name of the player only?

I need the name to be EXACTLY "red", "blue" or "green" because I want to use the player.name later for a different function.

rmaddy
  • 314,917
  • 42
  • 532
  • 579

3 Answers3

2

There may be a better way to do this, but this is the first thing I thought of - make the playerTexture variable an array of tuples containing the texture and the name you want to give it:

 var playerTexture = [(SKTexture, String)]()

  playerTexture.append((SKTexture(imageNamed: “red”), "red"))
  playerTexture.append((SKTexture(imageNamed: “blue”), "blue"))
  playerTexture.append((SKTexture(imageNamed: “green”), "green"))

  let rand = Int(arc4random_uniform(UInt32(playerTexture.count)))
  let chosenColor = playerTexture[rand].0 as SKTexture
  let colorName = playerTexture[rand].1
  let playerSkin = chosenColor

  player = SKSpriteNode(texture: playerSkin)
  player.size = CGSize(width: 50, height: 50)
  player.position = location
  self.addChild(player)
  player.name = colorName
claassenApps
  • 1,137
  • 7
  • 14
  • Right. There is no way to retrieve the name from the `SKTexture` itself, so you need to store the string that you used to create it. (One way to simplify is to *only* store the string, and initialize the `SKTexture` inline when you assign `chosenColor`.) – andyvn22 Jul 18 '16 at 16:02
  • Thanks claassenApps! This was the easiest method! I'm new to coding, so this was perfect. Cheers! –  Jul 20 '16 at 18:16
1

The only way to get a filename from SKTexture is by using the Textual Representation For Classes.

Swift make it easy to convert a custom class to a string (e.g. for use with print) via the CustomStringConvertible protocol. (a clear improvement over earlier implementations)

This is an example:

class X : CustomStringConvertible  {
  var description: String{
    return "This is class X"
  }
}

print(X()) //output is: "This is class X"

So, if you make a:

print(SKTexture())

your actual output in Swift 2.2 will be:

<SKTexture> '(null)' (0 x 0)

where null is the filename.

To obtain your filename you can do:

let filename = chosenColor.description.characters.split{$0 == " "}.map(String.init)[1].stringByReplacingOccurrencesOfString("\'", withString: "") as! NSString

Output:

red.png

Advantages - easy to do, you can get the real filename used by your SKTexture

Disadvantages - It's not elegant, finally you parse a string from a class which could will change his description structure (for example a new element can be added to the description and the filename could be in the position 2 instead of the actual index 1 after <SKTexture>) in future iOS release's or Swift version's, but this might happen also to other parts of your code.

Alessandro Ornano
  • 34,887
  • 11
  • 106
  • 133
1

If you're just starting with SpriteKit, I would suggest that you create specialized subclasses of SKSpriteNode and keep all behaviour and concerns inside them. Over time you'll find that the whole game logic is going to be much simpler to implement and maintain.

public class PlayerNode:SKSpriteNode
{
   static let colorNames           = ["red","blue","green"]
   static let textures:[SKTexture] = PlayerNode.colorNames.map(){ SKTexture(imageNamed:$0) }

   init(randomAtLocation location:CGPoint)
   {
      let rand = Int(arc4random_uniform(UInt32(PlayerNode.colorNames.count)))
      super.init( texture: PlayerNode.textures[rand], 
                    color: UIColor.clearColor(), 
                     size: CGSize(width: 50, height: 50)
                )
      name     = PlayerNode.colorNames[rand]
      position = location
   }

   public required init?(coder aDecoder: NSCoder) { super.init(coder:aDecoder) }
}

So your player initializing code could be as simple as :

let player = PlayerNode(randomAtLocation:location)
self.addChild(player)
Alain T.
  • 40,517
  • 4
  • 31
  • 51
  • Is this: "PlayerNode.colorNames.map(){ SKTexture(imageNamed:$0) }" some magic voodoo that goes through all the textures? – Confused Oct 01 '16 at 22:23
  • Apart from the confusion regarding the array voodoo, I have to add, thank you! The code architecture tip is priceless. THANK YOU!!! – Confused Oct 01 '16 at 22:34
  • And, if you've got a moment... how do I change this line to reflect the size of the image being loaded, rather than being arbitrary? "size: CGSize(width: 50, height: 50)" – Confused Oct 06 '16 at 00:58
  • You could use super.init(texture:) without the color / size parameters. I believe it will use the size of the texture as a default. You can always set the color on the next line but I think it will be clear by default as well. – Alain T. Oct 06 '16 at 16:57