So I have objects that in turn have sprites associated to them. a snippet of my Object class:
import SpriteKit
class Block {
var sprite : ColourSprite
}
So as you can see, it has a variable that is in fact a SKSprite (ColourSprite is my custom class that inherits from SKSpriteNode).
Now, at some points during the game, these sprites are deleted (i.e sprite.removeFromParent()), but the objects are obviously still somewhere.
I want to be able to send the objects to garbage collection once their sprites are gone. I am thinking that I can do something like sprite.getOwner() but I can't seem to find it. Is this possible?
The only other option I can think of is to manually check all objects and check each one's sprite but I feel that is long and wasteful.
You can check whether the Blocks are still in memory by using Xcode 8.3's new debug panel.
Just after you remove your sprites pause the program and go to that panel. See if there is any Block instances in the left panel. If there is, click on it to check what is retaining it.
If for example your GameScene is retaining the Block, you go to your GameScene and find the property. Then you can just set that to nil after you remove your sprite.
Related
I am developing a game for iOS using Swift. The game is played in rounds, and when a round is over, it is no longer needed. So unlike conventional applications where a storyboard scene may stick around when someone navigates away from it, I want the scene for the round to be destroyed when the game navigates to the scene following the round.
I am pretty confident I have figured out a way to do this because I’m instantiating certain objects in the scene and I have verified that the deinit method for these objects gets call when the round ends and navigation to the next scene occurs. The problem is that for one of the objects, the deinit method is not being called, and I have not been able to figure out why. The storyboard scene should be the only thing referencing the object, and searching through to source code has not revealed any other usages. It seems like something beside the storyboard scene somehow has a reference to the object and keeps it alive when the scene goes away.
I have verified the object is being created by setting a breakpoint in its init method, and that breakpoint gets hit when starting the round.
I’ve tried using the Allocations instrument to track what might be referencing the object. However when I run the game and finish the round. I can find no evidence that the Allocation instrument ever saw the object at all. I suspect the instrument may not track objects that are created by a storyboard scene, especially since I can not find traces of the other storyboard objects that do get deleted with the storyboard.
What can be done to determine why this object seems to survive past the lifetime of the storyboard scene that should own it?
I think found out why the object was not being destroyed. In it's initializer it was applying a closure to something else. The closure contained a reference to a member of the object, and so I think the closure was capturing self strongly even though self was never explicitly needed for things to compile successfully. This might be a bug with the Swift compiler; it could have emitted a warning or error about this; it would have been easier the find and/or prevent the problem. Anyway I changed the closure so that it captures the object's member as unowned and now the object appears to get destroyed.
I'd like to switch things up a bit with my enemies in my SpriteKit game. They're just so... predictable. I've been inspired by the sorts of enemies that are encountered in The Binding of Isaac: Rebirth.
For example, let's say I'd like to implement enemies which split into two smaller enemies when enemy.health < 50.0f. In a simple scenario, this could be done from my main scene update loop by iterating through all my enemies. Something like:
if(enemy.health < 50 && enemy.type == kEnemyTypeSplitsIntoTwo) {
CGPoint position1 = CGPointMake(enemy.position.x+20,enemy.position.y);
CGPoint position2 = CGPointMake(enemy.position.x-20,enemy.position.y);
[enemy killEnemy];
[self spawnNewEnemyWithType:enemyType andHealth:50 atPosition:position1];
[self spawnNewEnemyWithType:enemyType andHealth:50 atPosition:position2];
}
This will probably work for simple cases. But this is something that I definitely want to keep out of my main scene update loop. The problem is that my enemy class is effectively a subclass of SKSpriteNode.
For situations like this, ideally I'd like a new class such as a ComplexEnemy or EnemyGroup class to handle this so I can implement more complex enemy behaviours and patterns (think epic boss fights with multiple phases). I'd imagine this new class would likely derive from SKNode (or even NSObject?) and generate multiple Enemy instances at certain points.
Am I thinking down the right path? I'd be interested to hear what means people have used to achieve this sort of behaviour, preferably with a couple of examples.
-DC
tl;dr - Groups of enemies, bosses with multiple phases. How do you guys do it?
There's nothing wrong with using SKSpriteNode as an enemy class. I do it all the time. If you want to add a health bar, for example, you can simply add it as child.
Your question is primarily opinion based so expect it to be closed soon enough. However, it is a good question nonetheless. I suggest you use one or more enemy SKSpriteNode classes to handle your workload as it can make things easier for a beginner. You can of course get away with just using one enemy class and have its update method handle various aspects based on properties. For example:
-(void)update:(NSTimeInterval)currentTime {
if(self.enemyType == kDragon) {
// do big stuff
}
if(self.enemyType == kDwarf) {
// do small stuff
}
}
I am currently working on a project which has 10 different kinds of enemies and 4 behavior options for each one. It is all being handled from one class (SKSpriteNode).
It all boils down to what you want and how you arrange your code to do the job. I suggest you think about exactly what it is you are trying to do and if you get stuck, ask for help on a more specific issue.
In your situation, I would subclass the ComplexEnemy as a simple object. This object would be responsible for the instantiation and the adding and removing to the scene of the various enemies that could appear.
Then in your scene update method, I'd call a checking method in that object. The checking method would do the rest of the heavy lifting. You can put that call (the one in the update method) in an array of methods and when the ComplexEnemy gets instantiated, it would register itself in that array so it can be checked. It would remove itself from the array before being removed from memory..
I'm rather new to objective C and at the moment I'm trying to create one small project.
The task I want to accomplish is the following:
I've got the UIViewController for the screen of the game I'm creating. It has an UIImageView and a UITextView on it. What it does so far is that the latter one is moving towards the former one. And when their frames intersect (CGRectIntersectsRect) some actions happen.
What I want to achieve next is to create a specific class for UITextviews, so that there will be many of them created on the screen of UIViewController (I think array should be used here). And next I want every of them to be checking themselves, if they have an intersection with the UIImageView - than (again) something happens.
I've tried several ways like creating a mutable array, but every time I've some errors connected with variables of the original ViewController used inside of the new class (Hit).
The code I use for the one existing UITextView, that is created inside of UIViewController, is the following:
-(void)Moving{
HitR.center = CGPointMake(HitR.center.x+HitRX, HitR.center.y+HitRY);
if (CGRectIntersectsRect(HitR.frame, Finish.frame)) {
/*some actions here*/
}
}
etc
Can you help me to create these array of UItextFields, using their own class, tell them what to do with the help of properties like UIimageview.frame from the ViewController and then to place them on the screen.
P.S. I've read numerous articles about how to transfer variables from one class to another, but still failed to accomplish my aim.
I'm currently building a game using Xcode, sprite kit and now tiled. The game is simple, a person jumping from 1 block to another, but if they hit the side it will be game over. Now is their anyway through tiled to create a block for the person to jump on. And through out the game to keep repeating and coming on for the person to jump on, I would like the object to have different heights and widths? Please Help?!
What you can go for is creating a reuse mechanism that will reuse nodes instead of creating and destroying them. A mechanism well-known from UITableView or UICollectionView.
You would implement a method:
- (SKNode *)dequeueReusableNode;
that gets reused SKNode from some storage, say, NSMutableArray (grabs first object from array, then deletes it from array and returns it). If array is empty, method returns nil.
Then you check if you got a node from the dequeueReusableNode method, if it's nil, you create a new instance of a node. If it's not nil, you configure it with your data.
This goes for every visible node that should be reused.
Nodes that went completely off-screen are sent to reuseQueue – all their property values return to default state, and then node gets added to the end of the NSMutableArray that is the reuseQueue.
In a space shooter, I add enemies through a separate LUA file. These enemies have timers that create shots. When changing scenes, I want to remove all instances of enemies, stop their timers and remove all shots.
I have been able to remove the individual enemies by adding them to the scene's display group, but I can't do that with the timers or the shots.
How do I do this?
While creating a timer, just do as follows:
declare the timer at the top of you scene to get it a global scope on the scene, as:
local timer_1
Then use the timer as:
timer_1 = timer.performWithDelay(1000,myFunction,-1)
Then you can stop it as:
if(timer_1)then
timer.cancel(timer_1)
end
Keep coding.................. :)
What i would do (and that's how i handle this kind of issue in my game actually) is create a table to keep track of the enemies, then make it so enemies are object oriented classes owning both the timers and the shots.
Example:
You could create an 'enemy' class (local myEnemy) which has an internal timer (myEnemy.timerID) and an internal table of shots fired (myEnemy.shots).
Even better, add a 'destroy' method to the enemy (myEnemy.destroy()) that stops the timers and destroys the shot, then when you change scene you just have to iterate through your table, call the destroy method on each enemy, and timers / shots will be destroyed automatically :)
I don't know if your code is object oriented already but in this kind of case it makes things a lot easier :)
Let me know if you need anymore info
Cheers