As3 strange If statement evaluation behaviour - actionscript-3

I am writing a small game for a bit of fun. It's a simple turn based battle game kind of like Pokemon style battles but with stupid/joke characters.
I have some stuff on the main timeline for user interface but everything else is handled in external actionscript files. I have a class for a battle which has some battle related methods like attack etc and I also have characters as their own classes which inherit from an interface.
In my user interface there are some buttons and when a battle commences I have an event listener on my attack button which executes the following code each time:
public function attack(attacker:Character, defender:Character):void
{
var defenderHp:int;
var attackPower:int;
var postAttackHp:int;
defenderHp = defender.getHP();
attackPower = attacker.getAttack();
if (! passiveBlock(defender))
{
if (! criticalStrike(attacker))
{
trace("defender hp trace: " + (defenderHp - attackPower));
postAttackHp = (defenderHp - attackPower);
}
else
{
trace("defender hp trace: " + Math.floor((defenderHp - (attackPower*1.5))));
postAttackHp = Math.floor((defenderHp - (attackPower*1.5)));
displayText = attacker.getName() + " landed a critical strike!";
}
if (! postAttackHp > 0)
{
gameIsOver(attacker, defender);
}
else
{
defender.setHP(postAttackHp);
}
}
else
{
displayText = defender.getName() + " blocked the attack!";
}
}
The code gets called by the button fine every time, the problem lies in the if (! postAttackHp > 0) condition. For some reason only occasionally does the game over method get called when the defender's HP goes below 0. I am tracing the postAttackHp variable out each time and I can see every time that it is below 0 but the if statement more often than not skips down to the else section.
What is strange is that sometimes it works properly and sometimes it does not but it is more frequently not working.
Is there something fundamentally stupid about the way this is set up?
Thanks in advance for your help :)

I don't have Flash installed on this machine, or else I would try to see if this is the issue, but my first guess would be that
! postAttackHp > 0
is evaluating as (! postAttackHp) > 0. In this case, it would only be true if postAttackHp were == 0. Anything else, even a negative number, would evaluate to False, since ! -10 = False. False > 0 is False, since typecasting False would leave it as 0.
Try either,
if (! (postAttackHp > 0))
or
if (postAttackHp <= 0)

Related

How to wait, then do something, in the GameScene

