I am a newbie in game developing, now i am working with a shooter game for learning purpose.
I have a question,
in my game I created three tween animation :
var myTween:Tween = new Tween(this, "scaleX", Back.easeIn, 1.2, 0, 10);
var myTween2:Tween = new Tween(this, "scaleY", Back.easeIn, 1.2, 0, 10);
var myTween3:Tween = new Tween(this, "alpha", None.easeIn, 1, 0, 10);
This tweens will occur after enemy's health become zero,
What I intended is after the animation, the clip will be removed from stage.
my question is, is there a way to know that all these tweens has finished? I tried to apply TweenEvent.MOTION_FINISH event for each tween , but If i do that i have to create three listenesr ( which will be problematic if I want to create ten tweens).
Thank you
Since all the tweens run for the same duration could you not just add your listener to the last tween and when the handler executes you will know that they have all completed?
Alternatively you could do something like this:
import fl.transitions.Tween;
import fl.transitions.TweenEvent;
import fl.motion.easing.Back;
import fl.transitions.easing.None;
// Populate an array with the tweens
var tweens:Array = [];
tweens.push(new Tween(this, "scaleX", Back.easeIn, 1.2, 0, 10));
tweens.push(new Tween(this, "scaleY", Back.easeIn, 1.2, 0, 10));
tweens.push(new Tween(this, "alpha", None.easeIn, 1, 0, 10));
// Finished tweens count
var finishedCount:int = 0;
// Loop through all the tweens and add a handler for the motion finished event
for (var i:int = 0; i < tweens.length; i ++)
{
// Each of the tweens motion finished event can be assigned to the same handler
Tween(tweens[i]).addEventListener(TweenEvent.MOTION_FINISH, motionFinishedHandler);
}
function motionFinishedHandler(e:TweenEvent):void
{
// Good practice to remove the event listener when it is no longer needed
e.target.removeEventListener(TweenEvent.MOTION_FINISH, motionFinishedHandler);
// Increment the count and test whether it equals the number of tweens
if (++ finishedCount == tweens.length)
trace("Finished");
}
You might also want to consider Greensock's TweenLite which is pretty much the standard for animating objects in Flash and which will allow you to tween multiple properties of the same object in a single call.
+1 for Greensock's TweenLite & TimelineLite.
Makes tweening everything cleaner and easier.
Related
I want to create a text typing effect in simple web application. It's my first time using dart for web application. I did something like this.
var chars = "Hello World".split('');
var textstream = Stream<String>.fromIterable(chars);
var idx = 0;
textstream.listen((data) {
Future.delayed(Duration(milliseconds: idx * 200), () {
var element = querySelector('#hero-keyword');
element.appendText(data);
idx++;
});
});
And my html has this
<p id="hero-keyword"></p>
But, I want each letter printed in the interval of 200ms. But what I got is, all letters show up at the same time.
Your idx variable is only being updated when the delayed future completes, which will happen on the first pass of the event loop after the specified delay.
fromIterable, however, will process its values all at once, in sequence. Taken together, the net effect is that all of your delays are being set to 0, and then, after a slight delay, all of your characters will be emitted, and idx will be incremented.
You can try the following pattern, instead, adjusted to your use case:
void main() {
var text = "Hello world";
Stream
.periodic(Duration(milliseconds: 200), (count) {
print(text[count]);
})
.take(text.length)
.drain();
}
I have a moving background which is 1500 x 600 pixels and constantly moves vertically down the screen using this code:
let bgTexture = SKTexture(imageNamed: "bg.png")
let moveBGanimation = SKAction.move(by: CGVector(dx: 0, dy: -bgTexture.size().height), duration: 4)
let shiftBGAnimation = SKAction.move(by: CGVector(dx: 0, dy: bgTexture.size().height), duration: 0)
let moveBGForever = SKAction.repeatForever(SKAction.sequence([moveBGanimation, shiftBGAnimation]))
var i: CGFloat = 0
while i < 3 {
bg = SKSpriteNode(texture: bgTexture)
bg.position = CGPoint(x: self.frame.midX, y: bgTexture.size().height * i)
bg.size.width = self.frame.width
bg.zPosition = -2
bg.run(moveBGForever)
self.addChild(bg)
i += 1
}
I now want a new background to come onto the screen after x amount of time to give the feel the player is moving into a different part of the game.
Could I put this code into a function and trigger it with NSTimer after say 20 seconds but change the start position of the new bg to be off screen?
The trouble with repeatForever actions is you don't know where they are at a certain moment. NSTimers are not as precise as you'd like, so using a timer may miss the right time or jump in too early depending on rendering speeds and frame rate.
I would suggest replacing your moveBGForever with a bgAnimation as a sequence of your move & shift actions. Then, when you run bgAnimation action, you run it with a completion block of { self.cycleComplete = true }. cycleComplete would be a boolean variable that indicates whether the action sequence is done or not. In your scene update method you can check if this variable is true and if it is, you can run the sequence action once again. Don't forget to reset the cycleComplete var to false.
Perhaps it sounds more complex but gives you control of whether you want to run one more cycle or not. If not, then you can change the texture and run the cycle again.
Alternatively you may leave it as it is and only change the texture(s) after making sure the sprite is outside the visible area, e.g. its Y position is > view size height.
In SpriteKit you can use wait actions with completion blocks. This is more straightforward than using a NSTimer.
So, to answer your question - when using actions for moving the sprites on-screen, you should not change the sprite's position at any time - this is what the actions do. You only need to make sure that you update the texture when the position is off-screen. When the time comes, obviously some of the sprites will be displayed, so you can't change the texture of all 3 at the same time. For that you may need a helper variable to check in your update cycle (as I suggested above) and replace the textures when the time is right (sprite Y pos is off-screen).
I want k to follow multiple paths. I want it to finish p1 and then run p2. After it finishes p2, i want it to follow p3. How can I do this? Is there a handler that detects if the sprite finishes the path?
//k is my SKSpritenode
func followPath(path:CGPath,sprite:SKSpriteNode,speed:CGFloat){
sprite.runAction(SKAction.followPath(path, speed: speed))
}
followPath(p1, sprite: k, speed: 90)
followPath(p2, sprite: k, speed: 90)
followPath(p3, sprite: k, speed: 90)
You can add a list of actions into a sequence and then this sequence as one long actions itself.
Apologies, as I use Xamarin and C#, so my calls will look slightly different, but in essence, here's a simple example:
var rect = new CGRect(0, 0, 100, 100);
var path = new CGPath();
path.AddRect(rect);
var moveOneDirection = SKAction.FollowPath(path, false, true, 5.0f);
var sequence = SKAction.Sequence(moveOneDirection, moveOneDirection.ReversedAction);
sprite.RunAction(SKAction.RepeatAction(sequence, 3));
This will make your sprite move along a rectangle, then back, and do this 3 times. Obviously, you can add many more paths!
I have 4 buttons and 4 images when I click a button a different image appears. I want the images to ease in and out after each button click. I have tried the code below but can't seem to figure it out.
home_btn.addEventListener(MouseEvent.CLICK, homeClick);
function homeClick(e:MouseEvent):void{
backgroundimg.source = "images/bluebg.jpg";
var bluebgTween:Tween = new Tween(backgroundimg, "alpha", Strong.easeIn, 1, 0, 3, true);
}
If fading in then fading out, set the initial alpha of backgroundimg to 0.
backgroundimg.alpha = 0;
You can then fade in on the CLICK event. Note that I've swapped the begin and finish values for the Tween.
Once the tween has finished, the yoyo() method can then be used to fade out again.
home_btn.addEventListener(MouseEvent.CLICK, homeClick);
function homeClick(e:MouseEvent):void{
backgroundimg.source = "images/bluebg.jpg";
var bluebgTween:Tween = new Tween(backgroundimg, "alpha", Strong.easeIn, 0, 1, 3, true);
bluebgTween.addEventListener(TweenEvent.MOTION_FINISH, onFinish);
function onFinish(te:TweenEvent):void {
bluebgTween.yoyo();
bluebgTween.removeEventListener(TweenEvent.MOTION_FINISH, onFinish);
}
}
I used these sites as a reference for this:
http://www.republicofcode.com/tutorials/flash/as3tweenclass/
http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/fl/transitions/Tween.html
I have a path which I want to animate every 5 seconds. I tried the using setInterval in the following code but it keeps duplicating the canvas. Is there an easier solution?
JS Fiddle Link
window.onload= function aa () {
paper = Raphael(0,0,900,900);
var p=paper.path("M10,10 h20 v10 h-20z");
p.animate({path:"M10,10 h300 v10 h-300z"},5000);
//window.setInterval(aa(), 5000);
}
You are repeating the whole aa function that initializes the raphael paper (paper = Raphael(0,0,900,900);). That's why your canvas gets duplicated.
Moreover, it would be better to use callbacks (you can see the the docs on animate) rather than setInterval to trigger your animations.
This is how I would code it :
function init(){
var paper = Raphael(0, 0, 900, 900),
pathsString = ["M10,10 h20 v10 h-20z","M10,10 h300 v10 h-300z"],
p = paper.path(pathsString[0]),
animationCounter = 0,
animationDuration = 5000,
animate = function(){
animationCounter++;
p.animate({path : pathsString[animationCounter %2]}, animationDuration, animate);
};
animate();
};
window.onload = init;
Here's a working example of the above code.