Swift SKAction.waitForDuration Executing Too Fast - swift

this is my first post. I've looked everywhere for an answer and it appears I am doing it right, but it just does't seem to be working.
I'm trying to execute a combat sequence between two nodes in Swift. After each node attacks, it is supposed to wait for its specified attack speed duration before attacking again.
Here is my code for the combat sequence:
func playerMonsterCollision(player: Character, monster: Character) {
player.removeAllActions()
monster.removeAllActions()
let playerFight = player.dealDamage(monster)
let playerWait = SKAction.waitForDuration(player.attackSpeed)
let monsterFight = monster.dealDamage(player)
let monsterWait = SKAction.waitForDuration(monster.attackSpeed)
player.runAction(SKAction.repeatActionForever(SKAction.sequence([playerFight, playerWait])))
monster.runAction(SKAction.repeatActionForever(SKAction.sequence([monsterFight, monsterWait])))
}
And this is the dealDamage function that is called:
func dealDamage(target: Character) -> SKAction {
let action = SKAction.runBlock()
{
if (target.health > 0 && self.health > 0)
{
let damageDelt = self.calcAttack()
target.takeDamage(damageDelt)
print("Damage delt: \(damageDelt), \(target.name!) health: \(target.health).")
}
else
{
if self.name! == "Monster"
{
if !self.isAlive()
{
self.removeFromParent()
}
}
else
{
if !target.isAlive()
{
target.removeFromParent()
}
}
}
}
return action
}
The player.attackSpeed is a double, 3.0, and monster.attackSpeed is also a double, 3.5. As far as I understand, the double would represent a time in seconds, however, when I run my program it seems to be less than half a second between executions.

Found the problem!
I was indeed doing everything correct, but thank you to this answer I figured out that I had changed the speed property in the creation of my objects. Once I fixed it, my code executed as expected. A few other speed related issues popped up, but they will be easy enough to fix now that I know what caused it!
Hopefully this helps others who stumble across a similar issue with things executing too fast (or too slow). Be careful not to unintentionally change the SKSpriteNode.speed property.

Related

Swift compiler struggles with this expression

