hi i am beginner in programming and pygame
and i was trying to make game like this
http://dan-ball.jp/en/javagame/dust/
and i started by making this simple code
import pygame
from pygame.locals import*
import os
os.environ['SDL_VIDEO_WINDOW_POS'] = "%d,%d" % (0,25)
pygame.init()
screen=pygame.display.set_mode((1360,705))
clock = pygame.time.Clock()
boxs=[]
while True :
screen.fill((0,0,0))
for event in pygame.event.get():
if event.type==QUIT :
pygame.quit()
quit()
if event.type== pygame.MOUSEBUTTONDOWN:
if event.button == 1:
mous=pygame.math.Vector2(event.pos[0]-4,event.pos[1]-4)
boxs.append(mous)
if event.type== pygame.MOUSEBUTTONDOWN:
if event.button == 3:
print (len(boxs))
for i in range(len(boxs)):
if ((boxs[i])[1])>=685:
pass
else:
(boxs[i])[1]=(boxs[i])[1]+2
for v in range (len(boxs)):
if v==i:
pass
else :
if (int((boxs[i])[1]))+4 >= (int((boxs[v])[1])) and (int((boxs[i])[1])) <= (int((boxs[v])[1]))+4 and (int((boxs[i])[0]))+4 >= (int((boxs[v])[0])) and (int((boxs[i])[0])) <= (int((boxs[v])[0]))+4:
(boxs[i])[1]=(boxs[i])[1]-2
break
pygame.draw.rect(screen,(250,250,250),((boxs[i])[0],(boxs[i])[1], 4, 4))
pygame.display.update()
clock.tick(60)
it works very good as start but my problem is that when the boxes became more the 350 or 400 the game will be lagging too much i dont know what iam doing wrong
and sorry if i was asking too much bad questions but thank you so much i have learned so much from you guys
I notice that you're doing this:
if ((boxs[i])[1])>=685:
pass
That means that you're never deleting boxes that go off the bottom of the screen, so as time goes by, your box list is getting larger and larger, which is going to eventually lead to lag.
You're also using Pygame vectors for your list, and then not taking advantage of them. For example, instead of:
(boxs[i])[1]=(boxs[i])[1]+2
you can say:
boxs[i].y += 2
Finally, you are not looping in a Pythonic way. In Python, you almost never need to loop with an index variable. Instead, you should be doing something like this:
for box in boxs:
if box.y >= 685:
pass
else:
box.y += 2
for other in boxs:
if other == box:
pass
and so on...
Finally, you should be using pygame Rect() objects, because then you can use the builtin pygame collision functions to easily handle your collisions.
http://www.pygame.org/docs/ref/rect.html
Related
I have made some little games with the pygame module and it had been fun. However, right now i´m trying to move the character with a piano via midi using pygame.midi. there´s the problem. I did it but not in the way i wanted to because
the character moves sometimes and other it doesn´t. I think i know where is the problem: If i understand correctly, the pygame.event.get() function "catch" the events always, it does not matter when (inside the main loop of the game), so i think that with my code this is not happening, i mean, i believe that the player not always do what is supposed to do because the midi input has to be in a specific "time" not as pygame.event.get(). I looked into the pygame documentation and there seems to be a function that does the trick: pygame.midi.midis2events(), but i don´t know how to use it.The question is just:
How can i move the character through the piano via midi with pygame in order that the character moves everytime?
import pygame as pg, pygame.midi
WIDTH = 800
HEIGHT = 600
FPS = 60
BLACK = (0,0,0)
BLUE = (0,0,255)
pg.init()
pg.midi.init()
screen = pg.display.set_mode((WIDTH,HEIGHT))
pg.display.set_caption('STACKOVERFLOW_EXAMPLE_MIDI')
clock = pg.time.Clock()
running = True
inp = pg.midi.Input(1)
x = WIDTH//2
y = HEIGHT//2
speedx = 0
midi_list = []
while running:
clock.tick(FPS)
if inp.poll():
midi_value = inp.read(1000)[0][0][1]
if midi_value==57:
midi_list.append(midi_value)
if len(midi_list)==1:
speedx = -1
else:
speedx = 0
midi_list = []
if midi_value == 63:
running = False
x = x+speedx
screen.fill(BLUE)
pg.draw.rect(screen,BLACK,[x,y,50,60])
pg.display.update()
pg.display.flip()
pg.quit()
I need that the player moves to the left (or to the right) when the piano´s key A3 (a specific note) is being pressed and that the player stops moving when
the key has been released. In this particular fragment of the code, but also to do things like press a piano´s key an shoot one bullet regardless of whether is being pressed or not, in short, to do the same things i can do with the keyboard events.
ok! i found and answer that works well for the time being:
if inp.poll():
s(0.1)
midi_values = inp.read(1000)
for midi in midi_values:
midi_value = midi[0][1]
#Movement to the left
if midi_value==57:
midi_list.append(midi_value)
if len(midi_list)==1:
speedx = -50
Modifying the code in order to iterate the list midi_values gives me the correct input-output response without the inestability which i experienced. Also i did introduce a sleep(0.1) delay and works well without to much cpu use. I found the answer here:
https://www.reddit.com/r/learnpython/comments/36dxu9/python_whileloop_cpu_demanding/
The only problem which i find now is that the pygame window stops with the message no responde (doesn´t respond or something similar) and it stops working.
For example the cube which i´m moving with the keys of the piano doesn´t do anything but the key to close the program does work fine!!
I am struggling with a problem I can't solve.
I want to change the image of my character when the enemy hurts it.
In pseudocode, it would be like this:
*If enemy collides -> player close eyes and get red;*
*After 0.50 seg -> player gets normal back again*
I tried to do it with Clock and Timers but it is very difficult. I only get changing the image, but not getting it back.
Any ideas?
Thank you!
I would assume it's as easy as this. pygame.time.set_timer(x, y) basically creates an x event on the event stack every y milliseconds.
# Main game loop
while True:
# display stuff and other parts of your game
# replace this with whatever detection you have for collision
if enemycollide:
player.setSprite(1)
pygame.time.set_timer(14, 500) # 500 milliseconds = .5 seconds
# event handling
for event in pygame.event.get():
if event.type == 14:
player.setSprite(0)
pygame.time.set_timer(14, 0) # Disable the timer
I've been looking for an answer to a question I've been having, and to be honest this is the first time in the ten months that I couldn't find an answer. I've looked at multiple questions, Dictionaries do work, this conclusion was found in error(and I tried to use dictionaries(which most of the answers suggest), but they haven't worked.) The only other answers I could find was to use exec(), but they always seem to be accompanied by a comment saying they're dangerous, so I've steered clear of them.
On to my question:
This is an example of the code that I've been working on in Pygame:
import pygame,sys
from pygame.locals import *
pygame.init()
screen = pygame.display.set_mode((800,230))
pygame.display.set_caption('Example')
tickclock = pygame.time.Clock()
change = 1
car1 = pygame.image.load('Car1.png')
car2 = pygame.image.load('Car2.png')
while True:
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
elif event.type == KEYDOWN:
if event.key == K_ESCAPE:
pygame.quit()
sys.exit()
elif event.key == K_SPACE:#To change the picture when the user presses space
change = change + 1
#Current way-----#
if change == 1:
screen.blit(car1,(0,0))
elif change == 2:
screen.blit(car2,(0,0))
#Continue until all pictures are used...
elif change > 2:#The 2 will change based on the amount of pictures.
change = 1
#----------------#
pygame.display.flip()
tickclock.tick(60)
Where it is commented as "current way" is where my question is. Using this message of if/elif statements can take up a tun of lines if there are a lot of pictures for Pygame to display, and that would be doubled by the need to call screen.blit() every after every if/elif statement.
This is an example of what I would like to do:
import pygame,sys
from pygame.locals import *
pygame.init()
screen = pygame.display.set_mode((800,230))
pygame.display.set_caption('Example')
tickclock = pygame.time.Clock()
varcar = 'car'
varnum = '1'
car1 = pygame.image.load('Car1.png')
car2 = pygame.image.load('Car2.png')
while True:
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
elif event.type == KEYDOWN:
if event.key == K_ESCAPE:
pygame.quit()
sys.exit()
elif event.key == K_SPACE:#To change the picture when the user presses space
varnum = int(varnum)
varnum = varnum + 1
varnum = int(varnum)
#Using this to substitute the class I set up for the actual file--#
varcombined = varcar + varnum#To make varcombined = 'car1','car2',etc.
if varnum > 2:#To keep varnum within the loaded image numbers
varnum = 1
#-----------------------------------------------------------------#
#The way I wish to use--------------------------------------------#
#Some Code
screen.blit(varcombined,(0,0))
pygame.display.flip()
tickclock.tick(60)
What I am trying to do here is combine the varcar and varnumber variable so that I can combine them in the varcombined variable while only changing the varnumber variable. This will give strings that are the same as the variable names of the loaded images: car1 and car2. Then what I want to do is somehow call the variables car1 and car2 in 'screen.blit(varcombined,(0,0))' on line 31 by using the string as a substitute to the actual variable name. (Without actually having to dynamicly create a new variable)
Is there a way this can be done, and if so, how can it be done?
Even though the question may seem a bit specific, I think this can benefit a lot of people who may have a need/want to use a string to call a variable.
If anyone doesn't understand what I'm asking, just say so, and I'll try to edit the question to clarify.
EDIT
Thank you to abarnert and Fernando Aires for their speedy answers. :)
I'm not sure if I should make this an edit or another question, but I need to expand my question a little due to recent issues.
I used abarnert's answer, and it worked like a charm.
car_dictionary = {1: car1 2: car2}
#-----------#
screen.blit(car_dictionary[change], (0,0))
I would now like to ask, what I should do in the case that I added a 'truck1' and 'truck2' image, and now needed to not only interchange between 1 and 2 but also car and truck?
If there's a way to do that of course.
So, what you want here is some way to get car1 or car2 depending on whether change is 1 or 2. And, ideally, to be able to expand this to car73 without writing a chain of 73 elif statements.
While it's possible to do this by constructing the variable names and then looking them up in the appropriate global/local/object scope (e.g., vars()['car{}'.format(change)]), this is a very bad idea, for lots of reasons.
The right way to do this is to store the cars in a dictionary, keyed by the varnum values:
cars = {1: car1, 2: car2}
Or, even better, load the cars directly into the dictionary with a loop, and don't even create the separate variables in the first place (which would get really tedious when you have 73 cars):
cars = {}
for num in range(1, 3):
car = pygame.image.load('Car{}.png'.format(num))
cars[num] = car
Or, more simply:
cars = {num: pygame.image.load('Car{}.png'.format(num)) for num in range(1, 3)}
Now, to look up a car by its key, that's just cars[change]. In particular, your code becomes:
screen.blit(cars[change], (0.0))
It's worth noting that in your existing code, the keys aren't really doing anything after load time. They're just contiguous integers, and you just start at the first one, count up one by one, and roll back to the first one whenever you reach the end. If that's true in your real code, you don't even really need a dictionary here, just a list; the only change you need to make is to start counting from 0 instead of from 1.
change = 0
cars = [pygame.image.load('Car{}.png'.format(num)) for num in range(1, 3)]
And if the only thing you need change for is to pick a car, you can simplify this even further by getting rid of change, too. You just want to iterate over cars, repeating forever. itertools.cycle makes that a one-liner. Instead of while True:, you can do this:
for car in itertools.cycle(cars):
And then, instead of cars[change] you just use car.
You could use a dictionary for that, as in:
car1 = pygame.image.load('Car1.png')
car2 = pygame.image.load('Car2.png')
...
screen.blit( {"car1": car1, "car2": car2}[varcombined], (0,0))
Or you could even replace your varcombined with a carNumber variable, for instance - and therefore changing your dictionary to {1: car1, 2: car2}.
Hope that helps.
basically, at the moment, in my game the user can shoot as many times as they wish... this defeats the objective of the game (it makes it too easy) as they can just spam bullets. I have a 'Shop' type function which enables the user to purchase upgrades, therefore the spamming defeats the purpose of the shop.
elif event.key == K_SPACE:
newBullet = {'rect': pygame.Rect(bulletX, bulletY, 10, 3), 'surface': bullet}
pistolSound.play()
bullets.append(newBullet)
This is the code, what can I add to it in order prevent the button mashing spam. I'm bad with the pygame time function, but I have a feeling that could be used.
Additionally, i would like to my zombies to spawn consistently instead of at the moment where it is quite random...
timer = clock.tick()
if waveNumber <= 2:
timer += 1
if timer == 2:
newZombie = {'rect':pygame.Rect(zombieX, zombieY, 75, 75), 'surface': zombie}
zombieSound.play()
zombies.append(newZombie)
timer = 0
How would I go about doing this? I think I'm using the time function wrong.
Many thanks, Will.
Limit the number of bullets to some small number:
elif event.key == K_SPACE:
if len(bullets) < 3:
newBullet = {'rect': pygame.Rect(bulletX, bulletY, 10, 3), 'surface': bullet}
pistolSound.play()
bullets.append(newBullet)
You should break your simulation and event handling into brief "turns" and allow the player to shoot only one bullet per turn (or even less).
The closest to your code example would be setting a "shot button pressed this turn" flag when the appropriate kind of event is processed, then after all events have been processed shooting at most once:
#each event
if event.key == K_SPACE:
playerShooting=True
...
#each turn
if playerShooting:
newBullet = {'rect': pygame.Rect(bulletX, bulletY, 10, 3), 'surface': bullet}
pistolSound.play()
bullets.append(newBullet)
playerShooting=False#clear to prepare for next turn
Zombies have a similar problem: you cannot predict the value of clock.tick(). Instead, spawn zombies at most once per turn (likely on a schedule, e.g. every fifth turn). The clock should be used to decide whether the main loop should proceed to game state update instead of waiting for further inputs, and to decide when to render frames.
For reference, a bad example and a good but incomplete example of PyGame main loops.
I've been following a tutorial "McGugan - Beginning Game Development with Python and Pygame (Apress, 2007)" and in the code at around chapter five involving object movement I keep getting invalid syntax alerts on '-' being used in the code. It isn't up to date but I would've thought a subtract wouldn't be changed in any updates due to its simplicity and necessity.
This is the code I have:
background_image_filename = 'sushiplate.jpg'
sprite_image_filename = 'fugu.png'
import pygame
from pygame.locals import *
from sys import exit
from gameobjects.vector2 import Vector2
pygame.init()
screen = pygame.display.set_mode((640, 480), 0, 32)
background = pygame.image.load(background_image_filename).convert()
sprite = pygame.image.load(sprite_image_filename).convert_alpha()
clock = pygame.time.Clock()
position = Vector2(100.0, 100.0)
speed = 250.
heading = Vector2()
while True:
for event in pygame.event.get():
if event.type == QUIT:
exit()
if event.type == MOUSEBUTTONDOWN:
destination = Vector2(*event.pos) – Vector2(*sprite.get_size())/2.
heading = Vector2.from_points(position, destination)
heading.normalize()
screen.blit(background, (0,0))
screen.blit(sprite, position)
time_passed = clock.tick()
time_passed_seconds = time_passed / 1000.0
distance_moved = time_passed_seconds * speed
position += heading * distance_moved
pygame.display.update()
am I doing something wrong or is it just simply outdated?
Any help is much needed.
In this line:
destination = Vector2(*event.pos) – Vector2(*sprite.get_size())/2.
You somehow typed the character "–" (EN DASH) instead of "-" (HYPHEN-MINUS).
Use "-" (HYPHEN-MINUS) instead, like this:
destination = Vector2(*event.pos) - Vector2(*sprite.get_size())/2.
I can't be sure without a stack trace, but I have a hunch that it's the wrong - symbol. What editor are you using? Is it possible that your editor is taking the - symbol and turning it into a fancier dash, like an ndash or an mdash?
Maybe try changing speed to "speed = 250.0". I don't know if that dangling dot would throw python off.
What is going on here, with your error message at least, is the Python parser is stumbling over something before your '-', which screws up its interpretation of '-'. So I recommend looking before the '-' for typos.
Also, make sure you turn on visible white space in your editor when debugging Python code. This could be a white space error, which would be invisible to us at Stack Overflow.
EDIT:
So I was completely wrong about that '-' error being a red herring. But keep that parser behavior in mind/white space thing in mind, could help in the future.
Apologies if this is obvious to you, I don't know what level you are at with Python.