SKTextureAtlas cannot be found - swift

I dragged a folder named "movementAnim" into the Image assets folder, which is suppose to create a texture atlas (from what I picked from the WWDC 2015 What's New in SpriteKit Session). See the code below:
SimpleSprite class:
Init() {
let spriteAtlas = SKTextureAtlas(named: "movementAnim")
sprite = SKSpriteNode(texture: spriteAtlas.textureNamed("moveAnim01"))
sprite.name = spriteCategoryName
sprite.position = CGPointMake(CGRectGetMidX(screenSize), sprite.frame.size.height * 3.7)
initialPos = sprite.position
sprite.zPosition = 10
}
func physicsProperties () {
sprite.physicsBody = SKPhysicsBody(rectangleOfSize: sprite.frame.size)
sprite.physicsBody?.friction = 0.4
sprite.physicsBody?.restitution = 0.1
sprite.physicsBody?.dynamic = false
}
In the init of the GameScene class:
simpleSprite = SimpleSprite()
addChild(simpleSprite!.sprite)
simpleSprite!.physicsProperties()
I get the following log message:
Texture Atlas 'movementAnim' cannot be found.
But when I use the following instead of the texture, it works perfectly:
sprite = SKSpriteNode(imageNamed: "newMoveAnim01")
I've crossed checked the names and made sure there are no duplicates. I am not sure what's wrong.

If you add the extension .spriteatlas to your folder name, it should work. XCode does not add this by default.
You are correct that atlases are done in the image assets folder now, William Hu's way was the old way it was done.

Create a folder in your project root path, name it movementAnim.atlas, then copy and paste all your images into this folder. Then go back your project navigator and add this folder into your project, make sure the folder is blue.

Related

Automatic texture importer not assigning alpha in Unity

I have written a custom texture importer, and put it in my Editor folder inside the Assets folder, which is supposed to apply my custom settings automatically when a new texture is imported to the project.
This is my code:
'''
public class TexturePostProcessor : AssetPostprocessor
{
void OnPostprocessTexture(Texture2D texture)
{
TextureImporter importer = assetImporter as TextureImporter;
importer.textureType = TextureImporterType.Default;
TextureImporterPlatformSettings settings = importer.GetPlatformTextureSettings("WebGL");
settings.overridden = true;
settings.name = "WebGL";
settings.maxTextureSize = 1024;
settings.format = TextureImporterFormat.DXT5Crunched;
settings.compressionQuality = 50;
settings.allowsAlphaSplitting = false;
importer.SetPlatformTextureSettings(settings);
}
}
'''
The issue i have is, when the texture is imported, it doesn't get the alpha channel, but if I manually right click and re-import the texture, then the alpha is applied. You can see that in below image:
Re-importing is not an option though because our textures will be coming in from external sources automatically, so it needs to have the correct alpha and format the first time.
Can someone point me in the right direction please?

SceneKit – Node with animated skeleton not moving

I have a SceneKit app with 2 .scn files in the art.scnassets folder. The base ship.scn that comes with the project, and a new file orcIdle.scn that I added myself.
When I call this code on this ship, it moves it properly:
self.myScene = SCNScene(named: "art.scnassets/ship.scn")!
// Set the scene to the view
let ship = (myScene.rootNode.childNode(withName: "ship", recursively: false))!
ship.position = SCNVector3(0, 0, -5)
self.sceneView.scene = myScene
When I call the same code on my orcIdle file, it places the orc exactly at (0,0,0)
self.myScene = SCNScene(named: "art.scnassets/orcIdle.scn")!
// Set the scene to the view
let orc = (myScene.rootNode.childNode(withName: "orcIdle", recursively: false))!
orc.position = SCNVector3(0, 0, -5)
self.sceneView.scene = myScene
here are screenshots of the file node:
This is the default ship file included in the project by Xcode.
This is my orcIdle file.
As you can see, it's the exact same code but 1 moves, and the other doesn't. Also, in the top right corner of the images, i can adjust the Z value there. It works for .ship, but not for .orcIdle.
Is it a scale issue? Any thoughts?
Here's a new screenshot with as much of the scene graph as I can capture.
Usually, you must select a skeleton's top hierarchy (like root node) to move geometry, since its mesh was bound to skeleton. If model's skeleton is considerably deeper in the hierarchy use .childNodes[x] subscript syntax to fetch a desired joint.
But a solution based on your .scn file is the following – create a topNode object and put root and LOD_Group inside it.
So your code should look like this:
let scene = SCNScene(named: "art.scnassets/orcIdle.scn")!
orc = scene.rootNode.childNode(withName: "topNode", recursively: true)!
orc.position = SCNVector3(0,0,-20)

JSONReaderException when deploying on hololens [duplicate]

I have am developing a HoloLens project that needs to reference .txt files. I have the files stored in Unity's 'Resources' folder and have them working perfectly fine (when run via Unity):
string basePath = Application.dataPath;
string metadataPath = String.Format(#"\Resources\...\metadata.txt", list);
// If metadata exists, set title and introduction strings.
if (File.Exists(basePath + metadataPath))
{
using (StreamReader sr = new StreamReader(new FileStream(basePath + metadataPath, FileMode.Open)))
{
...
}
}
However, when building the program for HoloLens deployment, I am able to run the code but it doesn't work. None of the resources show up and when examining the HoloLens Visual Studio solution (created by selecting build in Unity), I don't even see a resources or assets folder. I am wondering if I am doing something wrong or if there was a special way to deal with such resources.
Also with image and sound files...
foreach (string str in im)
{
spriteList.Add(Resources.Load<Sprite>(str));
}
The string 'str' is valid; it works absolutely fine with Unity. However, again, it's not loading anything when running through the HoloLens.
You can't read the Resources directory with the StreamReader or the File class. You must use Resources.Load.
1.The path is relative to any Resources folder inside the Assets folder of your project.
2.Do not include the file extension names such as .txt, .png, .mp3 in the path parameter.
3.Use forward slashes instead of back slashes when you have another folder inside the Resources folder. backslashes won't work.
Text files:
TextAsset txtAsset = (TextAsset)Resources.Load("textfile", typeof(TextAsset));
string tileFile = txtAsset.text;
Supported TextAsset formats:
txt .html .htm .xml .bytes .json .csv .yaml .fnt
Sound files:
AudioClip audio = Resources.Load("soundFile", typeof(AudioClip)) as AudioClip;
Image files:
Texture2D texture = Resources.Load("textureFile", typeof(Texture2D)) as Texture2D;
Sprites - Single:
Image with Texture Type set to Sprite (2D and UI) and
Image with Sprite Mode set to Single.
Sprite sprite = Resources.Load("spriteFile", typeof(Sprite)) as Sprite;
Sprites - Multiple:
Image with Texture Type set to Sprite (2D and UI) and
Image with Sprite Mode set to Multiple.
Sprite[] sprite = Resources.LoadAll<Sprite>("spriteFile") as Sprite[];
Video files (Unity >= 5.6):
VideoClip video = Resources.Load("videoFile", typeof(VideoClip)) as VideoClip;
GameObject Prefab:
GameObject prefab = Resources.Load("shipPrefab", typeof(GameObject)) as GameObject;
3D Mesh (such as FBX files)
Mesh model = Resources.Load("yourModelFileName", typeof(Mesh)) as Mesh;
3D Mesh (from GameObject Prefab)
MeshFilter modelFromGameObject = Resources.Load("yourGameObject", typeof(MeshFilter)) as MeshFilter;
Mesh loadedMesh = modelFromGameObject.sharedMesh; //Or design.mesh
3D Model (as GameObject)
GameObject loadedObj = Resources.Load("yourGameObject") as GameObject;
//MeshFilter meshFilter = loadedObj.GetComponent<MeshFilter>();
//Mesh loadedMesh = meshFilter.sharedMesh;
GameObject object1 = Instantiate(loadedObj) as GameObject;
Accessing files in a sub-folder:
For example, if you have a shoot.mp3 file which is in a sub-folder called "Sound" that is placed in the Resources folder, you use the forward slash:
AudioClip audio = Resources.Load("Sound/shoot", typeof(AudioClip)) as AudioClip;
Asynchronous Loading:
IEnumerator loadFromResourcesFolder()
{
//Request data to be loaded
ResourceRequest loadAsync = Resources.LoadAsync("shipPrefab", typeof(GameObject));
//Wait till we are done loading
while (!loadAsync.isDone)
{
Debug.Log("Load Progress: " + loadAsync.progress);
yield return null;
}
//Get the loaded data
GameObject prefab = loadAsync.asset as GameObject;
}
To use: StartCoroutine(loadFromResourcesFolder());
If you want to load text file from resource please do not specify file extension
just simply follow the below given code
private void Start()
{
TextAsset t = Resources.Load<TextAsset>("textFileName");
List<string> lines = new List<string>(t.text.Split('\n'));
foreach (string line in lines)
{
Debug.Log(line);
}
}
debug.Log can print all the data that are available in text file
You can try to store your text files in streamingsasset folder. It works fine in my project

How do run an SKAction on a group of SKSpriteNodes with the same name?

I'm making a game in Xcode 6 using spriteKit and swift. I have a plane on scene, and to make it look like its moving, I'm create clouds off the scene to the left of the screen. I then us an SKAction to move the cloud to the right side of the screen. This works great. You then click to jump off the plane, and the plane moves up off the scene. I then have it start making the clouds on the bottom of the scene, then they move up off the top of the scene, but the problem is, the already existing clouds still have to move to the right side of the screen. My question is, how do I make it so all of the existing clouds stop their action that moves them to the right, then begin to move up exactly where they are? How do I access the group of existing clouds all at the same time once they have been created? I also want the clouds to slow down after you have jumped when you tap the screen to open your parachute, but this should be able to be done by ending the SKAction that moves the clouds, then using another SKAction on them that moves them up slower, but I don't know how to access a group of SKSpriteNodes.
Here is the code that I have to make the clouds:
//This is how the cloud is first declared at the top of the .swift file
var cloud = SKSpriteNode()
//This is the function that runs every certain interval through an NSTimer
func createCloud()
{
cloud = SKSpriteNode(imageNamed: "cloud")
cloud.xScale = 1.25
cloud.yScale = cloud.xScale/2
cloud.zPosition = -1
self.addChild(cloud)
if personDidJump == false
{
let moveRight = SKAction.moveToX(CGRectGetWidth(self.frame) + CGRectGetWidth(cloud.frame), duration: cloudSpeed)
var apple = CGRectGetWidth(self.frame)
var randomNumber:CGFloat = CGFloat(arc4random_uniform(UInt32(apple)))
cloud.position = CGPointMake(-CGRectGetWidth(cloud.frame), randomNumber)
cloud.runAction(moveRight)
}
if personDidJump == true
{
let moveUp = SKAction.moveToY(CGRectGetHeight(self.frame) + CGRectGetWidth(cloud.frame), duration: cloudSpeed)
var apple = CGRectGetWidth(self.frame)
var randomNumber:CGFloat = CGFloat(arc4random_uniform(UInt32(apple)))
cloud.position = CGPointMake(randomNumber, -CGRectGetHeight(cloud.frame))
cloud.runAction(moveUp)
}
}
Also, should I be worried about deleting the clouds when they move off the scene? Or can I just leave them there because you can't see them, and from what I've seen, they don't lag you.
Any help would be greatly appreciated. Thank you.
-Callum-
Put your clouds in an array. When your player jumps (or whenever you need to move them) run through the array and run your action on each cloud.
stackoverflow.com/a/24213529/3402095
^ That is where I found my answere ^
When you make a node give it a name:
myNode.name = "A Node Name"
self.addChild(myNode)
If there are a lot of these nodes, later you can change properties or preform SKAcions on these nodes or do whatever you want to do by using enumerateChildNodesWithName:
self.enumerateChildNodesWithName("A Node Name")
{
myNode, stop in
myNode.runAction(SKAction.moveToY(CGRectGetHeight(self.Frame), duration: 1)
}
I hope this is useful to whoever may need it.

How do I remove a group of Nodes in Swift?

I'm new to objective c and swift and I created a small app where small circles are rendered and once the player collides with a circle, the game ends. I managed to get everything to work, but how do I remove the nodes after they collide. I tried removeAllChildren(), but none of them disappear. When I use removeFromParent(), only 1 disappears. I want a way to remove all 3 nodes that will be rendered in the code below
//addEvilGuys() is called first
func addEvilGuys()
{
addEvilGuy(named: "paul", speed: 1.3, xPos: CGFloat(self.size.height/3))
addEvilGuy(named: "boris", speed: 1.7, xPos: frame.size.width/4 + 50)
addEvilGuy(named: "natasha", speed: 1.5, xPos: frame.size.width/4 + 150)
}
func addEvilGuy(#named:String, speed:Float, xPos: CGFloat)
{
evilGuyNode = SKSpriteNode(imageNamed: named)
evilGuyNode.zPosition = 10
evilGuyNode.physicsBody = SKPhysicsBody(circleOfRadius: 16)
evilGuyNode.physicsBody!.affectedByGravity = false
evilGuyNode.physicsBody!.categoryBitMask = ColliderType.BadGuy.rawValue
evilGuyNode.physicsBody!.contactTestBitMask = ColliderType.Hero.rawValue
evilGuyNode.physicsBody!.collisionBitMask = ColliderType.Hero.rawValue
evilGuyNodeCount++
var evilGuy = EvilGuy(speed: speed, eGuy: evilGuyNode)
evilGuys.append(evilGuy)
resetEvilGuy(evilGuyNode, xPos: xPos)
evilGuy.xPos = evilGuyNode.position.x
addChild(evilGuyNode)
}
func resetEvilGuy(evilGuyNode:SKSpriteNode, xPos:CGFloat)
{
evilGuyNode.position.y = endOfScreenBottom
evilGuyNode.position.x = xPos
}
It looks like in addEvilGuy you are recreating a stored property (i.e. that is visible for the entire class + whatever the access level allows) to create the SKSpriteNode that you're adding. This means that you are orphaning the previously created EvilGuy.
In addEvilGuy, replace
evilGuyNode = SKSpriteNode(imageNamed: named)
with
let evilGuyNode = SKSpriteNode(imageNamed: named)
and remove the property from your class (it doesn't seem like you have a need for in in a larger scope).
It also looks like you're creating EvilGuys and storing them in an array, which is good. So when you can remove all of them from the screen with a function like:
func removeAllEvilGuys(evilGuys: [EvilGuy]) {
for evilGuy in evilGuys {
evilGuy.eGuy.removeFromParent()
}
}
As a best practice advice, since you mentioned you're a beginner:
I'd recommend defining the characteristics of the evil guys in a .plist and then use the file to create an array of evil guys. This way you can easily make changes to the evil guys in that file without having to change anything in your code.
The code that creates an EvilGuy object should be separated from the one that adds the evil guy to the screen. As long as you are storing the SKNode of each one, you'll be able to add/remove without unnecessarily recreating the entire object.