EDIT
The source of the issue seems to be the use of .lowercased() to return a lower case string. Adding this to any line seems to result in a 40-60ms compile time.
In an effort to speed up my compile times I've added the "-Xfrontend -debug-time-function-bodies" flag detailed here as well as following the optimisation tips here
The compiler seems to struggle with filter functions for example this:
// Filter by search term
if self.searchController.isActive {
filteredManualTasksArray = self.filteredManualTasksArray.filter() {
let taskName:String = $0.bmTaskName!.lowercased()
let searchText:String = searchController.searchBar.text!.lowercased()
return taskName.contains(searchText)
}
}
Result in this warning:
Expression took 51ms to type-check (limit: 50ms)
The variable filteredManualTasksArray is declared elsewhere as:
var filteredManualTasksArray:[BMTask]!
So all variables are explicitly typed as far as I can tell. Is there anything I can do to speed this up?
Edit: I've tried a couple of approaches that seem to make no difference
1) combining the three lines into one:
return $0.bmTaskName!.lowercased().contains(searchController.searchBar.text!.lowercased())
2) Specifying the filter type:
filteredManualTasksArray = self.filteredManualTasksArray.filter { (task: BMTask) -> Bool in
Edit 2
This line:
let searchText:String = searchController.searchBar.text!.lowercased()
Seems to be the cause of the issue - it take 38ms to type check. Any ideas how I can improve this?
You could move the let searchText line out of the filter function:
if self.searchController.isActive {
let searchText:String = searchController.searchBar.text!.lowercased()
filteredManualTasksArray = self.filteredManualTasksArray.filter() {
let taskName:String = $0.bmTaskName!.lowercased()
return taskName.contains(searchText)
}
}

Uneven typing in Spritekit SKAction sequence led typing animation

Hi I know there are plenty of questions on here about the timer, but nothing I can find about this specific issue. Thanks in advance for any help.
I am trying to use a sequence of SKActions to simulate a typing animation (in an SKLabelNode I've called actualLabel) that begins after a user touch.
I have the following:
var charArray = []
var labelText = ""
var calls = 0
And then, in touchesEnded:
if calls < charArray.count + 1 {
let wait = SKAction.wait(forDuration: 1)
let block = SKAction.run({
self.redoLabelText()
})
let sequence = SKAction.sequence([wait,block])
run(SKAction.repeatForever(sequence))
}
With my function as the following:
func redoLabelText() {
if labelText.characters.count < charArray.count {
labelText += charArray[calls]
actualLabel.text = labelText
calls += 1
}
}
And then touchesBegan resets all the initial variables and the process starts again. Everything works fine, except the typing is really choppy. Every time the user presses again, the typing gets faster. It's as if after one press it works fine, then after two etc there are more characters waiting in labelText at each second interval.
Thanks again, got me baffled.

Filter & Map over a Swift Dictionary?

I have two methods doing the same thing, one using the more functional Swift.
func getConstraints1(forState newState: State) -> (on: [NSLayoutConstraint], off: [NSLayoutConstraint]) {
return (
constraints.filter { $0.key.rawValue == newState.rawValue }.map { $1 }.first!,
constraints.filter { $0.key.rawValue != newState.rawValue }.map { $1 }.first!
)
}
The other one using a standard procedural approach.
func getConstraints2(for nextState: State) -> (on: [NSLayoutConstraint], off: [NSLayoutConstraint]) {
var on = [NSLayoutConstraint]()
var off = [NSLayoutConstraint]()
for (state, constraints) in constraints {
if state == nextState {
on += constraints
} else {
off += constraints
}
}
return (on, off)
}
I feel like getConstraints2 is going to be faster than getConstraints1, but I like the syntax in getConstraints1. Is there ever a case fort doing filter/map/reduce operations on a Dictionary? Is this it?
Every time you say filter or map, you are cycling through the entire sequence. So getConstraints1 cycles at least twice (maybe four times, but maybe not, because of laziness considerations), whereas getConstraints2 cycles once.
The question is: do you care? Only you (and Instruments) can answer that one.
Personally, if I were going to deal a deck of cards into two piles (say, all red cards and all black cards), I would work my way through the deck once. Having dealt all the red cards into one pile, I'd feel pretty silly working my way through the deck again looking to see if each remaining card was black.
If your data set is so large that iterating over it twice matters than use function2. Normally, I wouldn't think it matters because it will still run in O(n). If you want a functional approach you can alway modify your filter function to return two arrays in a tuple if you are worried about the second iteration.
It really depends what you are map/filter/reduce'ing over since it will iterate over each item, every time one is called. Sometimes using map/filter/reduce can be more readable than larger for loops.
To make getConstraints2 a bit more functional, you could use a reduce here and it would only iterate over the dictionary once. I did a bit of guessing with the types so hopefully this matches up :)
typealias StatefulConstraints = (on: [NSLayoutConstraint], off: [NSLayoutConstraint])
var constraints = [State: [NSLayoutConstraint]]()
func getConstraints3(for nextSate: State) -> StatefulConstraints {
let initial = (on: [NSLayoutConstraint](), off: [NSLayoutConstraint]())
return constraints.reduce(initial) { (combined, next: (state: State, constraints: [NSLayoutConstraint])) -> StatefulConstraints in
var mutableCombined = combined
if next.state == nextSate {
mutableCombined.on += next.constraints
} else {
mutableCombined.off += next.constraints
}
return mutableCombined
}
}

Weird Memory Behavior in Swift

OK... so I have no idea why this happens but:
Compare the following two lines:
let pointCurve: [AnyObject] = self.curve.map{NSValue(point:$0)}
and
let pointCurve: [NSPoint] = self.curve.map{$0}
In either case, the variable is local and not used at all after assignment. The line resides in a method that is called repeatedly and very quickly. The first case results in terrible and ever faster growing of memory usage. But when I change it to the second, the memory stats are flat as a disc.
You may say, "oh, you're not doing anything in the second line". So I tried the following:
var pointCurve: [AnyObject] = []
for c in self.curve {
pointCurve.append(NSValue(point:NSPoint(x:1, y:1))
}
vs
var pointCurve: [NSPoint] = []
for c in self.curve {
pointCurve.append(NSPoint(x: 1, y: 1))
}
Now I see the exact same results. The culprit seems to be NSValue. I checked with Instruments that a whole bunch of NSConcreteValues are allocated, and I read online these are related to NSValue. But I didn't find anything about them causing memory leaks.
The question is what can I do about this. I'm supposed to send an array of points to some ObjC code, and until I figure out how to fix this, I can't do it without huge performance issues.
Try:
func pointCurvy() {
autoreleasepool {
let pointCurve: [AnyObject] = self.curve.map{NSValue(point:$0)}
// Do something with pointCurve.
}
}

is the init method not working properly in swift

With the code below, the local songs variable is never able to be iterated despite all the checks to the contrary ( println shows the value stored ). The other thing is that the Xcode debugger seems to jump all over the place in the init method.
let gLibraryManager = LibraryManager()
class LibraryManager {
var Songs = Dictionary<String, String>()
init() {
println("struct being initialized from NSDefaults")
let userDefaults = NSUserDefaults.standardUserDefaults();
var result:AnyObject = userDefaults.objectForKey(LIKED_LIST)
println(result)
var local = result as? Dictionary<String,String>
if local != nil {
println("local not nil: \(local!)")
for (id,title) in local! {
Songs[id] = title
}
if Songs.count > 0 {
println("NSDefaults detected: \(Songs)")
} else {
println("no NSDefaults detected. Initializing empty")
}
}
}
ok. i figured out what is was.
I had set the Swift Compiler - Code Generation. Optimization level to -Fastest. This was to prevent the extremely slow creation of Dictionaries.
However, it appears this breaks the ability to iterate structures.
It also seems to resolve the weird bouncing around of breakpoints.
This was a needle in a haystack that tooks many hours. I guess the moral of the story is not to mess with compiler flags yet.