Pause a for Loop for actions - Swift: Sprite Kit - for-loop

I'm trying to make a deer to jump ramdonly through different defined positions.
func deerJumping () {
// The different locations are arranged ramdonly
var places: [CGFloat] = [1124, 852, 1540, 1908, 628, 1736, 392].shuffled()
//Then the for loop with the actions (jumps) between this positions
for posc in places {
//SKAction for the up and down
//SKAction for the displacement left or right
//Code for the deer to face the direction of the jump
//Then run the action:
deer.run(SKAction.group([jump, move]))
}
}
The problem is that the loop is not waiting for the actions to finish before to go to the next position in the array.
There's this Pause and Resume a for Loop question that I find. It is about to create NSOperation instances in the loop and add them to an NSOperationQueue but sadly I am a beginner and I don't understand the solution so I have no idea how to apply it to my code.
Any help would be much appreciated!!

The reason why nothing is waiting is because you run all of your actions at the same time. You want to create an array of actions and run it in sequence
func deerJumping () {
// The different locations are arranged ramdonly
var places: [CGFloat] = [1124, 852, 1540, 1908, 628, 1736, 392].shuffled()
//Then the for loop with the actions (jumps) between this positions
var actions = [SKAction]()
for posc in places {
//SKAction for the up and down
//SKAction for the displacement left or right
//Code for the deer to face the direction of the jump
//Then run the action:
actions.append(SKAction.sequence([jump, move]))
}
var deerRunning = SKAction.sequence(action)
deer.run(deerRunning)
}
Now I have no idea why you want to pause and resume a for loop, you are going to have to elaborate on that one before I can help you out.

Related

How to force display of Xcode moverow animation?

I'm trying to reorder a list multiple times and want to see the animation of each individual move, however, the iPhone simulator shows a long delay during the loop, and then it animates the results of all the moves at once:
for _ in 1...1000 {
let source = Int.random(in: 0..<list.count)
let destination = Int.random(in: 0..<list.count)
tableView.moveRow(
at: IndexPath(row: source, section: 0),
to: IndexPath(row: destination, section: 0))
}
I have tried the following commands from Developer Documentation:
tableView.reloadData()
tableView.reloadRows(at:with:)
tableView.reloadSections(at:with:)
tableView.layoutSubviews()
tableView.layoutSublayers(of:)
tableView.layoutIfNeeded()
tableView.beginUpdates()-tableView.endUpdates()
however, they all have the same effect of delaying the animation until the end of the loop.
How can I display the animation of each individual row move within the loop?

My animation is lagging, why?

