I am writing a Tetris program with PyGame, and came across a funny problem.
Before I ask the question, here is the pseudo-code:
while True:
# In this part, the human controls the block to go left, right, or speed down
if a key is pressed and the block isnt touching the floor:
if the key is K-left:
move piece left one step
if the key is K-right:
move piece right one step
if the key is K-down:
move piece down one step
# This part of the code makes the piece fall by itself
if the block isnt touching the floor:
move block down one step
# This part makes the while loop wait 0.4 seconds so that the block does not move
# down so quickly
wait 0.4 seconds
The problem is that, because of the "wait 0.4 seconds" part of the code, the part that the human controls can only move every 0.4 seconds. I would like it so that the block moves as fast as the human can press the key, while at the same time, the block dropping every 0.4 seconds. How could I arrange the code so that it will do that? Thanks!
The main problem I see here is that you are limiting your framerate using a wait of 0.4 seconds.
You should not limit framerate, but instead, you should limit how fast your block falls.
If I remember well, there was a formula you could use to do just that. It was based on the amout of time elapsed since the last frame. It looked like:
fraction of a second elapsed since last frame * distance you want your block to move in a second
This way, you can keep your mainloop intact, and the move processing will happen at every frame.
You could also do...
...
# This part of the code makes the piece fall by itself
if the block isn't touching the floor and
the block hasn't automatically moved in the last 0.4 seconds:
move block down one step
...
Just realize you'll be doing a lot of polling if the user hasn't struck any keys.
You may try asking gamedev.stackexchange.com instead. Check the site for Game Loops, and check out other example pygame projects to see how they're doing it. Having a good game loop is essential and will take care of things for you such as user inputs and a consistent frame rate.
Edit: https://gamedev.stackexchange.com/questions/651/tips-for-writing-the-main-game-loop
When doing games you should always try to do something like this:
while not finished:
events = get_events() # get the user input
# update the world based on the time that elapsed and the events
world.update(events, dt)
word.draw() # render the world
sleep(1/30s) # go to next frame
The sleep time should be variable so it takes into consideration the amount of time spend drawing and calculating the world updates.
The world update method would look something like this:
def update(self, events, dt):
self.move(events) # interpret user action
self.elapsed += dt
if self.elapsed > ADVANCE_TIME:
self.piece.advance()
self.elapsed = 0
The other way of implementing this (so you dont redraw too much) is to have events fired when the user orders a piece to be moved or when ADVANCE_TIME time passes. In each event handler you would then update the world and redraw.
This is assuming you want the pieces to move one step at a time and not continuous. In any case, the change for continuous movement is pretty trivial.
Related
I'm trying to create a turn-based RPG where the player characters and the enemy characters each possess a speed stat. Using this stat, I would like to create an on-screen display of the next, say, 6 people in the queue to take their turn.
My issue is that I can't figure out how to turn the speed stat of each character into a useable number to determine turn order.
For example:
char1.speed = 10;
char2.speed = 20;
char3.speed = 80;
In a situation like this, I would like to be able to create a turn queue such that char3 takes two or three turns ahead of the other characters, since his character is significantly faster than the others. So the on-screen display would show portraits of char3, char3, char2, char3, char1, char3, for example. (I can make the queue display and make it re-sort itself; my struggle is making a changeable turn order that is based on a character's speed stat.)
Another issue that I'm struggling with is that I want to be able to modify a character's speed by spells, potions, etc that may end up changing the turn order mid-battle. I anticipate having an updateTurns() function which will re-sort my queue when this happens... is the best way to go about this giving each character two speed stats, baseSpeed and adjSpeed, for example? So that the baseSpeed remains the same no matter what happens through spells and items, while the adjSpeed represents a character's speed at that particular moment in battle?
Thanks for the help, and hopefully I've made sense. This is my first time posting here, so if I need any more clarification or whatnot, just let me know.
Should be relatively straight forward. First you need your divisor, i.e, how to determine what a single turn is. I assume 10? So get how many turns each character gets, set up a constant with the single turn speed in your character base class;
public static const TURN:uint = 10;
Then you can do something like this to get each players' turns;
char2.speed / character.TURN = // how many turns each player gets.
Then you can have a main loop, which is an array of your characters, and a sub loop, which loops through each character, removing a turn each time, and adding the char to the queue each time. Once turn = 0. The next character will be iterated by the main loop. Once you have a queue, you could shuffle it afterwards to change the order up a bit. Break it into two tasks.
Once you have turnsfor each character, you could deduct some turns, so also store a speedPenalty in each char which is normally 0, but if hit by a spell, change it to x. Then your main forumula is actually;
(char2.speed / character.TURN) - speedPenalty
If you do this, you'll have to make sure each char can never go below 1 turn. Or, as you say, have a base speed, and a current speed, and then deduct from current speed and use that to calculate turns, and reset it to base speed once the spell wears off.
I've written a basic velocity-based animation engine which iterates over a list of custom Shape objects which hold direction and velocity. When animating more than 500 objects, my application sees significant slowdown, but the actual time it takes to change the positions of the objects is very low.
Results are roughly as follows:
100 objects - <1ms modification time, 60 FPS
500 objects - 2ms modification time, 40 FPS
1000 objects - 4ms modification time, 10 FPS
I am currently using Timer-based animation, and my timer is set to 15ms intervals. The timer is the ONLY thing executing in my program, and the modification times I have listed measure the entirety of the timer's event function which contains only synchronous code. This means (as far as I can tell) that the only thing that could be responsible for the delay between timer events is screen rendering.
All my objects are tightly clustered. Would screen rendering really take four times as long for 1000 objects as 500? There is no opacity, and the only properties being edited are x and y values.
Specifically, I am wondering if there is a more efficient way to re-render content than changing the positions and then calling event.updateAfterEvent(). Any help is appreciated!
I'm having trouble achieving frame rate independent motion in AS3 at 60fps. Every frame I measure the time since the previous frame, add it to an accumulator, and if the accumulator is greater than my target time, which is 16.666ms (60fps), a frame is simulated.
The problem is that the AS3 getTimer() only returns a time in milliseconds.
The delta times I get are often 16ms for the first frame, 16ms for the second, then 18ms for the third, and this pattern repeats. This averages out to 16.666. But in the first frame it is lower than the target time (16 < 16.666), so no frame is simulated. In the second frame the accumulator is higher than the target time, but slightly less than double it, so one frame is simulated. For the third frame 18ms pushes the accumulator over double the target time, so two frames are simulated.
So I'm getting this very jerky motion where no frames are rendered, then one, then two, then none, then one, then two, and this continues.
How would I get around this?
Wow... I thought I was only one who found that out.
Yes, the timer class in AS3 is not accurate. It will only trigger every ~16ms which causes MAJOR issues at times.
If want to see 2048 actions in 1000ms: FlashText Markup Language
(To test this, you'll need a method which takes 1ms to execute - just for even stats)
Notice the difference:
CORRECT: 1000ms | timer=0 == 1000 actions
AS3: 1000ms | timer=0 == 62.5 actions
I was able to write a class that works like this:
CORRECT: 1000ms | timer=0 == 1000 actions
RESHAPE TIMER: 1000ms | timer=0 == 1024 actions
NOTE:
it DOES NOT fire an action every ms
it DOES catch up to actions between the 16ms interval
an ACTION (the way I use it) is a method call, each method call can have its own body
The methodology I used to create this was catch-up... basically the first timer event will fire at 16ms... we know we have a full 16ms worth of code time to fire our own actions before the timer class fires again - thats where you inject sub-actions...
The highest I was able to produce was 2048 actions in 1000ms... more than 2 actions per ms.
Now... back to your problem
There is NO WAY to trigger a 0ms timer event. Based on my solution, if you want to by-pass the first 16ms of lag before the timer fires... you can dispatch an event which will fire within 2ms depending on the current system processes.
Possible Solution
If you take my approach for throwing your own actions within the 16ms, then you can build your own timer class. Use events for times under 16ms, when fired... fire 15 more - lol. Basically, you can create your own deltas between the 16ms.
Recently I've been planning out how I would run a game with an environment/map that is capable of unlimited dimensions (unlimited being a loose terms as there's obviously limitations on how much data can be stored in memory, etc). I've achieved this using a "grid" that contains level data stored as a String that can be converted to a 2D Array that would represent objects and their properties.
Here's an example of two objects stored as a String:
"game.doodads.Tree#200#10#terrain$game.mobiles.Player#400#400#mobiles"
The "grid" is a 3D Array, of which the contents would represent the x/y coordinate of the grid cell. The grid cells would be, say, 600x600.
An example of this "grid" Array would be as follows:
var grid:Array = [[["leveldata: 0,0"],["leveldata 0,1"]],
[["leveldata: 1,0"],["leveldata 1,1"]]];
The environment will handle loading a grid square and it's 8 surrounding squares based on a given point. ie the position of the Player. It would have a function along the lines of
function loadCells(xp:int, yp:int):void
This would also handle the unloading of the previously loaded cells that are no longer close enough to be required. In the unload process, the data at grid[x][y] would be overwritten with the new data, which is created by looping through the objects in that cell and appending each new set of data to the grid cell data.
Everything works fine in terms of when you move in a direction, cells are unloaded/saved and new cells are loaded. The problem is this:
Say this is a large city infested by zombies. If you walk three grid squares in any direction and return, everything is as you left it. I'm struggling to find a way to at least simulate all objects still moving around and doing their thing. It looks silly when you for example throw a grenade, walk away, return and the grenade still hasn't detonated.
I've considered storing a timestamp on each object when I unload the level, and when it's initialized there's a loop that runs it's "step" function amount of times. Problem here is obviously that when you come back 5 minutes later, 20 zombies are going to try and step 248932489 times and the game will crash.
Ideas?
I don't know AS3 but let me try give you some tips.
It seems you want to make a seamless world since you load / unload cells as a player moves. That's a good idea. What you should do here is deciding what data a cell should load / unload( or, even further, what data a cell should hold or handle ).
For example, the grenade should not be unloaded by the cell as it needs to be updated even after the player leaves the cell. It's NOT a good idea for a cell to manage all game objects just because they are located in the cell. Instead, the player object could handle the grenade as an owner. Or, there could be one EntityManager which handles all game entities like grenades or zombies.
With this idea, you can update your 20 zombies even when they are in an unloaded zone (their location does not matter anymore) instead of calling update() 248932489 tiems at once. However, do you really need to keep updating the zombies? Perhaps, unloading all of them and spawning new zombies with the number of the latest active zombies in the cell would work. It depends on your game design but, usually, you don't have to update entities which are not visible or far enough from the player. Hope it helps. Good luck! :D
Interesting problem. Of course, game cannot simulate unlimited environment precisely. If you left some zone for a few minutes, you don't need every step of zombies (or any actors there) to be simulated precisely. Every game has its own simplications. Maybe approximate simulation will help you. For example, if survivor was in heavily infested zone for a long time, your simulator could decide that he turned into zombie, without computing every step of the process. Or, if horde was rampant in some part of the city, this part should be damaged randomly.
I see two methods as to how you could handle this issue.
first: you have the engine keep any active cells loaded, active means there are object-initiated events involving cell-owned objects OR player-owned objects (if you have made such a distinction that is). Each time such a cell is excluded from normal unloading behaviour it is assigned a number and if memory happens to run out the cells which have the lowest number will be unloaded. Clearly, this might be the hardest method code-wise but still it might be the only one truly doing what you desire.
second: use very tiny cells and let the engine keep a narrow path loaded. The cells migth then be 100x100 instead of 600x600 and 36 of them do the work one bigger cell would do ( risk: more cluttter code-wise) then each cell your player actually traverses ( not all that have been loaded to produce a natural visibility-range ) is kept in memory including every cell that has player-owned objects in it for a limited amount of time ( i.e. 5 minutes ).
I believe you can find out how to check for these conditions upon unloading yourself and hope to have been of help to you.
I'm having a silly-yet-serious case of coder's block. Please help me work through it so my brain stops hurting and refusing to answer my questions.
I want to fire a timer at intervals up to a final time. For example, if t = 0, my goal is 100, and my interval is 20, I want to fire at 0, 20, 40, 60, 80, and 100.
The timer is not precise, and may fire early or late. If it first fires at 22, I want to fire again in 18. If it first fires at 19, I want to fire in 21. All I know when the timer fires is the current time, goal time, and firing interval. What do I do?
Edit: Sorry, I wasn't too specific about what the heck I'm actually asking. I'm trying to figure out what kind of math (probably involving taking the modulus of something) needs to be done to calculate the delay until the next firing. Ideally, I also want the timer to by matched to the end time — so if I start the timer initially at 47, it schedules itself to fire at 60 and not at 67, so the last firing will still be at 100.
If the primitive functionality you have is "schedule X to fire once at time T", then your procedure handling X should know the time T0 at which it was supposed to fire (the time T1 at which it actually fired is not needed) as well as the desired firing interval DT and schedule itself for time T0+DT. If the primitive is "fire D from now", then it should schedule for D = T0+DT-T1 (if that's negative then it needs to schedule itself immediately again but record that the scheduled time and the "was supposed to fire at" time are different so it can keep compensating on following firings).
Somebody already mentioned that .NET's Timer does this for you; so does Python's sched stdlib module; so, I'm sure, do many other languages / frameworks / libraries. But in the end you can build it if needed on top of either of the single-scheduling primitives above (one for an absolute time or one for a relative delta from now) as long as you keep track of desired as well as actual firing times!_)
I would use the system clock to check your interval. For example if you know that your interval is every 20 minutes, fire off the first interval, check what the time was, and adjust the next interval start time.
If your language/platform's underlying timers don't do what you want, then it's usually best to implement timers in terms of "target times", which means the absolute time at which you want the timer to fire next. If you platform asks for an "absolute time", then you give it the target time. If it asks for a "relative time" (or, like sleep, a duration), then it is of course target_time - current_time.
The quick way to calculate each target time in turn is:
When you first set up the timer, calculate the "interval" (which might have to be a floating-point value, assuming that won't cripple performance) and also the "target time" of the first timer fire (again, you might need fractions). Record both, and set your underlying timer mechanism, whatever that is.
When the timer fires, work out the next target time by adding the interval to the previous target time.
The problem with that approach is that you might get some very tiny accumulating errors as you add the interval to the target time (or not so tiny, if you haven't used floats).
So the longer and more accurate way is to store the very first start time, the target finishing time, and the number of firings (n). Then you recalculate the target time for each new firing in turn, which makes sure that you don't get cumulative rounding errors. The formula for that is:
target(k) = start + ((target_end - start) * k) / n
Of if you prefer:
target(k) = (k/n) * end + (1-k/n) * start
Where the firings of the timer are k=1, 2, 3, ... n. I was going to make it 0-based, then realised that was daft ;-)
The last thing you have to wrestle with when implementing timers is the difference between "wall clock" time, and real elapsed time as measured by your hardware clock. Wall clock time can suddenly jump forwards or backwards (either by an hour if your wall clock is affected by daylight savings, or by any amount if the system's clock is adjusted or corrected). Real time always increases (as long as it doesn't wrap). Which you want your timer to respect depends on the intended purpose. If you want to know when your last bus leaves, you want a timer firing daily according to wall clock time, but most commonly you care about real time elapsed. A good timer API has options for these kinds of things.
Build a table listing the desired fire times, say 10:00, 10:20, 10:40, 11:00, and 11:20.
If your timer function takes an absolute time, the rest is trivial. Set it to fire at each of the desired times. If for whatever reason you can only set one timer at a time, okay, set it to fire at the first desired time. When that event happens, set it to fire again at the next time in the table, without regard to what time it is now. Each time through, pick up the next time until you're done.
If your timer function only accepts an interval, no big deal either. Find the difference between the desired time and the current time, and set it to fire at that interval. Like if the first time is 10:00 and it's now 9:23, set it to fire in 10:00 minus 9:23 equal 37 minutes. Then when that happens, set the interval to the next desired time minus the current time. If it really fired at 10:02, then the interval is 10:20 minus 10:02 equals 18 minutes. Etc.
You probably should check for the possibility that the next fire time has already passed. If the process can take longer than the interval you might run past it, and even if not, the system might have been down. If a fire time is missed, you may want to do catch up runs, or just skip it and go to the next desired time, depending on the details of your app.
If you can't keep the entire table -- like it goes on to infinity -- then just keep the next fire time. Each time through the process, add a fixed amount to the next fire time, without regard to when the current process ran. Then calculate the interval based on the current time. Like if you have a desired interval of 20 minutes going on forever starting at 10:00, and it's now 9:23, you set the first interval to 37 minutes. Say that actually happens at 9:59. You set the next fire time to 10:00 plus 20 minutes equals 10:20, i.e. base it on the goal time rather than the actual time. Then calculate the interval to the next fire time based on the current time, i.e. 10:20 minus 9:59 equals 21 minutes. Etc.