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..
Related
I have a number of different scenes in Swift. Each scene animates a number of objects briefly. These objects are disparate and all animate in their own unique ways.
The issue is that now I have lines and lines of code for each scene, all of which govern a different SKAction. Is there a way to minify this kind of code, or to restructure the code so that we put it all in one place (and draw from it somewhere else)?
One of my ideas is to make all of the animated nodes a specific class, like AnimatedNode, and then put all the animations in there; as separate functions. This would effectively remove the code from the scene.swift file. Is this the best I can do, or is there some other approach to this that I don't see?
EDIT: My animation code runs 100+ lines across every scene, but as an example of how animations are performed on one such node, this is what it looks like:
// can
let can = bgNode.childNode(withName: "can")
let tip = SKAction.rotate(byAngle: CGFloat(GLKMathDegreesToRadians(10)), duration: 0.5)
let tipSound = SKAction.playSoundFileNamed("pot", waitForCompletion: false)
can?.run(SKAction.sequence([tip, tipSound, tip.reversed()]))
SKActions were meant to be re-used or at least pre-loaded. Your idea is good, because cluttering your scenes with the same code over and over is poor design.
You can make an ActionManager, that has properties for each action you want to run already pre-loaded as a property.. this will increase performance of your game, especially if you are using it more than once.
There are multiple ways to do this, but a plain function (though not as performant as properties) is a good way to at least organize your code.
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.
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 am using Core Data in a multi-threaded way. It's working fine so far and I'm quite happy and have patted myself on the back a few times. Except one small thing.
I have for example a data model Hand. I have another model: Finger.
A Hand as a one-to-many relationship with Finger
in my awakeFromInsert method on Hand, I have:
- (void)awakeFromInsert
{
[super awakeFromInsert];
if(self.fingers.count == 0)
{
// creates instances in current context. sets their hand to this one.
[self addFingersToHand];
}
}
Here's the problem. If I create this hand on the background 'working' context, then save that and its parent contexts, it would appear that a Hand is inserted on the parent context, some fingers are also created, THEN the fingers that were created on the child context are merged, leaving 10 fingers on one hand. O_O
Did this make sense and what have I done incorrectly? I want to make sure that if I create a Hand it will have 5 and only 5 fingers on one hand.
Strange. When you push up a Hand with 5 fingers to the parent context via save:, I am not even sure awakeFromInsert should be called. But even if it is called, self.fingers.count should evaluate to 5, not 0. Did you check with breakpoints what exactly is happening?
Maybe you need to check again where exactly you are inserting stuff.
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