I'm trying to get the camera to move, but it's not having any effect when I click q w e a s or d. I tried asking the original programmer, but that came to nought, so I don't know what to do.
Code:
import pygame, sys, math
class Cam:
def __init__(self,pos=(0,0,0),rot=(0,0)):
self.pos = list(pos)
self.rot = list(rot)
def update(self,dt,key):
s = dt*10
if key[pygame.K_q]: self.pos[1]-=s
if key[pygame.K_e]: self.pos[1]+=s
if key[pygame.K_w]: self.pos[2]+=s
if key[pygame.K_s]: self.pos[2]-=s
if key[pygame.K_a]: self.pos[0]-=s
if key[pygame.K_d]: self.pos[0]+=s
pygame.init()
w,h = 400,400; cx,cy = w//2,h//2
screen = pygame.display.set_mode((w,h))
clock = pygame.time.Clock()
verts = (-1,-1,-1,),(1,-1,-1),(1,1,-1),(-1,1,-1),(-1,-1,1),(1,-1,1),(1,1,1),(-1,1,1)
edges = (0,1),(1,2),(2,3),(3,0),(4,5),(5,6),(6,7),(7,4),(0,4),(1,5),(2,6),(3,7)
cam = Cam((0,0,-5))
while True:
dt = clock.tick()/1000
for event in pygame.event.get():
if event.type == pygame.QUIT: pygame.quit(); sys.exit()
screen.fill((255,255,255))
for edge in edges:
points = []
for x,y,z in (verts[edge[0]],verts[edge[1]]):
x-=cam.pos[0]
y-=cam.pos[1]
z-=cam.pos[2]
f = 200/z
x,y = x*f,y*f
points+=[(cx+int(x),cy+int(y))]
pygame.draw.line(screen,(0,0,0),points[0],points[1],1)
pygame.display.flip()
key = pygame.key.get_pressed()
cam.update(dt,key)
You've forgotten to properly indent the last two lines.
import pygame, sys, math
class Cam:
def __init__(self,pos=(0,0,0),rot=(0,0)):
self.pos = list(pos)
self.rot = list(rot)
def update(self,dt,key):
s = dt*10
if key[pygame.K_q]: self.pos[1]-=s
if key[pygame.K_e]: self.pos[1]+=s
if key[pygame.K_w]: self.pos[2]+=s
if key[pygame.K_s]: self.pos[2]-=s
if key[pygame.K_a]: self.pos[0]-=s
if key[pygame.K_d]: self.pos[0]+=s
pygame.init()
w,h = 400,400; cx,cy = w//2,h//2
screen = pygame.display.set_mode((w,h))
clock = pygame.time.Clock()
verts = (-1,-1,-1,),(1,-1,-1),(1,1,-1),(-1,1,-1),(-1,-1,1),(1,-1,1),(1,1,1),(-1,1,1)
edges = (0,1),(1,2),(2,3),(3,0),(4,5),(5,6),(6,7),(7,4),(0,4),(1,5),(2,6),(3,7)
cam = Cam((0,0,-5))
while True:
dt = clock.tick()/1000
for event in pygame.event.get():
if event.type == pygame.QUIT: pygame.quit(); sys.exit()
screen.fill((255,255,255))
for edge in edges:
points = []
for x,y,z in (verts[edge[0]],verts[edge[1]]):
x-=cam.pos[0]
y-=cam.pos[1]
z-=cam.pos[2]
f = 200/z
x,y = x*f,y*f
points+=[(cx+int(x),cy+int(y))]
pygame.draw.line(screen,(0,0,0),points[0],points[1],1)
pygame.display.flip()
# these two lines should be inside the `while` loop
key = pygame.key.get_pressed()
cam.update(dt,key)
Related
I'm working on a space shooting game and I want my gun to emit a cluster of particles every time it fires. I tried creating a class for the model of one particle and another class to apply this to 50 particles. Everything was pretty good since there was no syntax error, yet the code did not work. This is my code:
import pygame, sys, random
CLOCK = pygame.time.Clock()
pygame.init()
Screen = pygame.display.set_mode((500,500))
class FireParticles_system:
def __init__(self,pos):
self.particles = []
self.pos_x, self.pos_y = pos[0], pos[1]
self.radius = 5
def emit (self,Screen):
for particle in self.particles:
particle[0][0] += particle[2][0]
particle[0][1] += particle[2][1]
if random.randint(0,100)< 60:
particle[1] -= 0.1
pygame.draw.circle(Screen,(255,255,255),particle[0],int(particle[1]))
def add_particles(self):
vx, vy = random.randint(10,0)*.1, random.randint(-2,2)
self.particles.append[[self.pos_x,self.pos_y],self.radius,[vx,vy]]
class Fire:
def __init__(self,pos):
self.particles = []
for i in range(50):
self.particles.append(FireParticles_system(pos))
def update(self,Screen):
for i in self.particles:
i.emit(Screen)
self.particles = [particle for particle in self.particles if particle.radius > 0]
fire = []
while True:
Screen.fill((0,0,0))
mouse_x, mouse_y = pygame.mouse.get_pos()
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
if event.type == pygame.MOUSEBUTTONDOWN:
if event.button == 1:
f = Fire([mouse_x, mouse_y])
fire.append(f)
for i in range(len(fire)):
if len(fire[i].particles) > 0:
fire[i].update(Screen)
pygame.display.update()
CLOCK.tick(60)
I could not spot any problems. Pls, help me T.T
FireParticles_system has a list of particles. However Fire needs just 1 particle system:
import pygame, sys, random
CLOCK = pygame.time.Clock()
pygame.init()
Screen = pygame.display.set_mode((500,500))
class FireParticles_system:
def __init__(self,pos):
self.particles = []
self.pos_x, self.pos_y = pos[0], pos[1]
self.radius = 5
def emit (self,Screen):
for particle in self.particles:
particle[0][0] += particle[2][0]
particle[0][1] += particle[2][1]
particle[1] -= 0.1
pygame.draw.circle(Screen,(255,255,255),particle[0],int(particle[1]))
def add_particles(self):
vx, vy = random.randint(0, 10), random.randint(-2,2)
self.particles.append([[self.pos_x,self.pos_y],self.radius,[vx,vy]])
class Fire:
def __init__(self,pos):
self.particles_system = FireParticles_system(pos)
def update(self,Screen):
self.particles_system.add_particles()
self.particles_system.emit(Screen)
fire = []
while True:
Screen.fill((0,0,0))
mouse_x, mouse_y = pygame.mouse.get_pos()
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
if event.type == pygame.MOUSEBUTTONDOWN:
if event.button == 1:
f = Fire([mouse_x, mouse_y])
fire.append(f)
for i in range(len(fire)):
fire[i].update(Screen)
pygame.display.update()
CLOCK.tick(60)
I'm making chess in pygame, but the pieces don't blit onto the surface for them. How could I fix this?
import pygame
pygame.init()
size = (600,600)
screen = pygame.display.set_mode(size)
pygame.display.set_caption("chess")
clock = pygame.time.Clock()
chessboard = pygame.image.load("chess_board.png")
whitepawn = pygame.image.load("whitepawn.png")
blackpawn = pygame.image.load("blackpawn.png")
class pawn(pygame.sprite.Sprite):
def __init__(self,colour,x,y):
self.x = x
self.y = y
moved = False
self.colour = colour
pygame.sprite.Sprite.__init__(self)
self.im = pygame.surface.Surface((75,75))
def showpiece(self):
if self.colour == "white":
pygame.Surface.blit(self.im,whitepawn,(self.x,self.y))
elif self.colour == "black":
pygame.Surface.blit(self.im,blackpawn,(self.x,self.y))
num1 = 0
pawns = []
for i in range (8):
pawns.append(pawn("black",0+num1,75))
pawns.append(pawn("white",0+num1,450))
num1 += 75
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
screen.blit(chessboard,[0,0])
for n in range (len(pawns)):
pawns[n].showpiece()
pygame.display.flip()
clock.tick(60)
Also what is the point in clock.tick? I know it controls fps, but why does that need limiting?
You have to blit the Sprites on the display Surface (screen):
class pawn(pygame.sprite.Sprite):
# [...]
def showpiece(self):
if self.colour == "white":
screen.blit(whitepawn, (self.x,self.y))
elif self.colour == "black":
ecreen.blit(blackpawn, (self.x,self.y))
I suggest to use pygame.Rect to store the positions of the pieces:
import pygame
pygame.init()
size = (600,600)
screen = pygame.display.set_mode(size)
pygame.display.set_caption("chess")
clock = pygame.time.Clock()
chessboard = pygame.image.load("chess_board.png")
whitepawn = pygame.image.load("whitepawn.png")
blackpawn = pygame.image.load("blackpawn.png")
class pawn(pygame.sprite.Sprite):
def __init__(self, colour, image, x, y):
pygame.sprite.Sprite.__init__(self)
self.colour = colour
self.image = image
self.rect = self.image.get_rect(topleft = (x, y))
def showpiece(self, surf):
surf.blit(self.image, self.rect)
pawns = []
for i in range(8):
pawns.append(pawn("black", blackpawn, i*75, 75))
pawns.append(pawn("white", whitepawn, i*75, 450))
run = True
while run :
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
screen.blit(chessboard, (0, 0))
for p in pawns:
p.showpiece(screen)
pygame.display.flip()
clock.tick(60)
pygame.quit()
I'm creating a memory card game, but having difficulty updating each boxes' rect starting positions. First for loop loads each image and the second get's the starting position for each one. When I do a collision test, it only answers to <0,125,0,175> as my rect position's aren't updating. How can I update this?
import pygame, sys
from pygame.locals import *
screen_height = 800
screen_width = 800
card_x_size = 125
card_y_size = 175
marginx = 45
marginy = 25
class Box():
def __init__(self,image):
self.image = image
self.rect = image.get_rect()
def draw(self,screen):
screen.blit(self.image, self.rect)
def play_game():
pygame.init()
screen = pygame.display.set_mode((screen_width, screen_height))
back_images = ['back.jpg']*16
back_image_list = []
for back_image in back_images:
back_pic = pygame.image.load(back_image)
back_pic = pygame.transform.scale(back_pic, (card_x_size,card_y_size))
back_image_list.append(back_pic)
rect = back_pic.get_rect()
boxes = [Box(img) for img in back_image_list]
for j, box in enumerate(boxes):
pos_x = marginx + j % 4 * available_spacex
pos_y = marginy + j // 4 * available_spacey
box.rect.topleft = (pos_x, pos_y)
print(pos_x,pos_y)
while True:
mouse_clicked = False
clicked_card = False
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
elif event.type == MOUSEMOTION:
mousex, mousey = event.pos
elif event.type == MOUSEBUTTONUP:
mouse_clicked = True
print(mousex, mousey)
if rect.collidepoint(mousex,mousey):
clicked_card = True
print("hit")
for b in boxes:
b.draw(screen)
pygame.display.update()
play_game()
You have to evaluate whether the mouse click is on one of the box objects:
for box in boxes:
if box.rect.collidepoint(mousex, mousey):
clicked_card = True
print("hit")
function play_game:
def play_game():
# [...]
while True:
mouse_clicked = False
clicked_card = False
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
elif event.type == MOUSEMOTION:
mousex, mousey = event.pos
elif event.type == MOUSEBUTTONUP:
mousex, mousey = event.pos
mouse_clicked = True
print(mousex, mousey)
for box in boxes:
if box.rect.collidepoint(mousex, mousey):
clicked_card = True
print("hit")
for b in boxes:
b.draw(screen)
pygame.display.update()
I just started learning Pygame and I'm doing a little game (school project), where using mouse I can click on the image and drag it. There are a lot of images, so my question is how I can identify what image is chosen. Thank you!
Here are some code:
def Transformation(element):
element = pygame.transform.scale(element,(50,75))
fire = pygame.image.load("ElementIcon/fire.png").convert_alpha()
Transformation(fire)
fire.set_colorkey(BLACK)
fire_rect = fire.get_rect()
earth = pygame.image.load("ElementIcon/earth.png").convert_alpha()
Transformation(earth)
earth.set_colorkey(BLACK)
earth_rect = earth.get_rect()
while not done:
screen.fill(WHITE)
#Update the screen with drawings
screen.blit(fire,(408,450))
screen.blit(earth,(419, 350))
mouse_pos = pygame.mouse.get_pos()
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
print("User quits the game :(")
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
done = True
print("Game stopped early by user :( ")
if event.type == pygame.MOUSEBUTTONDOWN:
print mouse_pos
print fire_rect
if fire_rect.collidepoint(mouse_pos):
print "over fire"
if earth_rect.collidepoint(mouse_pos):
print "mama"
When I try to print fire_rect I get <0,0,62,75>
Have a play with this code:
import pygame
from pygame.locals import *
pygame.init()
screen = pygame.display.set_mode((600,600))
clock = pygame.time.Clock()
FPS = 60
class MovableImage(pygame.Surface):
def __init__(self, image, xpos=0, ypos=0):
self.image = image
self.xpos = xpos
self.ypos = ypos
self.width = image.get_width()
self.height = image.get_height()
self.selected = False
self.rect = pygame.Rect(xpos, ypos, image.get_width(), image.get_height())
def move(self, move):
self.xpos += move[0]
self.ypos += move[1]
self.rect = pygame.Rect(self.xpos, self.ypos, self.width, self.height)
def Transformation(element):
element = pygame.transform.scale(element,(50,75))
def init():
global ImageList
fire = pygame.Surface((50,50))
fire.fill((255,0,0))
#fire = pygame.image.load("ElementIcon/fire.png").convert_alpha()
#Transformation(fire)
#fire.set_colorkey(BLACK)
#fire_rect = fire.get_rect()
earth = pygame.Surface((50,50))
earth.fill((255,255,0))
#earth = pygame.image.load("ElementIcon/earth.png").convert_alpha()
#Transformation(earth)
#earth.set_colorkey(BLACK)
#earth_rect = earth.get_rect()
fire_obj = MovableImage(fire, 408, 450)
earth_obj = MovableImage(earth, 419,350)
ImageList =[]
ImageList.append(fire_obj)
ImageList.append(earth_obj)
def run():
global done
done = False
while not done:
check_events()
update()
clock.tick(60)
def check_events():
global done
global ImageList
mouse_pos = pygame.mouse.get_pos()
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
print("User quits the game :(")
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
done = True
print("Game stopped early by user :( ")
if event.type == pygame.MOUSEBUTTONDOWN:
for im in ImageList:
if im.rect.collidepoint(mouse_pos):
im.selected = not im.selected
if event.type == pygame.MOUSEBUTTONUP:
for im in ImageList:
if im.rect.collidepoint(mouse_pos):
im.selected = False
if event.type == pygame.MOUSEMOTION:
for im in ImageList:
if im.rect.collidepoint(mouse_pos) and im.selected:
xmv = event.rel[0]
ymv = event.rel[1]
if event.buttons[0]:
if xmv < 0:
if im.xpos > 0:
im.move((xmv,0))
elif event.rel[0] > 0:
if im.xpos < screen.get_width():
im.move((xmv,0))
elif event.rel[1] < 0:
if im.ypos > 0:
im.move((0,ymv))
elif event.rel[1] > 0:
if im.ypos < screen.get_height():
im.move((0,ymv))
def update():
global ImageList
screen.fill((255, 255, 255)) #WHITE)
#Update the screen with drawings
for im in ImageList:
screen.blit(im.image, (im.xpos, im.ypos))
pygame.display.update()
if __name__=="__main__":
init()
run()
You can get the mouse pos and the image rect and check for collision:
pos = pygame.mouse.get_pos()
if image.rect.collidepoint(pos)
# move it
If you want to move the image with the mouse you can get the relative x/y movement with pygame.mouse.get_rel() and use that to change the image location.
I am just getting started with Pygame and I am currently trying out some basic movement functions.
I ran into a problem when trying to code my movement conditions into my object class rather than in the game loop.
My first attempt which works is as follow:
classes.py:
import pygame, sys
from pygame.locals import *
class GameObject:
def __init__(self, image, height, speed):
self.speed = speed
self.image = image
self.pos = image.get_rect().move(0, height) #initial placement
def move_south(self):
self.pos = self.pos.move(0, self.speed)
if self.pos.right > 600:
self.pos.left = 0
def move_east(self):
self.pos = self.pos.move(self.speed , 0)
if self.pos.right > 600:
self.pos.left = 0
main.py:
import pygame, sys
from pygame.locals import *
from classes import *
screen = pygame.display.set_mode((640, 480))
#Importing Chars
player = pygame.image.load('green_hunter_small.png').convert()
#player.set_alpha(100) #makes whole player transparent
player.set_colorkey((0,0,0)) #sets background colour to transparent
ennemi = pygame.image.load('red_hunter_small.png').convert()
ennemi.set_colorkey((0,0,0))
background = pygame.image.load('grass_map_640x640.png').convert()
screen.blit(background, (0, 0))
objects = []
objects.append(GameObject(player, 80, 0))
for x in range(2): #create 2 objects
o = GameObject(ennemi, x*40, 0)
objects.append(o)
while True:
for event in pygame.event.get(): #setting up quit
if event.type == QUIT:
pygame.quit()
sys.exit()
if event.type == KEYDOWN:
if event.key == K_DOWN:
for o in objects:
screen.blit(background, o.pos, o.pos) #erases players by bliting bg
for o in objects:
o.speed = 4
o.move_south() #moves player
o.speed = 0
screen.blit(o.image, o.pos) #draws player
if event.key == K_RIGHT:
for o in objects:
screen.blit(background, o.pos, o.pos) #erases players by bliting bg
for o in objects:
o.speed = 4
o.move_east() #moves player
o.speed = 0
screen.blit(o.image, o.pos) #draws player
pygame.display.update()
pygame.time.delay(50)
My second attempt which didn't work was to dp:
classes.py:
import pygame, sys
from pygame.locals import *
class GameObject:
def __init__(self, image, height, speed):
self.speed = speed
self.image = image
self.pos = image.get_rect().move(0, height) #initial placement
def move_south(self):
self.pos = self.pos.move(0, self.speed)
if self.pos.right > 600:
self.pos.left = 0
def move_east(self):
self.pos = self.pos.move(self.speed , 0)
if self.pos.right > 600:
self.pos.left = 0
def move(self):
for event in pygame.event.get():
if event.type == KEYDOWN:
if event.key == K_DOWN:
screen.blit(background, self.pos, self.pos) #erases players by bliting bg
self.speed = 4
self.move_south() #moves player
self.speed = 0
if event.key == K_RIGHT:
screen.blit(background, self.pos, self.pos) #erases players by bliting bg
self.speed = 4
self.move_east() #moves player
self.speed = 0
screen.blit(self.image, self.pos) #draws player
main.py:
import pygame, sys
from pygame.locals import *
from classes import *
screen = pygame.display.set_mode((640, 480))
#Importing Chars
player = pygame.image.load('green_hunter_small.png').convert()
#player.set_alpha(100) #makes whole player transparent
player.set_colorkey((0,0,0)) #sets background colour to transparent
ennemi = pygame.image.load('red_hunter_small.png').convert()
ennemi.set_colorkey((0,0,0))
background = pygame.image.load('grass_map_640x640.png').convert()
screen.blit(background, (0, 0))
objects = []
objects.append(GameObject(player, 80, 0))
for x in range(2): #create 2 objects
o = GameObject(ennemi, x*40, 0)
objects.append(o)
while True:
for event in pygame.event.get(): #setting up quit
if event.type == QUIT:
pygame.quit()
sys.exit()
for o in objects:
o.move()
pygame.display.update()
pygame.time.delay(50)
So it seems that the code struggles to go and check the event loop from the instance. The reason I wanted to code the movement as a method rather than straight in main was to save space and make it easier to add characters later on.
Your code has a race condition (to use the term really loosely).
The reason that your characters are not moving is that the first pygame.event.get call (when you are checking for a QUIT event) consumes all the KEYDOWN events that are on the queue. Then (unless you manage to press a key while the first loop is running), there are no KEYDOWN events in the queue when the first GameObject checks for events. Diddo for all other GameObjects.
You need to handler all pygame events in one loop. Example code:
class GameObject():
#rest of class
def move(self,event):
if event.key == K_DOWN:
screen.blit(background, self.pos, self.pos) #erases players by bliting bg
self.speed = 4
self.move_south() #moves player
self.speed = 0
#repeat for all other directions
screen.blit(self.image, self.pos) #draws player
#initialize objects
while True:
for event in pygame.event.get():
if event.type == QUIT: #handle quit event
elif event.type == KEYDOWN:
for o in objects:
o.move(event)
#do non-eventhandling tasks.