Folder of images: create and fill SKShapeNodes, 1 of each
Asked Answered
K

2

2

Is it possible to create a folder and have SpriteKit go through that folder, find each image (regardless of name), and create a SKShapeNode for each in that folder (regardless of how many there are)?

Assume all images are the same size, and all .png files ready to be used as unique images as textures for filling SKShapeNodes, and that all SKShapeNodes will be the same size.

I want to know, once done, how many shapes have been created, and have them uniquely named based on the name of the image of the texture used.

But all I'm reading seems to be about knowing how many images are there, and what their names are, before hand.

Clueless as to where to start searching about how to do this.

Update: no idea how to reference the "folder" with images:

I've dumped the images, with their very imaginative names [one, two, three, four, five etc. ], into a folder as "atlas", like this:

enter image description here

but as per Allessandro's wonderful answer, I have no idea how to address this "folder" and get at what's in it.

I think it's this line I'm getting completely wrong:

let folderPath = Bundle.main.path(forResource: "Images", ofType: nil)

I don't know what to replace "Images" with.

Update 2:

Found a much easier way to do this:

let myTextureAtlas = SKTextureAtlas(named: "demoArt")

        print(myTextureAtlas)
        print(myTextureAtlas.textureNames)
Kalina answered 1/10, 2016 at 20:47 Comment(2)
Are you sure you want SKShapeNode(s)? Maybe you mean SKSpriteNode?Videogenic
Definitely want SKShapeNodes. Odd shapes, mostly circles, but some other odder things. I wish there was something more performant, but converting them to SKSpriteNodes after adding textures and outlines is the best I can do...Kalina
B
1

Too many requests , so I try to help you with some code:

Create a folder:

func createDir(folderName:String) {
        let fileManager = FileManager.default
        if let directory = fileManager.containerURL(forSecurityApplicationGroupIdentifier: "APP_GROUP_IDENTIFIER") {
            let newDirectory = directory.appendingPathComponent(folderName)
            try! fileManager.createDirectory(at: newDirectory, withIntermediateDirectories: false, attributes: nil)
        }
}

Now you have your folder so you can decide to save a file or to copy one file from documents to this new directory. I make an example for the last one.

Copy a file:

let fileManager = FileManager.default
do {
   try fileManager.copyItem(atPath: "hero.png", toPath: "subfolder/hero.swift")
}
catch let error as NSError {
   print("Something went wrong: \(error)")
}

Now you want to know how to extract all files from a directory.

Extract all files from a directory:

func extractAllFile(atPath path: String, withExtension fileExtension:String) -> [String] {
        let pathURL = NSURL(fileURLWithPath: path, isDirectory: true)
        var allFiles: [String] = []
        let fileManager = FileManager.default
        if let enumerator = fileManager.enumerator(atPath: path) {
            for file in enumerator {
                if #available(iOS 9.0, *) {
                    if let path = NSURL(fileURLWithPath: file as! String, relativeTo: pathURL as URL).path
                        , path.hasSuffix(".\(fileExtension)"){
                        allFiles.append(path)
                    }
                } else {
                    // Fallback on earlier versions
                }
            }
        }
        return allFiles
    }

Usage:

let folderPath = Bundle.main.path(forResource: "Images", ofType: nil)
let allPngFiles = extractAllFile(atPath: folderPath!, withExtension: "png") // returns file path of all the png files inside the folder

After that, you can create an array of SKShapeNode based from allPngFiles using fillTexture with a SKTexture created from each image and give to each node the name of the file used (so you know at the end also how many nodes you have created from array.count).

