Updating amount of "lifes" that the player has - actionscript

I'm making this small flash game where a user has to fly and try to dodge stuff... when the user hits an object it has to remove one of his lives that is shown by a feather.
Everything of the game works perfectly however the feathers don't want to update on the frame (they keep showing 3 which is the starting amount of lives).
This function adds the feathers (illustrating the lives of the player).
var levens = 3;
stage.addEventListener(Event.ENTER_FRAME, leeft);
function leeft(evt:Event):void {
for(var i = 0; i < levens; i++)
{
var v:MovieClip = new feather_mc();
addChild(v);
v.x = 50 + i*12;
v.y = 382;
}
}
Following function is a hittest object function that updates the variable "levens"... as soon as the user hits an object
function raak(evt:Event):void {
if(eagle_mc.hitTestPoint(evt.target.x,evt.target.y, true)==true)
{
removeChild(MovieClip(evt.target));
evt.target.removeEventListener(Event.ENTER_FRAME,raak);
levens--;
if(levens==0)
{
gotoAndStop(41);
}
}
}

You are constantly adding new feathers since the "leeft" function is called on each frame. The result is that the feathers are stacked on top of each other, so if you remove one, the other at the same location appears. I suppose you'll want to execute this method once during initialization.

Related

Very slow hover interactions in OpenLayers 3 with any browser except Chrome

I have two styles of interactions, one highlights the feature, the second places a tooltop with the feature name. Commenting both out, they're very fast, leave either in, the map application slows in IE and Firefox (but not Chrome).
map.addInteraction(new ol.interaction.Select({
condition: ol.events.condition.pointerMove,
layers: [stationLayer],
style: null // this is actually a style function but even as null it slows
}));
$(map.getViewport()).on('mousemove', function(evt) {
if(!dragging) {
var pixel = map.getEventPixel(evt.originalEvent);
var feature = null;
// this block directly below is the offending function, comment it out and it works fine
map.forEachFeatureAtPixel(pixel, function(f, l) {
if(f.get("type") === "station") {
feature = f;
}
});
// commenting out just below (getting the feature but doing nothing with it, still slow
if(feature) {
target.css("cursor", "pointer");
$("#FeatureTooltip").html(feature.get("name"))
.css({
top: pixel[1]-10,
left: pixel[0]+15
}).show();
} else {
target.css("cursor", "");
$("#FeatureTooltip").hide();
}
}
});
I mean this seems like an issue with OpenLayers-3 but I just wanted to be sure I wasn't overlooking something else here.
Oh yeah, there's roughly 600+ points. Which is a lot, but not unreasonably so I would think. Zooming-in to limit the features in view definitely helps. So I guess this is a # of features issue.
This is a known bug and needs more investigation. You can track progress here: https://github.com/openlayers/ol3/issues/4232.
However, there is one thing you can do to make things faster: return a truthy value from map.forEachFeatureAtPixel to stop checking for features once one was found:
var feature = map.forEachFeatureAtPixel(pixel, function(f) {
if (f.get('type') == 'station') {
return feature;
}
});
i had same issue, solved a problem by setInterval, about this later
1) every mouse move to 1 pixel fires event, and you will have a quee of event till you stop moving, and the quee will run in calback function, and freezes
2) if you have an objects with difficult styles, all element shown in canvas will take time to calculate for if they hit the cursor
resolve:
1. use setInterval
2. check for pixels moved size from preview, if less than N, return
3. for layers where multiple styles, try to simplify them by dividing into multiple ones, and let only one layer by interactive for cursor move
function mouseMove(evt) {
clearTimeout(mm.sheduled);
function squareDist(coord1, coord2) {
var dx = coord1[0] - coord2[0];
var dy = coord1[1] - coord2[1];
return dx * dx + dy * dy;
}
if (mm.isActive === false) {
map.unByKey(mm.listener);
return;
}
//shedules FIFO, last pixel processed after 200msec last process
const elapsed = (performance.now() - mm.finishTime);
const pixel = evt.pixel;
const distance = squareDist(mm.lastP, pixel);
if (distance > 0) {
mm.lastP = pixel;
mm.finishTime = performance.now();
mm.sheduled = setTimeout(function () {
mouseMove(evt);
}, MIN_ELAPSE_MSEC);
return;
} else if (elapsed < MIN_ELAPSE_MSEC || mm.working === true) {
// console.log(`distance = ${distance} and elapsed = ${elapsed} mesc , it never should happen`);
mm.sheduled = setTimeout(function () {
mouseMove(evt);
}, MIN_ELAPSE_MSEC);
return;
}
//while multithreading is not working on browsers, this flag is unusable
mm.working = true;
let t = performance.now();
//region drag map
const vStyle = map.getViewport().style;
vStyle.cursor = 'default';
if (evt.dragging) {
vStyle.cursor = 'grabbing';
}//endregion
else {
//todo replace calback with cursor=wait,cursor=busy
UtGeo.doInCallback(function () {
checkPixel(pixel);
});
}
mm.finishTime = performance.now();
mm.working = false;
console.log('mm finished', performance.now() - t);
}
In addition to #ahocevar's answer, a possible optimization for you is to utilize the select interaction's select event.
It appears that both the select interaction and your mousemove listener are both checking for hits on the same layers, doing double work. The select interaction will trigger select events whenever the set of selected features changes. You could listen to it, and show the popup whenever some feature is selected and hide it when not.
This should reduce the work by half, assuming that forEachFeatureAtPixel is what's hogging the system.