I have an animation in unity, and basically it shows Donald Trump running:
I also have this one frame animation of Trump jumping:
Basically, when he jumps, the jump animation plays, and when he lands, the walk animation plays again.
This all works, and this code runs it:
function Update() {
trump.velocity = Vector2(speed, trump.velocity.y);
if (jump > 0) {
jumpBool = true;
}
else {
jumpBool = false;
}
animator.SetBool("Jump", jumpBool);
That's in the physics script. Then from the animator:
This all works, and the animations change when they are supposed to. The issue is, it lags before it finishes. I think that when Trump jumps, the walk animation finishes before it switches to the jump animation. My question is, how do I automatically switch animations immediately, so it won't look so laggy?
You can immediately call the Jump animation to be played at the point you make the JumpBool = true. Doing so you don't need to wait for the walk animation finish, it will simply stop the Walk and and move to Jump.
function Update() {
trump.velocity = Vector2(speed, trump.velocity.y);
if (jump > 0) {
animator.Play("Trump Jump");
//jumpBool = true;
}
else {
//jumpBool = false;
}
//animator.SetBool("Jump", jumpBool);
You don't even need to Set the bool, after the Jump animation has finished it will move back to the Walk animation.

Simple 2-step animation using Unity's Animation Tool

I am new to Unity/coding and trying to create a simple 2-step animation in which I can adjust the delay times for each step. I have a lift in my game that uses two animations: "Up" and "Down".
I'm using an enumerator to play the animations, and this is what I have so far:
IEnumerator Go()
{
while(true)
{
GetComponent<Animation>().Play ("Up");
yield return new WaitForSeconds(delayTime);
break;
GetComponent<Animation>().Play ("Down");
yield return new WaitForSeconds(delayTime);
break;
}
}
I understand I could just animate the whole thing as one motion, but I want to be able to adjust the delay times on the fly. My goal is to animate these two in succession. Up, then down. At the moment my lift goes up and stays there. What am I doing wrong?
Thanks for the help!
Remove the break-clauses:
IEnumerator Go()
{
while(true)
{
GetComponent<Animation>().Play ("Up");
yield return new WaitForSeconds(delayTime);
GetComponent<Animation>().Play ("Down");
yield return new WaitForSeconds(delayTime);
}
}
Now it should loop the two animations. In the original code the break statements are causing the execution jump out of the loop and, therefore, the Play for the "Down" is never called and execution of the function is terminated.
If you want the lift go up and down only once you need to remove the while loop.

Flixel Game Over Screen

I am new to game development but familiar with programming languages. I have started using Flixel and have a working Breakout game with score and lives.
I am just stuck on how I can create a new screen/game over screen if a player runs out of lives. I would like the process to be like following:
Check IF lives are equal to 0
Pause the game and display a new screen (probably transparent) that says 'Game Over'
When a user clicks or hits ENTER restart the level
Here is the function I currently have to update the lives:
private function loseLive(_ball:FlxObject, _bottomWall:FlxObject):void
{
// check for game over
if (lives_count == 0)
{
}
else
{
FlxG:lives_count -= 1;
lives.text = 'Lives: ' + lives_count.toString()
}
}
Here is my main game.as:
package
{
import org.flixel.*;
public class Game extends FlxGame
{
private const resolution:FlxPoint = new FlxPoint(640, 480);
private const zoom:uint = 2;
private const fps:uint = 60;
public function Game()
{
super(resolution.x / zoom, resolution.y / zoom, PlayState, zoom);
FlxG.flashFramerate = fps;
}
}
}
There are multiple ways to go about doing this...
You could use different FlxStates, like I described in the answer to your other post: Creating user UI using Flixel, although you'll have to get smart with passing the score or whatever around, or use a Registry-type setup
If you want it to actually work like you described above, with a transparent-overlay screen, you can try something like this (keep in mind, the exact details may differ for your project, I'm just trying to give you an idea):
First, make sure you have good logic for starting a level, lets say it's a function called StartLevel.
You'll want to define a flag - just a Boolean - that tracks whether or not the game is still going on or not: private var _isGameOver:Boolean; At the very end of StartLevel(), set this to false.
In your create() function for your PlayState, build a new FlxGroup which has all the things you want on your Game Over screen - some text, an image, and something that says "Press ENTER to Restart" (or whatever). Then set it to visible = false. The code for that might look something like:
grpGameOver = new FlxGroup();
grpGameOver.add(new FlxSprite(10,10).makeGraphic(FlxG.Width-20,FlxG.Height-20,0x66000000)); // just a semi-transparent black box to cover your game screen.
grpGameOver.add(new FlxText(...)); // whatever you want to add to the group...
grpGameOver.visible = false;
add(grpGameOver); // add the group to your State.
Depending on how your game is setup, you may also want to set the objects in your group's scrollFactor to 0 - if your game screen scrolls at all:
grpGameOver.setAll("scrollFactor", new FlxPoint(0,0));
In your update() function, you'll need to split it into 2 parts: one for when the game is over, and one for if the game is still going on:
if (_isGameOver)
{
if (FlxG.keys.justReleased("ENTER"))
{
grpGameOver.visible = false;
StartLevel();
}
}
else
{
... the rest of your game logic that you already have ...
}
super.update();
Keep in mind, if you have things that respond to user input anywhere else - like a player object or something, you might need to change their update() functions to check for that flag as well.
Then, the last thing you need to do is in your loseLive() logic:
if (lives_count == 0)
{
_isGameOver = true;
grpGameOver.visible = true;
}
else
...
That should do it!
I would highly recommend spending some time with different tutorials and sample projects to kind of get a better feel for Flixel in general. Photon Storm has some great material to play with (even though he's jumped over to HTML5 games)
I also want to note that if you get comfortable with the way Flixel handles updates, you can get really smart with your state's update() function and have it only call update on the grpGameOver objects, instead of having to change all your other objects updates individually. Pretty advanced stuff, but can be worth it to learn it.

Is there a better way of linking transitions in Corona Lua?

I'm currently animating a trash can when something gets dragged and dropped onto it with this code:
local trashUp
local trashDown
trashUp = function()
transition.to(
trash, {time=100, xScale=1.2, yScale=1.2, onComplete=trashDown })
end
trashDown = function()
transition.to(
trash, {time=100, xScale=1, yScale=1})
end
and then calling trashUp() when I want to start the animation.
The code works fine, but I can't help feel it could be coded better. Two functions to animate an object!
Is there any way I can do this more efficiently?
Well you could do it in a single function by setting the second transition with delay; refer to this code example: http://developer.anscamobile.com/reference/index/transitionto
Depending on your situation however that's not necessarily less complicated, because now you have to keep track of two transitions simultaneously instead of just one transition at a time. In the code you posted you aren't keeping track of the transitions, but you probably should be in case you need to cancel them before the transition is complete (eg. the player switches scenes in the middle of the transition).
You can do it by coding the onComplete function inline with the first transition call:
animateTrash = function()
transition.to(
trash,
{ time=100, xScale=1.2, yScale=1.2, onComplete=
function()
transition.to(
trash,
{time=100, xScale=1, yScale=1})
end
})
end
This won't be any more efficient, but it does keep everything to do with animating the trashcan in one place. I think this approach could get quickly out of hand, though, especially if you were doing anything other than the transitions when animating the trashcan, e.g., updating your program's state, or creating/destroying other objects, etc.
Echoing jhocking's answer, this approach doesn't support canceling either.
This question is pretty old, but since I was trying to do the same thing, I figured I should share what I came up with. This sequentially executes transitions that are passed in as variable args. If onComplete is supplied, it is called as its transition completes.
local function transitionSequence(target, step, ...)
local remaining_steps = {...}
if #remaining_steps > 0 then
local originalOnComplete = step.onComplete
step.onComplete = function(target)
if originalOnComplete then
originalOnComplete(target)
end
transitionSequence(target, unpack(remaining_steps))
end
transition.to(target, step)
else
transition.to(target, step)
end
end
Example:
transitionSequence(myImage,
{xScale=0.5, onComplete=function(t) print("squeeze") end},
{xScale=1, onComplete=function(t) print("relax") end},
{yScale=2, onComplete=function(t) print("stretch") end},
{yScale=1, onComplete=function(t) print("relax again") end})
transition.to( trash, {time=t, delta=true, xScale=1.5, transition=easing.continousLoop} )
Also very useful for purposes like that:
easing.sin = function( f, a )
return function(t, tmax, start, d)
return start + delta + a*math.sin( (t/tmax) *f * math.pi*2 )
end
end
easing.sinDampened = function( f, a, damp )
return function(t, tmax, start, d)
return start + delta + a*math.sin( damp^(t/tmax) *f * math.pi*2 )
end
end
...etc

Resources