Bohner answered 2/10, 2016 at 7:23 Comment(26)
WOW!!! And SORRY!!! The first part of the question, folder creation and dumping of images in it, I was talking about as a Finder activity. That I do that. The important question, for me, was having created that folder with an unspecified amount of images, is it possible to use that content in the way asked. Now I see I must learn a lot about file handling, because that's all here, too. I'm truly sorry, and THANK YOU!!!Kalina
And, strange as this may seem, it's the very last part (creating that array of textures and skshapenodes) that's the really tricky part, for me. I didn't know if this is possible, or how.Kalina
You're welcome, basically you can do all you've asked in your question, proceed step by step and check the progression of your work.Bohner
Thank you. You're a mine of information. I see and am learning 10x as much as I expected from this process. It never occurred to me that the file handling could be done in code.Kalina
This is going to take me some days to unpack and get working. Just reading each line takes minutes, then many searches and examinations to grok. Realising how stupid I am...Kalina
I'm struggling with folderPath. What should this be if my "folder" is demoArt.atlas in projects main folder?Kalina
@Kalina demoArt.atlas is a directory, have you ever change directory to an atlas folder? It's a common folder, simply have a dot and another word after it. Same thing for .atlascBohner
Yes, I created it as a .atlas folder. I'm trying to import sprites, and this seems to be the way SpriteKit wants this done.Kalina
@Kalina If you want the atlasc of your atlas folder: import atlas folder to you project , build it, go below to Product -> <ProjectName>.app , right button mouse ->Show in finder -> Show package contents ... here you should find also the atlasc folder, just copy and paste to your project folder and you have the atlasc folder (collage of frames to few images + plist ) so you can remove the atlas folderBohner
Wow. That's probably easy for you to say, you know where all that is, and what it all means. Decompressing that is hours of stepping around Xcode, for me. And it makes no sense. What is the goal of doing all that? Why can't I drag a folder into Xcode, as they claim, and have it all instantly recognised as to what it is, and where it is?Kalina
And what is an atlasc folder, and how is it different to an atlas folder?Kalina
@Kalina look this PDF man, raywenderlich.com/downloads/… , it explain your doubtsBohner
Here's a super stupid question: having created an array of all the names of these files, how do I use them as the unique names of the instances created using their texture? eg: arrayOfNames.first is "red", how do I now make an instance like let red = newInstanceOf()... how do I use that value of "red" to be the name of an instance?Kalina
And is that even possible?Kalina
Let me the time to read this question :) and give a reasonable answer..Bohner
It might be one of the most stupid questions of all time. I'm trying to find a way to name instance references, dynamically. That has to be wrong ;)Kalina
Generally, the idea to change dynamically names of instances come from the association of the code context to what you want to achieve, it's normal. But unachievable. Instead of it you have dictionary: you can associate a key to a value so you have "red": "redFile.txt" , this is more useful, in other words String:AnyObjectBohner
but dictionary I lose the index of an Array[n] right?Kalina
Dictionary have the index. Don't have a sorting like array, you lost just sorting.Bohner
Sadly, that sorting is important to me. Maybe I need an Array and a Dictionary, as friends.Kalina
Sure, you can built a custom struct. An Array of a custom struct or a dictionary as single element.Bohner
How does that look and work? And probably needs to be a new question... but I don't even know enough about the idea to formulate the question...Kalina
maybe this is an easier question, and less stupid... if I use a loop to create a bunch of objects, how do I make sure they all have unique reference names?Kalina
And, then, having given them all unique reference "names", put them in an array with those names.Kalina
The first part, how do I, using a loop, create multiple instances of a class, all with unique names, from within the loop?Kalina
I spoke about struct, but if you want to create a custom class you can. Choose what is more confortable for you.Bohner
E
1

Slightly different answer here. I'm not sure why one needs to create a directory and copy files over. In your screenshot you have a demoArt.atlas with 7 files (one.png, two.png, etc). You indicate you want to generate an SKShapeNode. It still isn't clear to me why you want SKShapeNode, but ignoring that, you just need to know the folder name. You'll notice how the folder is blue, which means it is a reference. This means that in the image, the folder is retained.

This would get you all the files in that directory:

let documentsPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0]
let texPath = NSURL(fileURLWithPath: documentsPath).appendingPathComponent("demoArt.atlas")

let filemanager:FileManager = FileManager()
// Error check/ensure path exists
let files = filemanager.enumerator(atPath:texPath!.path)

while let file = files?.nextObject() {
    print(file)
    // Create your SKShapeNode here, you can load file from this
    // This is all relative path, so "file" would be one.png, two.png, etc. If you need the full path, you
    // need to prepend texPath
}

Note the key diff here is not copying files over. Maybe I just don't understand the problem and why it would require the copy.

If you wanted to put that in an array you can. But here you'll have the file name of the texture which you would of course need to load.

Realistically, you want to load those textures asynchronously first, then construct your SKShapeNode.

Edile answered 6/10, 2016 at 6:28 Comment(4)
Yes, I've done a proper poor job of communicating what's going on here, and the need. There is no need for copying over files, my first draft of the question might have made it seem like file handling was part of the question, hence Alessandro's efforts there. The question I was trying to ask is about getting the files out, using them as textures, regardless of their names, so I could literally dump anything graphical in there, and have it work every time, to the limit of the images in the "folder". I don't really get how this left side works in Xcode. They're sometimes folders, sometimes not.Kalina
SpriteKit docs sometimes ask for addresses to folders, sometimes just say type in literally the name of files, sometimes there's a need for some other stepping into whatever's stored in the project. This ambiguity is doing my head in. And the "just drag and drop it in..." without specifics of WHERE to drop folders in is even more exasperating. Right up there with IBOutlets, which I think are super ridiculous to have as drag and drop, and the reason I'm using SpriteKit... to avoid IBOutlet. I kid. But only partially.Kalina
I think someone at Apple wants to pretend Xcode is approachable and friendly, and that's how IBOutlets, Storyboards and the file/texture handling in SpriteKit gets created. But they never look at how these things work in other apps, not even their own Pages/KeyNote/Numbers apps, let alone anything that has true drag-n-drop friendliness. As a result, it's just for WWDC videos... like the SKTileMapNode nonsense.Kalina
@Kalina In your Xcode project you have Folder references and Groups. Groups are just a logical grouping of files that can be in any directory. A folder reference is just that. Check out for more info: #34208164Edile

© 2022 - 2024 — McMap. All rights reserved.