Action not working correctly in SpriteKit

I'm new to iOS programing and I'm experimenting to learn trying to create a game in swift using Sprite Kit.
What I'm trying to achieve is having a constant flow of blocks being created and moving rightwards on the screen.
I start by creating a set which contains all the initial blocks, then an action "constant movement" is added to each one, which makes them move slowly to the right. What I'm having trouble is adding new blocks to the screen.
The last column of blocks has an "isLast" boolean set to true, when it passes a certain threshold it is supposed to switch to false and add a new column of blocks to the set which now have "isLast" set to true.
Each block in the set has the "constantMovement" action added which makes them move slowly to the right, the new blocks have it added as well, but they don't work as the original ones.
Not all of the move, even tho if I print "hasActions()" it says they do, and the ones that do move stop doing so when they get to the middle of the screen. I have no idea why this happens, can somebody experienced give me a hint please?
This is the update function:
override func update(currentTime: CFTimeInterval) {
/* Called before each frame is rendered */
let constantMovement = SKAction.moveByX(-1, y: 0, duration: 10);
background.runAction(SKAction.repeatActionForever(constantMovement));
let removeBlock = SKAction.removeFromParent();
let frame = self.frame;
var currentBlockSprite:SKSpriteNode;
var newBlock: Block;
for block in blocks {
currentBlockSprite = block.sprite!;
currentBlockSprite.runAction(constantMovement);
if(block.column == NumColumns - 1) {
block.isLast = true;
}
if(block.isNew) {
println("position \(currentBlockSprite.position.x) has actions \(currentBlockSprite.hasActions())");
}
if(block.isLast && currentBlockSprite.position.x < frame.maxX - 50) {
println("the block that hits is " + block.description);
println("HITS AT \(currentBlockSprite.position.x)");
block.isLast = false;
for row in 0..<NumRows {
newBlock = Block(column: NumColumns - 1, row: row, blockType: BlockType.random(), isLast: true, isNew: true);
blocks.addElement(newBlock);
addBlockSprite(newBlock);
println("new block: " + newBlock.description + "position \(newBlock.sprite?.position.x)");
}
}
if(currentBlockSprite.position.x < frame.minX) {
currentBlockSprite.runAction(removeBlock);
blocks.removeElement(block);
}
}
}
My whole project is in here: https://github.com/thanniaB/JumpingGame/tree/master/Experimenting
but keep in mind that since I'm new to this it might be full of cringeworthy bad practices.
I would remove any SKAction code from the update function as that's kind of a bad idea. Instead I would just apply the SKAction when you add your block sprite to the scene, like this.
func addBlockSprite(block: Block) {
let blockSprite = SKSpriteNode(imageNamed: "block");
blockSprite.position = pointForColumn(block.column, row:block.row);
if(block.blockType != BlockType.Empty) {
addChild(blockSprite);
let constantMovement = SKAction.moveByX(-10, y: 0, duration: 1)
var currentBlockSprite:SKSpriteNode
let checkPosition = SKAction.runBlock({ () -> Void in
if(blockSprite.position.x < -512){
blockSprite.removeAllActions()
blockSprite.removeFromParent()
}
})
let movementSequence = SKAction.sequence([constantMovement, checkPosition])
let constantlyCheckPosition = SKAction.repeatActionForever(movementSequence)
blockSprite.runAction(constantlyCheckPosition)
}
block.sprite = blockSprite;
}
That would then allow you to simply add a new block whenever you see fit and it will have the appropriate action when it's added.
I've used 512 as thats the size of the iPhone 5 screen but you could swap this out for another screen size or what would be better would be a variable that dynamically reflects the screen size.