SKAction has waiting for duration abilities, for a period of time on a node. And seems to perform actions on nodes. Like moveTo, etc.
If I don't want that, rather I'd prefer to call functions within GameScene after a period of time, how do I do that with SpriteKit in the GameScene, not on a Sprite or other Node?
Are SKActions the way to do this? The only way to do this?
Yes. This question IS that ridiculously simple. I lack the heuristics and terminology to find an answer. Just keep looping around on how SKAction waits are calls on SKSprites for things like scale, rotation, etc, after time. Which isn't want I want/need.
Update:
Desired outcome, inside GameScene
doSetupStuff() // does some stuff...
waitForAWhile() // somehow wait, perhaps do somethings in here, while waiting
doSomethingElse() // does this after the waitForAWhile has waited
UPDATE 2:
What I think happens, again, inside didMove(to view...)
func wait(){
let timeToPause = SKAction.wait(forDuration: 3)
run(timeToPause)
}
let wontwait = SKAction.wait(forDuration: 3)
run(wontwait)
thisFunction(willnot: WAIT"it starts immediately")
wait()
thisFunction(forcedToWait: "for wait()'s nested action to complete")
UPDATE 3:
Found a way to get the delay without using SKActions. It's a little crude and brutal, but makes more sense to me than SKActions, so far:
DispatchQueue.main.asyncAfter(deadline: .now() + 10.0) {
print("I waited ten seconds before printing this!")
}
An option, as you cited, is to manage this externally. The way I typically manage this sort of thing is to have an externally run update cycle. One that
To drive this updater, you could use either CADisplayLink (which is what I use right now with my OpenGL renderer) or a dispatch source timer (which I have used with my SpriteKit engine). When you use an updated, you want to calculate the delta time. The tick handler could look something like:
func tickHandler() {
let currTime = NSDate().timeIntervalSince1970
let dt = lastTime - currTime // lastTime is a data member of the class
// Call all updaters here, pretend "updater" is a known updater class
updater.update(dt)
}
And updater's update method would look something like:
func update(deltaTime:NSTimeInterval) {
// Do your magic
}
I typically have a main overall updater running independent of what people are calling scenes. Example usage would be something like having an attract mode like in old school arcade games. There they show title screen, sample game play, high scores, rinse and repeat. Scenes would be title, game play, high score. Here you can your main updater manage the time and coordinate the construction/destruction/switching of the scenes. Note this implies having an overall scene manager (which is actually quite handy to have).
For your case, you could use this updater to drive the GameScene updater. It's updater could look something like:
func update(deltaTime:NSTimeInterval) {
switch state {
case .SetupState:
// noop?
println("I'm in setup") // Shown just so you can see there is a setup state
case .WaitState:
waitTime += deltaTime
if waitTime >= kWaitTime {
// Do whats you gots to do
doSomethingElse()
state = .NextState
}
case .NextState:
// blah blah blah blah
}
}
So the flow to do this call path from your driver (CADisplayLink or dispatch source) would be something like:
tickHandler -> master updater -> game scene updater
Some will def find this is perhaps a little heavy handed. I, on the other hand, find this very helpful. While there is obviously some time management and the loss of being able to fire and forget, it can help provide more control for orchestrating pieces, as well as arbitrarily changing state without having to worry about killing already queued actions. There is also nothing that says you still cannot mix SKAction. When I did use SpriteKit, I did all my updating this way along with some dispatched items. I only used SKAction to update hierarchy. Keep in mind that I used my own animation and physics system. So at least for me I had a lot less dependency on SpriteKit (it effectively was just a renderer for me).
Note you have to have your own means to handle pause and coming to foreground where your timer will need to be resynced (you only need to worry about tickHandler). Breakpoints also will cause time jumps.
You can use below function
#define ANIM_TIME 2
SKAction *customACtion = [SKAction customActionWithDuration: ANIM_TIME actionBlock:^(SKNode *node, CGFloat elapsedTime) {
// Do Something Here
}];
Another way to make something happen after a certain period of time is to make use of the 'current time' parm passed to update(). The following code will spawn a boss at intervals ranging from 20 to 30 seconds.
In your property definitions:
var timeOfLastBoss: CFTimeInterval = -1 //Indicate no boss yet
var timePerBoss = CFTimeInterval()
.
.
.
didMoveToView() {
...
timePerBoss = CFTimeInterval(Int.random(20...30))
'''
}
.
.
.
func update(currentTime: CFTimeInterval) {
...
spawnBossForUpdate(currentTime)
...
}
'
'
'
func spawnBossForUpdate(currentTime : CFTimeInterval) {
if ( timeOfLastBoss == -1 ) {timeOfLastBoss = currentTime}
if (currentTime - timeOfLastBoss < timePerBoss) {return}
// Rest of 'spawnBoss code
self.timePerBoss = CFTimeInterval(Int.random(20...30))
self.timeOfLastBoss = currentTime
}
One way, using SKActions, in Swift 3.0, looks like this:
DEFINE: aPatientlyWaitingFunction() at the top level of
GameScene class.
To cause a delay to happen before calling the above function, inside
didMove(to view...)
three ways I've found to do this using Actions:
All three ways seem to accomplish the exact same thing:
let timeToWait: TimeInterval = 3 // is seconds in SKAction thinking time
let waitSomeTime = SKAction.wait(forDuration: timeToWait)
// 1st way __________________________________________
// with a completion handler, the function can be called after Action
run(waitSomeTime) {self.aPatientlyWaitingFunction()}
// 2nd way __________________________________________
// as a completion to be done after action, in the run invocation:
run(waitSomeTime, completion: aPatientlyWaitingFunction)
// 3rd way __________________________________________
// alternatively, as part of a sequence of actions...
// Create a sequence, by making a run action from waitSomeTime and...
let thenDoThis = SKAction.run(aPatientlyWaitingFunction)
// then activate sequence, which does one action, then the next
run(SKAction.sequence([waitSomeTime, thenDoThis]))
// OR... for something different ____________________
////////////////////////////////////////////////////////
DispatchQueue.main.asyncAfter(deadline: .now() + timeToWait) {
self.aPatientlyWaitingFunction()
print("DispatchQueue waited for 3 seconds")
}

[cc creator]Comparison not working

I have an array of Nodes 'flags', and I want to set my object's position at the first object in that array, it works and the object actually gets positioned as intended, but when I make the comparison it fails and logs 'NO'.
The line of code that sets the position works, but the comparison fails, what's wrong here?!
start: function () {
this.node.position = this.flags[0].position;
this.movement();
},
movement: function() {
if (this.node.position == this.flags[0].position) { // Problem
console.log("YES");
}
else {
console.log("No");
Update:
When I do it like this it works:
if (this.node.position.x == this.flags[0].position.x) // or position.y
Well if you write javascript here (and it looks like you do) there're two things you should know:
You can't compare objects with == out of the box
({"a":1} == {"a":1})
Will return false (you may try it yourself in your browser.
As a workaround you could do something like:
function posCompare(p1, p2){
return p1.x === p2.x && p1.y === p2.y;
}
Then use it instead of == for positions
See how I use === instead of ==? Second thing to know is Use only ===. You can learn the difference Which equals operator (== vs ===) should be used in JavaScript comparisons? but I'd keep away from == anywhere. It's slower, it may cause strange errors here and there - just don't use it at all

AS3 Boolean seemingly not working

Ok, so this is obviously going to be something that I stupidly overlooked in my code, but I am having problems with a boolean check in as3. In the below if statement I set a boolean, I can confirm that the boolean is set in this if switch as I have run a trace to check that:
if(switchA && switchB){
if(Side == "LEFT"){
localAttachCoords.x = (-Parent.collision.SideLength - entity.collision.SideLength)/2
localAttachCoords.y = Parent.collision.SideLength/2 - (((TargNode-1)*8) + entity.collision.SideLength/2)
}
if(Side == "RIGHT"){
localAttachCoords.x = (Parent.collision.SideLength + entity.collision.SideLength)/2
localAttachCoords.y = -(Parent.collision.SideLength/2 - (((TargNode-1)*8) + entity.collision.SideLength/2))
}
if(Side == "UP"){
localAttachCoords.y = (Parent.collision.SideLength + entity.collision.SideLength)/2
localAttachCoords.x = -(Parent.collision.SideLength/2 - (((TargNode-1)*8) + entity.collision.SideLength/2))
}
if(Side == "DOWN"){
localAttachCoords.y = (-Parent.collision.SideLength - entity.collision.SideLength)/2
localAttachCoords.x = Parent.collision.SideLength/2 - (((TargNode-1)*8) + entity.collision.SideLength/2)
}
entity.attached = true
entity.Parent = Parent
}
This would all be well and good, but for the fact that in a function from another class, executed every frame, claims that the boolean was set to false, I confirmed this with another trace function.
This is the function, taken from the class whose instance is referred to as entity in the above switch:
public function update(){
if (physics) physics.update()
if (node && physics){
trace(attached)
if(attached){
physics.nodeUpdate()
}
}
}
This function claims in the trace that attached == false despite it being set true earlier with no other reference to the attached variable. Any help would be appreciated!
Pathing
There are some un-addressed variables in your issue, foremost being the pathing you're taking to check your variable. This is relevant because of namespaces/scope affect what each piece of code has access to.
If your functions and variables shared the same space (i.e., global/document/timeline), then any reference the the same named variable will always return the same value, unless (as LoremIpsum noted) it's being shadowed by a local variable by the same name.
Obviously, this is not the case since you're using public function which is a class-only declaration. If the boolean you're looking for is on the timeline, and the class wants to read that variable, you need to have a valid path to it. Instantiated classes that are DisplayObjects and have been added to the DisplayList have both parent and stage properties which you can use to access the timeline global namespace (thereby providing access to your boolean).
However, if the class is not a DisplayObject (e.g., it does not extend a Sprite, Shape, or MovieClip), then access to the timeline has to be provided manually, either by setting a property on the class, or passing an argument to a method on the class.
Further complicating the matter is if the Boolean exists in another class object (either instantiated or static), you'd then need a way to get between them. A case of A sees B, C sees B, but neither A or C see eachother.
Values
A boolean is always going to be false, even if the assigned value was null, so if your class is trying to reference a variable that it can't see, that value will always be false. For example...
var foo:Boolean = this["fiddlesticks"];
trace("foo = " + foo); // traces: "foo = false"
There is no property this.fiddlesticks, so while the resolved value is null, foo becomes false. Consider using hasOwnProperty(), which indicates whether an object has a specified property defined, and is a method available to all objects.
Switch
You don't have to manually create your own switch using if then else if, AS3 has its own switch statement.
switch (Side) {
case "LEFT":
// Do stuff for left
break;
case "RIGHT":
// Do stuff for right
break;
case "UP":
// Throw your hands up
break;
case "DOWN":
// Get down and boogie!
break;
}
I hope that all helps. I'd like to say exactly what's going on with the access to your Boolean, but there simply isn't enough information to say.
Cheers!

How to suppress the warning "Assignment within conditional. Did you mean == instead of =?"

With the new ASC 2.0 compiler I get warnings when I code like below:
// (_achievementsFromServer is an Array)
while(item=_achievementsFromServer.pop())
{
// do something with item here
}
The warning reads: "Assignment within conditional. Did you mean == instead of =?"
While in general I appreciate all warnings from the compiler, I'd like to suppress this one in this case because I did not mean == here. I want to pop all items in the array and do something with it until the array is empty.
while( (item=_achievementsFromServer.pop())==true )
seems to work but looks a bit confusing. Any other ideas?
This may seem better.
while(_achievementsFromServer.length > 0) {
var item:Object = _achievementsFromServer.pop();
}
Just like removeChild
var d:DisplayObjectContainer;
while(d.numChildren > 0) {
d.removeChildAt(0);
}
While I was hoping for some other way, I think #AmyBlankenship improved my own suggestion:
while((item=_achievementsFromServer.pop())!=null)
{
//....
}
It's clear and understandable what's going on, and doesn't rely on checking the length of the Array on every iteration.
Googling some more I found a compiler option -compiler.warn-assignment-within-conditional that could be set to false but then you won't be warned anywhere in your project anymore. And I'm not so confident that I never accidently type = instead of ==, so that's not a good solution I think.

How to recognize that short code blocks can be refactored into something cleaner?

i have a bit of code that i wrote a few weeks ago (the code's purpose isn't so much important as its structure):
if (_image.Empty)
{
//Use the true image size if they haven't specified a custom size
if (_glyphSize.Width > 0)
imageSize.Width = _glyphSize.Width //override
else
imageSize.Width = _image.GetWidth;
if (_glyphSize.Height > 0) then
imageSize.Height = _glyphSize.Height
else
imageSize.Height = _image.GetHeight
}
else
{
//No image, but they can still override it with a custom size
if (_glyphSize.Width > 0) then
imageSize.Width = _glyphSize.Width
else
imageSize.Width = 0;
if (_glyphSize.Height > 0)
imageSize.Height = _glyphSize.Height
else
imageSize.Height := 0;
}
i was going over it tonight, and as i was cleaning it up, i realized that the cleaned version is must more concise:
//Figure out the final image width
if (_glyphSize.Width > 0)
imageSize.Width = _glyphSize.Width
else if (not _glyph.Empty)
imageSize.Width = _glyph.GetWidth
else
imageSize.Width = 0;
//Figure out the final image height
if (_glyphSize.Height > 0)
imageSize.Height = _glyphSize.Height
else if (not _glyph.Empty)
imageSize.Height = _glyph.GetHeight
else
imageSize.Height = 0;
Note: i've trimmed down the code to bare logical flow, and obfsucated the source language.
In the end i took the nested if's, and inverted them. Doing that allowed this shortening. My question is: how can i recognize this in the future?
What are the tell-tale signs that i've just written some code that can be refactored into something shorter?
Another example i had from a few weeks ago was something akin to a permission check: the user can perform an action:
if they have the permission they can do it
if they don't have the permission, but the override is in effect
Which i initially coded as:
if ((HasPermission || (!HasPermission and OverrideEnabled))
{
...do stuff
}
The logical conditions on that if clause seemed kind of wordy. i tried to reach back to my boolean algebra course to figure out how to simplify it. In the end i could do it, so i ended up drawing a truth table:
Permission Override Result
0 0 0
0 1 1
1 0 1
1 1 1
Which when i look at it is an OR operation. So my if statement became:
if (HasPermission or OverrideEnabled)
{
...
}
Which is obvious and simple. And so now i'm wondering how i couldn't see that to begin with.
Which brings me back to my SO question: What tell-tale signs could/should i be looking for in order to recognize that some block of code needs some TLC?
Here are some guidelines from Code Complete, off the top of my head. That is a good book to get for this sort of thing.
Nested if-else and repeated statements in blocks
Long for-loops
Repeated lines/statements or frequently used operations can be placed in a function
If for some reasons you are copying and pasting a line of code over and over again
I found discrete maths to have an influence in how I wrote if statements now. Usually, I see I am writing two same IF statements in 2 blocks, then I would do some mental 'factoring'.
Specifically related to boolean evaluation, it's worth noting that most(?) modern languages implement lazy evaluation.
That is, if "a" is true, then if(a) and if(a or b) are logically and functionally equivelant; the interpreter stops evaluating when it sees or after a true variable. This isn't very important when a and b are variables, but if they're callables [e.g. if(a() or b())], b() will not get evaluated when a is true.
You can save a lot of keystrokes (and processor time) by learning this well:
if(!userExists()):
if(!createUser()):
errorHandling()
else:
doStuff()
else: doStuff()
becomes
if(userExists() or createUser()): doStuff()
else: errorHandling()
Well done. Now, when I see this:
//Figure out the final image width
if (_glyphSize.Width > 0)
...
//Figure out the final image height
if (_glyphSize.Height > 0)
...
I think there is still more refactoring to do. Extracting code into methods isn't just a great way to eliminate redundant code. It's also a great way to make the code self documenting:
I'd be inclined to reduce the code to:
set_final_image_size
With set_final_image_size and its minions defined like so:
def set_final_image_size:
imageSize.Width = final_image_width;
imageSize.Height = final_image_height;
def final_image_width:
if (_glyphSize.Width > 0)
return _glyphSize.Width;
else if (not _glyph.Empty)
return _glyph.GetWidth;
else
return 0;
def final_image_height:
if (_glyphSize.Height > 0)
return _glyphSize.Height;
else if (not _glyph.Empty)
return _glyph.GetHeight;
else
return 0;
Now that you've separated the width and height logic, and noticed that it's identical - what if you were to add, say, getDimension(Direction direction) and setDimension(Direction direction, int length) to your classes? Now you've got
if (_glyphSize.getDimension(direction) > 0)
imageSize.setDimension(direction, _glyphSize.getDimension(direction))
else if (not _glyph.Empty)
imageSize.setDimension(direction, _glyph.getDimension(direction))
else
imageSize.setDimension(direction, 0);
Extracting the local brings us:
length = _glyphSize.getDimension(direction);
if (length > 0)
imageSize.setDimension(direction, length)
else if (not _glyph.Empty)
imageSize.setDimension(direction, _glyph.getDimension(direction))
else
imageSize.setDimension(direction, 0);
taking it a little further:
length = _glyphSize.getDimension(direction);
if (length == 0 && !_glyph.Empty)
length = _glyph.getDimension(direction);
imageSize.setDimension(direction, length);
Which, to my eyes at least, is starting to look pretty nice.