I'm pretty much blind when getting crashes like what is the problem? When the program is at the state of rabbits spawning here
rabbitCounter += 1
if rabbitCounter >= NEW_RABBIT:
rabbitCounter = 0
rabbits.append(pygame.Rect(random.randint(0, WINDOW_WIDTH
- RABBIT_SIZE), random.randint (0, WINDOW_HEIGHT - RABBIT_SIZE),
RABBIT_SIZE, RABBIT_SIZE))
It chrashes when I press the space bar to go to the other loop, level 2. I did this so I
could test the game fine but it seems not to work. Hopefully the problem gets found. It hangs the window gets greyed and the "Program has crashed dialog" comes up.
Here's all the files and py.files: https://www.dropbox.com/sh/gqke6hfooz7mbnr/Qm8NMlyNqc
It seems to be these two sections if I take a guess:
#Gris spawning
while pigSpawn == True:
pigCounter += 1
if pigCounter >= NEW_PIG:
pigCounter = 0
pigs.append(pygame.Rect(random.randint(0, WINDOW_WIDTH
- PIG_SIZE), random.randint (0, WINDOW_HEIGHT - PIG_SIZE),
PIG_SIZE, PIG_SIZE))
#Vildsvin spawning
while boarSpawn == True:
boarCounter += 1
if boarCounter >= NEW_BOAR:
boarCounter = 0
boars.append(pygame.Rect(random.randint(0, WINDOW_WIDTH
- BOAR_SIZE), random.randint (0, WINDOW_HEIGHT - BOAR_SIZE),
BOAR_SIZE, BOAR_SIZE))
In level 1 the programmer created 20 pigs, 20 boars etc.. then setup a while-loop that handled events. In that single loop it handled all events (to move the game). Spawned pigs/boars as needed etc..
The code in level 2 just contains a never ending while loop that add more and more pigs.
Probably until you run out of memory. Basically once you are in the pigSpawn loop you just continue to loop forever adding more and more pigs until the program crashes.
Related
I'm using a game engine to make my own 3D game in python. I need to simulate a jump and/or gravity, but I'm running into an issue : either the calcul is immediate and my character isn't moving, like, there's no animation, instant blink, or either (if for exemple I had a bigger number in my for loop) it takes wayyyy more time, really slow, it lags and everything, struggling to calculate the jump. I got both extremes, and none works, so I'd like to find a way to make my jump. All I have at my disposition to do this is :
player.y +=
#can be -=, =, +=, etc.
So, do you got any ideas of ways to do this ? I'm not really asking a specific problem, I'd just like to gather some ideas ! And there's even no need to give predone examples, just throw your ideas, like : use this, try with this formula, this function, etc.
Adding some details : what I already tried.
Here is the main solution I tried, pretty basic :
velocity = 3
def input(key):
global velocity
if key == "space":
for i in range(7):
print(velocity)
player.y += velocity
velocity -= 1
velocity = 3
Which is pretty cool, as you had to your height 3, then 2, then 1 (deceleration as your energy lowers), then you add -1, -2, -3 (acceleration due to gravity), and go back to your starting point. Perfect ! But, as said, instantly done. So if I try this :
velocity = 3
def input(key):
global velocity
if key == "space":
for i in range(61):
print(velocity)
player.y += velocity
velocity -= 0.1
velocity = 3
Again, instantly done. And if I try higher and higher intervals, at some point I just get it to lag, no in-between where it's done correctly
Slightly off-topic: You don't want to name your function input() because it shadows the inbuilt input() function.
The problem is that you change the velocity and then iteratively decrement it inside a loop! Because of the way python (or most programming languages, for that matter) works, the program execution moves on to the "draw on screen" step only after it's finished executing your input() function. So when you press a key, here's what your program is doing:
Draw a frame and listen for keypress
Key pressed! Call input() to handle the keypress (let's assume player.y = 0)
Is the key a space? Enter the loop
velocity = 3. Move player up by 3. Decrement velocity. player.y = 3
velocity = 2. Move player up by 2. Decrement velocity. player.y = 5
... and so on until you exit the loop
player.y is 0 again
Draw another frame. Player is at the same place they started, so it looks like nothing happened.
When you add iterations to your loop, this process takes longer (so you see lag), but essentially the same thing happens.
To fix this, you need to add the effect of gravity inside the function that draws your frames. For example, you could set a flag when the jump key is pressed, and if you had a function step() that was called at each timestep of your simulation, you could check if the flag is set and then handle the situation
def user_input(key):
global jump_velocity, is_player_jumping
if key == "space":
is_player_jumping = True
jump_velocity = 3
def step():
global jump_velocity, is_player_jumping
if is_player_jumping:
player.y += jump_velocity
jump_velocity -= 0.1
if player.y == 0: # Player is back on the ground
is_player_jumping = False
This way, you only change the player's location a little bit before the next frame is drawn, and you can actually see the animation.
You first need to know what is the current time step because if you have 2 ms between your frames and 20 ms your need to adapt the amount you get into the player's y position each step.
then it would be great to have a player velocity variable somewhere in addition to its position. Then you would have to decide on a velocity to add instantly to the player when the jump occurs and each time step adds a bit of acceleration down due to gravity.
I am fairly new to PyGame and I am creating a space shooter game. Part of this game are powerups and when a specific powerup is picked up by the player, I want the player not to be able to shoot for 3 seconds. Shooting is done by mouse click.
I can pick up the powerup, I know what powerup the player last picked up, but I am struggling with the event. How I am thinking of implementing is:
Can't Shoot power up is picked up -> that's done
Block mouse buttons
Wait 3 seconds, while the rest of the game is still running
Unblock mouse buttons.
I am aware that Python functions, such as wait, won't help.
Any ideas/suggestions?
Thanks
When you call clock.tick() it returns time since the last call. So save that time: dt = clock.tick() and then use that variable to count down your seconds.
Example:
dt = clock.tick() # only call once per iteration
if attack_blocked:
attack_block_count += dt
if attack_block_count >= 3000: # dt is in ms
attack_blocked = False
Example 2:
while True:
dt = clock.tick(60)
for event....
if block_attack_power_up:
attack_blocked = True
attack_block_count = 0
if not attack_blocked:
# do your attack
if attack_blocked:
attack_block_count += dt
if attack_block_count >= 3000:
attack_blocked = False
I'm trying to do a chess clock using tkinter, and to do so i'm using the root.after method from the class Tk of tkinter. When the program starts, it runs really well, but after a while the clock start to get slower and slower, but if i start shaking my mouse, the clock starts to run fast again. For a clock, time precision is crucial, so i can't afford to run the program in the way that is working now. How can i solve this problem?
def RunClock(self):
"""
Method that runs and change the clock info
"""
#t0 = time.time()
if self.playing:
#Time remaining in milliseconds
clock = self.clock
minutes = clock//60000
clock %= 60000
sec = clock//1000
clock %= 1000
mil = clock//10
#If the turn is of player 1
if self.turn == 1:
self.WriteClock(self.canvas1, self.play1, "%.2i:%.2i:%.2i"%(minutes, sec, mil))
else:
self.WriteClock(self.canvas2, self.play2, "%.2i:%.2i:%.2i"%(minutes, sec, mil))
#tf = time.time()
#deltat = (tf - t0)
#s = 1 - deltat
self.rel -= 1
#if s > 0:
# time.sleep(s/1000)
#else:
# self.rel += s*1000
self.root.after(1, self.RunClock)
Note: The time to run the function is very low (you can calculate it with the commented tf and t0 variables), so i didn't even consider it in the time interval
As Brian pointed out reducing the time interval will likely be the easiest solve to your question. Alternately though, you could try running your timer separately on it's own thread and having it run asynchronously and send it threading events as is discussed here:
Python threading.timer - repeat function every 'n' seconds
I am building a space invaders style game in Pygame. The enemies come in one at a time, and each loop sounds associated with them (this is for a psychology experiment in auditory learning, actually)
I want to put a 5 second delay in the game after a character is killed--so, when one character is shot, their sound fades out quickly, and the player must wait 5 seconds for the onset of the next character + sound
This is the script I have within my Game class, for generating enemies one at a time. I am using the core module from psychopy to measure time, but I can't seem to figure out how to delay the enemy onset without freezing the game (i.e. still allowing the player to move between onsets):
if len(self.enemyA_list) == 0 and len(self.enemyB_list) == 0 and len(self.enemyC_list) == 0:
self.enemy = Enemy()
#Increase speed, variability of character onset based on how many characters have been created
if len(self.dead_enemies) == 2 or len(self.dead_enemies) == 3:
self.enemy.x_speed *= 1.75
self.enemy.y_speed *= 1.75
elif len(self.dead_enemies) == 4:
self.enemy.x_speed *= 2
self.enemy.y_speed *= 2
timer = core.Clock()
timer.add(2)
if timer.getTime()>=0:
timer = 0
self.enemy.generate() #generate enemy offscreen and start playing sound
if self.enemy.enemy_type == 'A':
self.enemyA_list.add(self.enemy)
self.enemy.sound.out() #play enemy sound
self.enemy.env.play()
if self.enemy.enemy_type == 'B':
self.enemyB_list.add(self.enemy)
self.enemy.sound.out()
self.enemy.env.play()
if self.enemy.enemy_type == 'C':
self.enemyC_list.add(self.enemy)
self.enemy.sound.out()
self.enemy.env.play()
self.all_sprites_list.add(self.enemy)
In your main game loop you should just create a variable keeping track of how much time there has been since the last spawn.
Declare a variable.
lastTime = 0
Then you add 1 to lastTime each time through the loop.
lastTime += 1
Then you need to check how long it's been since the last time one spawned. Also you need to decide how many seconds you want between the spawns.
So...
if timeElapsed == FPS * secondsBetweenSpawns:
generateEnemy()
This will delay each spawn. Please note that this will require an FPS and an FPSClock.
I am a high school programming student and I have a small question. I have been tasked with writing a simple game in Tkinter where an icicle falls from the ceiling and you have to avoid it with your mouse. Simple enough. However, I have hit an issue. Whenever I run a loop in a Tkinter application, it won't open. I've tried with a for loop that pauses every .5 seconds using time.sleep() and the window opens as soon as the loop finishes. Is there some special thing I need to do to make loops work in Tkinter?
from Tkinter import *
import time
import random
class App:
def __init__(self, parent):
self.frame = Frame(root, bg= '#1987DF', width=800, height=800)
self.frame.bind("<Motion>", self.motionevent)
self.frame.pack()
#self.run()
def randhex(self):
b = "#"
for i in range(1, 7):
a = random.randint(0, 15)
if a == 10:
a = "A"
elif a == 11:
a = "B"
elif a == 12:
a = "C"
elif a == 13:
a = "D"
elif a == 14:
a = "E"
elif a == 15:
a = "F"
b = b+str(a)
return b
def motionevent(self, event):
xpos, ypos, bg = event.x, event.y, self.randhex()
str1 = "X : %d Y : %d BG : %s" % (xpos, ypos, bg)
root.title(str1)
x,y, delta = 100, 100, 10
self.frame.config(bg=bg)
def run(self):
for i in range(0, 10):
time.sleep(.5)
print 'i'
self.frame.config(bg=self.randhex())
root = Tk()
app = App(root)
root.mainloop()
Currently all it is supposed to do is change the background when the mouse moves. When the line in init that says self.run() is uncommented it will print 'i' 10 times then the window will open. Help?
Writing an event based program is not the same as writing traditional programs. There is already an infinite loop running, and like any infinite loop, if you place another loop inside, the outer loop can't continue until the inner loop finishes. Since the outer loop is what causes the screen to refresh and events to be processed, inner loops effectively freeze your app until they are done.
Since there is already a loop running you don't need to create another loop. All you need to do is add little jobs to the event queue one at a time. Each job is, in effect, one iteration of your inner loop.
For example, if you wanted to write an inner loop like this:
for i in range(10):
print "i:", i
... you would instead add an event to the event queue and each time the event loop iterates (or more precisely, each time it finishes processing any other events) it will do one iteration of your loop. You do it like this:
def do_one_iteration(i):
print "i:", i
if i < 9:
root.after_idle(do_one_iteration, i+1)
Then, after the first time you call do_one_iteration, it will place the next iteration of itself on the event queue, and continue to do so until it decides it is done.
Typically you would call do_one_iteration when the user presses a button (eg: the "start" button). Call it once, then it does one bit of work (ie: moving the icicle down a couple of pixels) and then reschedules itself.
In game development you might have a function called update_display which is in charge of redrawing everything. It could, for example, subtract 1 from the Y coordinate of each icicle. You can add bindings for the left and right arrows to move the player (by incrementing or decrementing the X coordinate), and your update function would use these new coordinates to redraw the player.
By the way, you can slow down your program by using after instead of after_idle to call the function after a slight delay. This delay can be used to control the frame rate. For example, assuming the update is nearly instantaneous (and it probably will be in your case), calling after with an argument of 41 (milliseconds) yields a framerate of approximately 24 fps (24 frames times 41 milliseconds equals 984 milliseconds, or roughly 24 frames per second)
It may sound complicated but it's really pretty easy in practice once you do it once or twice.