Re: [pygame] time progression independent of game "ticks"
Michael George wrote: Having recently taught a data structures course I'm forced to point out that for some number of fish, inserting into the queue will become a bottleneck, Actually, it's not the number of fish that determines when this will become a bottleneck, but the typical number of events in the queue at any given moment. This is not necessarily proportional to the number of active entities in the simulation. Another thing is that the event-queue approach might not help so much for an *animated* simulation. If the fish are all swimming around on the screen, you're going to have to process them all every frame anyway to update their positions. But if only a small proportion of the fish are visible at a time, and you can avoid having to simulate the motion of off-screen fish in a detailed way, it will probably help, as long as you have a way of quickly finding all the visible fish. -- Greg
Re: [pygame] time progression independent of game "ticks"
Yeah, a time queue is the way to go, don't bother with threads. On each update, you can get the current time (pygame.time, or pygame.clock), and pass that into your time queue. The time queue, will look something like this: [(5.0,eat,fish1),(6.5,eat,fish2)] At each iteration, you continue to pop() the list, calling each function (eat) with the argument (fish1, fish2), until the item on the list has a time that is greater than the current time. If you spread out your scheduling, so there aren't too many fish doing the same thing at the exact same time, this will scale really well and be a good way to handle timed events. As for tracking time, I use pygame.time as well. I've found pygame.clock to be inaccurate in some cases, and of course it's not usable in situations where you don't want to use pygame (server). I store lasttime = pygame.time.time() at the start of the simulation, then on each iteration I calculate dt = pygame.time.time()-lasttime;. Then if I have some sort of game timer (like your 15 minutes = 1 year) I add the dt(real time difference) times a modifier (to get game time difference) to the game time variable.
Re: [pygame] time progression independent of game "ticks"
Having recently taught a data structures course I'm forced to point out that for some number of fish, inserting into the queue will become a bottleneck, and you're better off using a priority queue (heap). --Mike Laura Creighton wrote: The first time I did something like that I made a fish class which did things like get-hungry. Each fish stored its time of creation and time of last feeding, mating, egg-laying etc. Then I kept doing: for every fish: check the time of day, and update the fishes' state based on the time elapsed This worked fine for a few fish. But it did not scale. When I had 10s of thousands of fish, I couldn't get through the whole list of fish before too much time had passsed. My fish were carrying too much state around with them as well. So I changed the design to make my fish schedule 'at this time something interesting will happen to me' events into a queue which was sorted by time. Then, for every bit of time, I only had to see if it was later than or equal to the first item in the queue, and pop things off the queue until the first item on it was 'later than now'. Just in case you run into the same problem that I had. Laura
Re: [pygame] time progression independent of game "ticks"
"Simon Wittber" <[EMAIL PROTECTED]> > On 7/20/07, Daniel Nixon <[EMAIL PROTECTED]> wrote: >> What is the best way to go about such a thing? Use MVC and run the >> model in its own thread? If that is the case what is the best way to >> keep track of the passage of actual time within the model? > > This may or may not help: > > http://entitycrisis.blogspot.com/2007/07/general-pygame-main-loop.html In that post you say the benefits of a fixed sim tick step are not immediately apparent, and yet the benefits to network game synchronization is obvious. Could you go into more detail? I don't see why fixed sim ticks are any better than variable sim ticks for networked games. -Dave LeCompte
RE: [pygame] time progression independent of game "ticks"
Have you considered using time deltas? Each fish instance could be initialised a timestamp of its creation, and each iteration of the main loop you could get a timestamp of *now* and pass it to each fish (or get each fish to get its own *now* for comparison), which could then use Python's builtin timedelta class to work out how much real time has passed, rather than how much game time has passed in game ticks. So if an instance of fish was "born" on 4:15pm in-game then at 4:30pm, your fish instance will roll out the birthday cake. I realise this may seem like more overhead, since pygame already has a clock class, but for me, I rely on the clock class to provide a nice and friendly way of adjusting framerate, rather than a definitive timepiece for my game. Of course, I could just be spouting bollocks. ~Chris -Original Message- From: [EMAIL PROTECTED] [mailto:[EMAIL PROTECTED] Behalf Of Daniel Nixon Sent: Friday, July 20, 2007 00:20 To: pygame-users@seul.org Subject: [pygame] time progression independent of game "ticks" Hi list, I'm working on a game in which the player looks after a fishtank full of fish. Each fish ages, gestates while pregnant, grows hungrier, etc. For arguments sake lets say 15 minutes = 1 fish year. I want this passage of time to be independent of frame rate and iterations through the main game loop (or do I?). What is the best way to go about such a thing? Use MVC and run the model in its own thread? If that is the case what is the best way to keep track of the passage of actual time within the model? Thanks for reading. -- Regards Daniel Nixon CONFIDENTIAL NOTICE: This email including any attachments, contains confidential information belonging to the sender. It may also be privileged or otherwise protected by work product immunity or other legal rules. This information is intended only for the use of the individual or entity named above. If you are not the intended recipient, you are hereby notified that any disclosure, copying, distribution or the taking of any action in reliance on the contents of this emailed information is strictly prohibited. If you have received this email in error, please immediately notify us by reply email of the error and then delete this email immediately.
Re: [pygame] time progression independent of game "ticks"
The first time I did something like that I made a fish class which did things like get-hungry. Each fish stored its time of creation and time of last feeding, mating, egg-laying etc. Then I kept doing: for every fish: check the time of day, and update the fishes' state based on the time elapsed This worked fine for a few fish. But it did not scale. When I had 10s of thousands of fish, I couldn't get through the whole list of fish before too much time had passsed. My fish were carrying too much state around with them as well. So I changed the design to make my fish schedule 'at this time something interesting will happen to me' events into a queue which was sorted by time. Then, for every bit of time, I only had to see if it was later than or equal to the first item in the queue, and pop things off the queue until the first item on it was 'later than now'. Just in case you run into the same problem that I had. Laura
Re: [pygame] time progression independent of game "ticks"
On 7/20/07, Daniel Nixon <[EMAIL PROTECTED]> wrote: What is the best way to go about such a thing? Use MVC and run the model in its own thread? If that is the case what is the best way to keep track of the passage of actual time within the model? This may or may not help: http://entitycrisis.blogspot.com/2007/07/general-pygame-main-loop.html -- :: Simon Wittber :: http://www.linkedin.com/in/simonwittber :: phone: +61.4.0135.0685 :: jabber/msn: [EMAIL PROTECTED]
Re: [pygame] time progression independent of game "ticks"
"Daniel Nixon" <[EMAIL PROTECTED]> wrote: > What advantage does calling pygame.time.wait() have over simply > lowering the frame rate passed to .tick()? I should really leave this one for folks who have been deeper into the SDL C code, but my understanding is that (at least until recently) for small frame times (frame rates above 30 fps? I don't recall), the tick(framerate) call tries to be accurate - and it accomplishes this by hogging the CPU. The wait() approach, on the other hand, guarantees that your program yields the CPU for a certain amount of time - you don't know when wait() will return, but the clock.tick() function gives you the timing data that you need, anyway. (And, don't worry - it's pretty close to the amount of time you specified, but it might be a little off.) The results of hogging all the CPU for your own process means that other processes end up getting starved for CPU, which isn't a good idea on multi-processing OSes (and who knows what the players are running in the background). All this ends up with a little bit of a counterintuitive practice: to get smooth behavior, call wait(), even though it's unpredictable. It'll average out and be more consistent than trying to manage time too precisely. -Dave LeCompte
Re: [pygame] time progression independent of game "ticks"
I've been using something like myClock.tick(60), but that's for no other reason than 60 seems to be popular in most of the examples I've read. I doubt my game will require such a high frame rate. Aiming for 60fps seems to cause the game to take an entire core for itself, but using your wait time brought that down to about 10% of one core. What advantage does calling pygame.time.wait() have over simply lowering the frame rate passed to .tick()? On 7/20/07, Dave LeCompte (really) <[EMAIL PROTECTED]> wrote: "Daniel Nixon" <[EMAIL PROTECTED]> wrote: > Thanks Ian, Dave. Passing down the milliseconds sounds like the way to > go. Thanks for the great advice. :) Actually, let me refine my suggestion. Back a month or more ago, I kicked off the whole "a CPU is not a saw" thread with a discussion very similar to this, and what I would suggest based on the opinions voiced at that time would be to make sure that you leave a few cycles each frame for the OS. If you're reasonably confident that you can pick a frame rate that the slowest machines can keep up with, and then some, all you'd have to do is pass in the argument to the tick() call: TARGET_FRAME_RATE=25.0 while(gamePlaying): #[see earlier post] myClock.tick(TARGET_FRAME_RATE) If you want to be extra sure to give up a few cycles to the OS, you can add in an explicit delay: TARGET_FRAME_RATE=25.0 WAIT_TIME=5 # number of milliseconds per frame to yield to other processes while(gamePlaying): #[see earlier post] myClock.tick(TARGET_FRAME_RATE) pygame.time.wait(WAIT_TIME) tune these numbers to where you feel comfortable with them. I feel bad plugging my game over and over again, but if you look at the 0.9 version of the code, it wasn't yielding any time to the OS, and sometimes things felt a little uneven. 0.91 and 0.92 are more aggressive about using more CPU-efficient approaches, and I decided to use a 60fps target. The result was much smoother performance. 0.9: http://www.pygame.org/projects/23/415/?release_id=698 0.92: http://www.pygame.org/projects/23/415/?release_id=767 -Dave LeCompte -- Regards Daniel Nixon ABN: 62 535 877 916 phone: 04 0109 8560 email: [EMAIL PROTECTED]
Re: [pygame] time progression independent of game "ticks"
"Daniel Nixon" <[EMAIL PROTECTED]> wrote: > Thanks Ian, Dave. Passing down the milliseconds sounds like the way to > go. Thanks for the great advice. :) Actually, let me refine my suggestion. Back a month or more ago, I kicked off the whole "a CPU is not a saw" thread with a discussion very similar to this, and what I would suggest based on the opinions voiced at that time would be to make sure that you leave a few cycles each frame for the OS. If you're reasonably confident that you can pick a frame rate that the slowest machines can keep up with, and then some, all you'd have to do is pass in the argument to the tick() call: TARGET_FRAME_RATE=25.0 while(gamePlaying): #[see earlier post] myClock.tick(TARGET_FRAME_RATE) If you want to be extra sure to give up a few cycles to the OS, you can add in an explicit delay: TARGET_FRAME_RATE=25.0 WAIT_TIME=5 # number of milliseconds per frame to yield to other processes while(gamePlaying): #[see earlier post] myClock.tick(TARGET_FRAME_RATE) pygame.time.wait(WAIT_TIME) tune these numbers to where you feel comfortable with them. I feel bad plugging my game over and over again, but if you look at the 0.9 version of the code, it wasn't yielding any time to the OS, and sometimes things felt a little uneven. 0.91 and 0.92 are more aggressive about using more CPU-efficient approaches, and I decided to use a 60fps target. The result was much smoother performance. 0.9: http://www.pygame.org/projects/23/415/?release_id=698 0.92: http://www.pygame.org/projects/23/415/?release_id=767 -Dave LeCompte
Re: [pygame] time progression independent of game "ticks"
OK, I agree, it is probably not the most accurate way to do it, I'm assuming that the problem is that the game won't run basically the same speed and cumulative errors aren't relevant (ex: the speed the fish swims won't be exactly the same but close enough). Ian
Re: [pygame] time progression independent of game "ticks"
Thanks Ian, Dave. Passing down the milliseconds sounds like the way to go. Thanks for the great advice. :) On 7/20/07, Dave LeCompte (really) <[EMAIL PROTECTED]> wrote: "Ian Mallett" <[EMAIL PROTECTED]> wrote: > You could try: > "http://www.pygame.org/docs/ref/time.html#pygame.time.Clock"; > with Clock.tick(framerate) which would normalize the speed of the program > on any computer. I wouldn't go about it that way - tick(framerate) tries to achieve the framerate, but if you're running on a slow machine and can only run at 10Hz, calling Clock.tick(20) won't make it catch up. That's even what the documentation says: "By calling Clock.tick(40) once per frame, the program will never run at more than 40 frames per second." Also, read on: "Note that this function uses SDL_Delay function which is not accurate on every platform" A few milliseconds every frame, over 15 minutes, who knows how far out of sync you'll end up? > On 7/19/07, Daniel Nixon <[EMAIL PROTECTED]> wrote: >> >> Hi list, >> >> I'm working on a game in which the player looks after a fishtank full >> of fish. Each fish ages, gestates while pregnant, grows hungrier, etc. >> For arguments sake lets say 15 minutes = 1 fish year. I want this >> passage of time to be independent of frame rate and iterations through >> the main game loop (or do I?). That plan sounds fine to me. The way I do this sort of thing is to create a clock (as suggested by Ian) and read the amount of time each time through the loop takes, and pass that duration down into your simulation code: theClock=pygame.time.Clock() while (gameIsPlaying): frameTime=theClock.tick() processInput() doSim(frameTime) renderFrame() Inside your doSim function, update the game logic based on frameTime going by. It might look a little like this: FISH_DAYS_PER_MILLISECOND=0.0004 fishDays=0 def doSim(milliseconds): fishDays += milliseconds*FISH_DAYS_PER_MILLISECOND And, you should find that after about 15 minutes of the player's time, the fishDays value has climbed up to about 365 days. I also usually have ways to suspend the sim, so that if the user leaves the window, or brings up a pause menu, or whatever, I no longer call the doSim function, which means the game clock isn't counting up. If you want to combine this with Ian's suggestion, and add a frame rate hint to the tick() call, you can, but even if you don't, you should be able to get some good results. -Dave LeCompte -- Regards Daniel Nixon ABN: 62 535 877 916 phone: 04 0109 8560 email: [EMAIL PROTECTED]
Re: [pygame] time progression independent of game "ticks"
"Ian Mallett" <[EMAIL PROTECTED]> wrote: > You could try: > "http://www.pygame.org/docs/ref/time.html#pygame.time.Clock"; > with Clock.tick(framerate) which would normalize the speed of the program > on any computer. I wouldn't go about it that way - tick(framerate) tries to achieve the framerate, but if you're running on a slow machine and can only run at 10Hz, calling Clock.tick(20) won't make it catch up. That's even what the documentation says: "By calling Clock.tick(40) once per frame, the program will never run at more than 40 frames per second." Also, read on: "Note that this function uses SDL_Delay function which is not accurate on every platform" A few milliseconds every frame, over 15 minutes, who knows how far out of sync you'll end up? > On 7/19/07, Daniel Nixon <[EMAIL PROTECTED]> wrote: >> >> Hi list, >> >> I'm working on a game in which the player looks after a fishtank full >> of fish. Each fish ages, gestates while pregnant, grows hungrier, etc. >> For arguments sake lets say 15 minutes = 1 fish year. I want this >> passage of time to be independent of frame rate and iterations through >> the main game loop (or do I?). That plan sounds fine to me. The way I do this sort of thing is to create a clock (as suggested by Ian) and read the amount of time each time through the loop takes, and pass that duration down into your simulation code: theClock=pygame.time.Clock() while (gameIsPlaying): frameTime=theClock.tick() processInput() doSim(frameTime) renderFrame() Inside your doSim function, update the game logic based on frameTime going by. It might look a little like this: FISH_DAYS_PER_MILLISECOND=0.0004 fishDays=0 def doSim(milliseconds): fishDays += milliseconds*FISH_DAYS_PER_MILLISECOND And, you should find that after about 15 minutes of the player's time, the fishDays value has climbed up to about 365 days. I also usually have ways to suspend the sim, so that if the user leaves the window, or brings up a pause menu, or whatever, I no longer call the doSim function, which means the game clock isn't counting up. If you want to combine this with Ian's suggestion, and add a frame rate hint to the tick() call, you can, but even if you don't, you should be able to get some good results. -Dave LeCompte
Re: [pygame] time progression independent of game "ticks"
You could try: "http://www.pygame.org/docs/ref/time.html#pygame.time.Clock"; with Clock.tick(framerate) which would normalize the speed of the program on any computer. Then you wouldn't have to deal with any of the annoying stuff. Of course this means that cutting edge computers would have no faster a fps rate than their slower counterparts. Ian On 7/19/07, Daniel Nixon <[EMAIL PROTECTED]> wrote: Hi list, I'm working on a game in which the player looks after a fishtank full of fish. Each fish ages, gestates while pregnant, grows hungrier, etc. For arguments sake lets say 15 minutes = 1 fish year. I want this passage of time to be independent of frame rate and iterations through the main game loop (or do I?). What is the best way to go about such a thing? Use MVC and run the model in its own thread? If that is the case what is the best way to keep track of the passage of actual time within the model? Thanks for reading. -- Regards Daniel Nixon