objective-c: proper way to generate a lot of instances of a certain class without creating a memory leak?

I'm making a simple SpriteKit game. It has one randomly generated world made up of lines. These lines are represented by the NHRLineNode class. I generate these lines all at once in the beginning of the level with two for loops, one for each side of the screen. This works fine. In addition to the main gameplay scene of the game, there is a "game over" screen that displays between plays and shows your score etc and a main menu scene. The problem comes when I play the game, die, see the game over screen, and play again. Looking at the memory usage in Xcode, it seems like the memory usage goes up when I first start the game from the menu scene, stays steady throughout the gameplay, and then jumps 6-10 MB when I die. This memory is never regained and the app uses more and more memory every time I play. I think this is because my for loops that generate the platforms are just creating a new instance of the NHRLineNode class, positioning it correctly, and then doing it again. Is this what is causing my memory issues? Or is it more likely something on the game over scene?
Relevant snippets:
The for loops that generate the platforms:
int previousXVal1 = -10;
int previousYVal1 = 425;
int newXPosition = 0;
//How many do you want?
int numToGen = 100;
for(int i = 1; i<=numToGen; i++) {
NHRLineNode *lineGen = [NHRLineNode initAtPosition:CGPointMake(previousXVal1 + arc4random_uniform(85), previousYVal1 - 75)];
[worldNode addChild:lineGen];
if(lineGen.position.x > 390) {
newXPosition = lineGen.position.x - 100; //That should bring it onscreen!
lineGen.position = CGPointMake(newXPosition, lineGen.position.y); //Make the new position
} else if (lineGen.position.x < 100) {
newXPosition = lineGen.position.x + 100; //That will bring it onscreen!!
lineGen.position = CGPointMake(newXPosition, lineGen.position.y);
}
previousXVal1 = lineGen.position.x;
previousYVal1 = lineGen.position.y;
}
//This creates the lines on the right side (performing the inverse calculation on the x pos
//int numToGen = 10;
int previousXVal2 = 350;
int previousYVal2 = 525;
for(int i = 1; i<=numToGen; i++) {
NHRLineNode *lineGen = [NHRLineNode initAtPosition:CGPointMake(previousXVal2 - arc4random_uniform(85), previousYVal2 - 75)];
[worldNode addChild:lineGen];
if(lineGen.position.x > 390) { //It is partially off-screeb=n
newXPosition = lineGen.position.x - 100; //That should bring it onscreen!
lineGen.position = CGPointMake(newXPosition, lineGen.position.y); //Make the new position
} else if (lineGen.position.x < 100) { //It is partially off-screen
newXPosition = lineGen.position.x + 100; //That will bring it onscreen!!
lineGen.position = CGPointMake(newXPosition, lineGen.position.y);
}
previousXVal2 = lineGen.position.x;
previousYVal2 = lineGen.position.y;
}
The initAtPosition method of NHRLineNode:
+(id)initAtPosition:(CGPoint)point {
//This is all the properties of one of the lines in the level
SKSpriteNode *theLine = [SKSpriteNode spriteNodeWithImageNamed:#"newLine"];
//The physics body is slightly smaller than the image itself -- why idk
theLine.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:CGSizeMake(75,5)];
//It is not affected by gravity
theLine.physicsBody.dynamic = NO;
//Its position is the point given us when the function was called
theLine.position = point;
//Return it for further positioning by the generator
return theLine;
}
Entire implementation of GameOverScene: http://pastebin.com/wUpguueb
Thanks for your help.
Even though you have ARC on your side, sometimes you need to give it "incentive" to free objects, especially when creating many in a loop. Really, this simply has to do with providing scope, so ARC understands that it may release allocated instances.
Try wrapping the bodies of your for loops (i.e. not around the entire for loops), with #autoreleasepool { …} - i.e., as if that #autoreleasepool block is the only statement for the for loop.
Let is know if it helps! I commonly have to do this when iteratively importing data to Core Data.

TransformGestureEvent.GESTURE_PAN event does not fire

