Organising animations in Swift - ios

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.

Related

Understanding UIView Animation In Swift

I know how to animate UIViews using the animate() function. What I'm trying to understand is why the animation takes place on the class in general, as opposed to a specific instance. I don't know the right words to describe this so I couldn't find any resources on this.
So for example, if I wanted to use SpriteKit and I wanted to move a node, I'd use node.run(SKAction.move(to: CGPoint.zero, 0.5). This makes a lot of sense to me. It defines an SKAction (so it could be used with other nodes if needed), and then applies it to a specific node.
If I wanted to do the same with a view, I'd do something like:
exampleViewConstraint.constant = 0
UIView.animate(withDuration: 0.5) { [weak self] in
self?.view.layoutIfNeeded()
}
Aside from this being much more complicated verbiage, I don't understand why this is being called on the class in general. I'm having a hard time conceptualizing. What exactly is happening here?
When you call a function on a general class, what does that do? Are there other examples where that's used? Why do you need to use a class function here?
I get that the closure captures the parent class's view, but what if there was another view elsewhere in the same function? How could I specify that it animates view 1 but not view 2?
Why must this be done in such a confusing way?
Thanks in advance for your help!

Complex enemy behaviors and patterns

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..

Array of UITextView's that interact with objects of the other classes

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.

how to detect interface changes on iOS application

Is there any possible way to detect every change on User Interface during runtime??
I'm trying to find all objects in the current app interface.
I'm trying to to get all nodes inspecting recursively the main Window, but, for example, how to know if the top viewcontroller changes or if it's added a uiview dynamically, or is presented a modalview??
The main objective is to have a library to do this..
Any idea, help?
Thanks!
You could write your own library based on this, using advanced Objective-C techniques. I do not recommend you to do this, since it mostly breaks MVC patterns on iOS. Depends on what do you want to use it for, maybe analytics?
So these are the options I believe, if you want to actively inspect UIView hierarchy. All options are pretty complicated though.
Swizzle methods such as addSubview and removeFromSuperview of UIView, so you could know when changes like that happens. Including the getters of frame and bounds, if you wish to know the position.
You could use KVO to watch properties such as: subviews, frame, bounds, superview to notice any changes. But at one point you would have to add the same object as the observer (could be singleton).
Decide for an interval that is fired by a NSTimer and go through the hierarchy recursively beginning at keyWindow on UIApplication. This would have a big performance impact though.
There may be other options, but these are the ones I believe to be the best choices.

Dealing with hierarchy-breaking effects in iOS games and apps

I started working as a iOS developer about a year and a half ago, and I'm having some trouble with software architecture and organization. I use Apple's recommended Model-View-Controller paradigm, and my code is generally very hierarchical: if a screen has (for example) a HUD, a control panel, and a display area, I have a main controller for the screen and sub-controllers for the HUD, control panel, and display area. The sub-controllers generally have no knowledge of their neighboring controllers and use methods in the main controller to interact with them.
However, especially in games, I often run into hierarchy-breaking problems that just can't be elegantly solved with this model. For instance, let's say I have a coin in the control panel area that I want to animate flying to the HUD. I can either animate the original coin to the new position, which would require a method like animateCoinToPosition: in the control panel sub-controller and a method like getPositionForFinalCoinPositionInHUD in the main controller; or, I can hide the original coin and create a duplicate coin either in the main controller or the HUD controller, which would require a delegate method like animateCoinToHUDFromStartingPosition:. I don't like having such oddly-specific methods in my controllers, since they only really exist to solve one problem, and additionally expose the hierarchy. My ideal solution would be to have a single method called animateCoinToHUD, but this would require flattening the entire hierarchy and merging the three controllers into one, which is obviously not worth it. (Or giving the sub-controllers access to their siblings — but that would essentially have the same effect. The sub-controllers would then have dependencies with each other, creating a single messy spiderweb controller instead of a main controller and three mostly independent sub-controllers.)
And it often gets worse. What if I want to display a full-screen animation or particle effect when moving the coin? What if my coin is a lot more complicated than a simple sprite, with many subviews and details, to the point where creating a duplicate coin using animateCoinToHUDFromStartingPosition: is inefficient? What if the coin flies to the HUD but then returns to the control panel? Do I "lend" the coin view to the main controller and then take it back when the animation completes, preserving the original position/z-order/etc. in temporary variables so that they can be restored? And another thing: logically, code that concerns multiple sub-controllers belongs in the main controller, but if these interactions are common, the main controller grows to be many thousands of lines long — which I've seen happen in many projects, not just my own.
Is there a consistent way to handle these hierarchy-breaking effects and actions that don't require duplicate code or assets, don't bloat my controllers, and elegantly allow me to share objects between sub-controllers? Or am I using the wrong approach entirely?
So, I think you may be thinking about the "never go up" the hierarchy a little too literally.
I think the idea is that you don't know specifically what the parent is, but you can define a protocol and know that whatever your parent object is it responds to said protocol. You ideally test in code to confirm that it responds to that protocol. Then use the protocol to send the message in a generic way wherein you pass the coin object to the parent object and let the parent object animate it off the screen and into the HUD.
The sub-controllers then have a id<parent_protocol> parent; instance variable and their initialization method takes one of those as a parameter. Given your description you already have something like this in place, or at least enough to implement "sub-controllers generally have no knowledge of their neighboring controllers and use methods in the main controller to interact with them" as you say.
So the idea, from a design perspective is that the coin pickup happens in the Display panel and all it knows is that it's parent object has a pickupCoin: method that will do whatever is appropriate with a picked up coin. The Display panel doesn't know it goes to the HUD, or whatever, just that picked up coins get handled by the parent controller's pickupCoin: method.
The OOP design philosophy here is that all knowledge of the parent is encapsulated in the protocol definition. This makes the child & parent more loosely coupled so that you could swap in any parent that implemented that protocol and the children would still work fine.
There are looser couplings you could use (globally posted notifications say), but in the cases you describe I think something like what I've outlined is probably more appropriate & likely more performant.
does that help?

Resources