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!
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.
I have some experience in SKSpriteKit and I am writing code in UIViewController using UIKit library. And I wonder if I could access existing propteries such as ones from UILabel, UITextField, UIView, and so on. In Swift, nodes can be named and called by their names using childWithName(name: String), so is there any way to do this in UIKit. ? I thought doing this would be much more convenienet and my writing would go smooth. I started programming in UIKit so I do not know much about it, so I appreciate if you teach me abou this!
Thankyou
You can't give "names" to UIViews as far as I'm concerned. However, there's something similar.
You can set a view's tag by doing:
someView.tag = 1
Then, assuming that superView is the super view of someView, you can do this to get someView:
superView.viewWithTag(1)
It's not as descriptive as name, but you can use named constants to make it clearer:
let scoreLabelTag = 1
superView.viewWithTag(scoreLabelTag)
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..
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.
I am very new to iOS programming, Objective-C, and programming in general, so please excuse me if you find this question frustratingly simple-minded.
The docs on Apple's website are usually great, but I'm having some trouble trying to wrap my head around certain parts of Core Animation. I want to explicitly animate the position of a CALayer. From what I understand, I need to create a CABasicAnimation object, configure it with fromValue, toValue, etc., then add it to a layer using this method:
- (void)addAnimation:(CAAnimation *)anim forKey:(NSString *)key
My problem is that I have no idea what the significance of the forKey: parameter is. From what I've seen in examples online, it's not required? I suppose it has something to do with key-value coding? (I still don't really understand that, either.) Even if it's not required, I'd like to know what it is so that I can take advantage of its usefulness in my app.
Thanks for any help you can offer.
It allows you to override animations. For example, implicit animations created by mutating an implicitly animateable property (such as opacity) will use the name of the property as a key. This way if you modify it again (to produce a new animation), the new animation will replace the old one instead of trying to have both animations running simultaneously.
CALayer has several methods for getting the animations that have been added to the layer. If you want to get, replace, or remove a particular animation from CALayer you have to give it the key when you call animationForKey: or removeAnimationForKey:.
You don't have to provide a key, you can use nil for the key if you don't have any particular need to find a particular animation by key.
It's just some identifier for your animation. You can call animationForKey: and removeAnimationForKey: methods later with the specified key.
Also because layer may have only one animation per unique key, you can use this value as identifier for some type of animations and all ...ForKey: methods will return/remove/replace most current animation for a given animation type/key.