I have the following code for ios app,
Multitouch.inputMode = MultitouchInputMode.GESTURE;
var mySprite:Sprite = new Sprite();
mySprite.addEventListener(TransformGestureEvent.GESTURE_PAN, onPan);
mySprite.addEventListener(TransformGestureEvent.GESTURE_SWIPE, onSwipe);
mySprite.addEventListener(TransformGestureEvent.GESTURE_ZOOM, onZoom);
mySprite.addEventListener(MouseEvent.CLICK, onClick);
mySprite.graphics.beginFill(0x336699);
mySprite.graphics.drawRect(0, 0, 80, 80);
mySprite.x = 100;
mySprite.y = 100;
var myTextField:TextField = new TextField();
myTextField.y = 200;
addChild(mySprite);
addChild(myTextField);
myTextField.text = "Wait";
function onClick(e:MouseEvent):void {
myTextField.text = "onClick";
}
function onPan(e:MouseEvent):void {
myTextField.text = "onPan";
}
function onSwipe(e:TransformGestureEvent):void {
myTextField.text = "onSwipe";
}
function onZoom(e:TransformGestureEvent):void {
myTextField.text = "onZoom";
}
When I test the app on itouch, everything works except onPan. It seems the TransformGestureEvent.GESTURE_PAN event never fires no matter what I do. When I move my finger while pressiing down, the onSwipe gets called. If I comment out the event listener for TransformGestureEvent.GESTURE_SWIPE then nothing gets called when I move my finger while pressing down.
Am I doing the pan gesture wrong? What is the difference between TransformGestureEvent.GESTURE_PAN and TransformGestureEvent.GESTURE_SWIPE gestures?
Thank you very much for any answer.
TransformGestureEvent.GESTURE_PAN works with two fingers.
Try it and you will check that when you press the screen with two fingers and move, the object will start panning.
Use instead MouseEvent.MOUSEMOVE
EDIT: Look this sentence from one Manual:
When a user grabs an object with two fingers and drags it, the TransformGesture
Event.GESTURE_PAN event is triggered and the onGesturePan method is called. Within the
onGesturePan method, the offsetX and offsetY values of this event are written to the
text property of the TextArea component. Adding the event’s offsetX and offsetY values
sets the object’s x and y to move the object across the stage.
Hope this help.
Pan only worked for me when I did double-finger press and move. I cant find a proper description of what these different gestures actually are, but that's what it seems to be.
function onPan(e:MouseEvent): must be onPan(e:TransformGestureEvent)

Actionscript 3, rotate object on drag

I have an object I need to rotate by clicking and dragging. Following some AS2 code I got the object to rotate a bit every time the mouse is clicked, but can't get it to work with drag.
needle.addEventListener(MouseEvent.MOUSE_DOWN, fl_ClickToDrag_2);
stage.addEventListener(MouseEvent.MOUSE_UP, fl_ReleaseToDrop_2);
function fl_ClickToDrag_2(event:MouseEvent):void
{
var angle = Math.atan2(mouseY-needle.y,mouseX-needle.x);
// apply rotation to handle by converting angle into degrees
needle.rotation = angle*180/Math.PI;
// rotate the grip opposite the handle so it won't rotate along with it
//this.grip._rotation = -this._rotation;
}
function fl_ReleaseToDrop_2(event:MouseEvent):void
{
needle.stopDrag();
}
Well the problem I see is that the MOUSE_DOWN event only fires once per click, so you only run the code in the handler once.
There could be a better way than this but this is how I'd consider doing it:
EDITED FOR DETAIL:
public class Test extends MovieClip {
private var n:Needle;
public function Test() {
// constructor code
n = new Needle();
stage.addEventListener(MouseEvent.MOUSE_DOWN,mouseDownF,false,0,true);
stage.addEventListener(MouseEvent.MOUSE_UP,mouseUpF,false,0,true);
n.x = stage.stageWidth/2; //center needle on stage
n.y = stage.stageHeight/2;
addChild(n); //add needle to stage
}
public function mouseDownF(e:MouseEvent):void {
stage.addEventListener(MouseEvent.MOUSE_MOVE,rotate,false,0,true);
}
public function rotate(e:MouseEvent):void {
var angle:Number = Math.atan2(mouseY - n.y,mouseX - n.x); //get angle in radians (pythagoras)
angle = angle * 180/Math.PI -90; //convert to degrees , the 90 is to have it point to the mouse
n.rotation = angle; //rotate
}
public function mouseUpF(e:MouseEvent):void {
stage.removeEventListener(MouseEvent.MOUSE_MOVE,rotate);
}
}
So when the user clicks down (mouseDown) it activates an event listener that fires the rotate handler every time the mouse moves. When the user lets go of the click the event listener is destroyed. The false,0,true); when adding the event listener is to make it a weakly referenced listener so that it gets collected by the garbage collector and doesn't just sit in memory taking up space forever.

Resources