Reputation: 767
I'm creating a collecting game, and I want to create a time slow/speed up powerup. Any ideas on how to do that in Flash/AS3?
One way I thought of was simply changing the frame rate. I can slow down the frame rate. But when I try to increase the frame rate beyond 60, Flash caps it at 60.
Thank you in advance for your help.
Upvotes: 0
Views: 703
Reputation: 21403
I like to do time-based movement instead of frame-based movement for better consistency. The general concept is to check the amount of time passed between frames and base movement on that instead of frames which can alternate (e.g. you can have 60FPS for a bit and then it slows down to 30FPS). You can do a simple calculation based on time passed for movement, for instance player.x += player.speed * timeDiff
but that can result in odd situations if the time passed between frames happens to be really large (for instance, the player can end up missing lots of collisions since you are moving him in one large movement). Instead, I like to use a game loop to move the player X times based on the amount of time that has passed between frames, ensuring that collisions and any other game loop events will be properly checked.
This also has the advantage that it is easy to adjust the speed.
Here is the basic concept:
private var speedMultiplier:int = 100;//100 normal speed, 0 paused
private var currRealTime:int = getTimer();
private var currGameTime:int = currRealTime;
private var globalLastTime:int = currRealTime;
private var totalTimeDiffRemainder:int = 0;
private var loopTime:int = 20;//every 20 ms run our actions
public function getGameTimer():int
{
return currGameTime;
}
private function updateGameTime():void
{
var realTime:int = getTimer();
currGameTime = currGameTime + speedMultiplier/100*(realTime - currRealTime);
currRealTime = realTime;
}
private function runEvents(event:Event):void
{//ENTER_FRAME event
var totalTimeDiff:int = getGameTimer() - globalLastTime + totalTimeDiffRemainder;
globalLastTime = getGameTimer();
while (totalTimeDiff > loopTime)
{//every 20 ms run all our actions
totalTimeDiff -= loopTime;
//run all your game loop events here, such as collision checks
}
totalTimeDiffRemainder = totalTimeDiff;
updateGameTime();
}
So every time an ENTER_FRAME event fires, we will check the time passed since the last ENTER_FRAME event and then run our actions once for each 20ms that has elapsed and pass the remainder over to the next ENTER_FRAME event. For instance, if it's been 47 ms since the last ENTER_FRAME, we will run our actions twice and pass over 7 remaining ms to the next ENTER_FRAME event.
In order to pause, slow down, or speed up the game, all you have to do is modify speedMultiplier. Changing speedMultiplier to 0 will pause the game, 50 is half speed 100 is normal speed, 200 double speed, etc.
Upvotes: 2
Reputation: 19748
I believe the general way to do this would be to use an MVC like setup where your model holds all the data for the game elements (character position/orientation, enemies, dynamic map elements) then the controller is modifying the model. With the controller modifying the model this way you could add a multiplier to the model, and use the multiplier when having the controller update the model for "physics" or other modifying dynamic elements in the game.
Roughly:
Model
public var speedMultiplier:Number=1;
public var playerXSpeed:Number;
public var playerYSpeed:Number;
Controller (I'm assuming you make a controller class and pass the view to the constructor and are listening for events from the view in the controller).
private function enterFrame_handler(event:Event):void
{
var playerSprite:Sprite = mainView.playerSprite;
playerSprite.x += playerXSpeed*speedMultiplier; //only problem I can see here is your player skipping past certain elements, to avoid this you could use a loop to make each motion and do checks but it's more CPU intensive
//var enemySprites:Vector<EnemySprite>;
//other game physics here, reduce speed due to drag, fix any invalid values etc.
}
Edit
Actually in thinking this through some more, although I do generally like using an MVC setup myself since it allows one to have a single sprite that does all the drawing; you could also use the same concept of a speedMultiplier shown here without necessarily changing around any software patterns. If you end up needing to do it with a loop because you need it to do checks for every spot it would hit as an object moves along, you may need to have your default speedMultiplier be something like 10 so you could set it down to 1 to get 1/10th speed with all the same checks as it would get at 10 being normal speed (again only issue here being it has to do whatever calculations 10 times for every update, in this case you may want to use a timer instead of the frame rate to control the overall calculation speed).
Upvotes: 1