I was following a tutorial on simulating physics with pymunk and pygame, however when i got to the part using event.MOUSEBUTTONDOWN, it keeps being highlighted by pycharm and says "':' expected". Changing it from = to == fixed this issue but now whenever it runs it gives the error.
if event.type == event.MOUSEBUTTONDOWN:
pps.append(create_pp(space,event.pos))
AttributeError: 'Event' object has no attribute 'MOUSEBUTTONUP'
import pygame,sys,pymunk
def create_pp(space,pos):
body = pymunk.Body(1,100,body_type = pymunk.Body.DYNAMIC)
body.position = pos
shape = pymunk.Circle(body,80)
space.add(body,shape)
return shape
def draw_pps(pps):
for pp in pps:
pos_x = int(pp.body.position.x)
pos_y = int(pp.body.position.y)
pp_rect = pp_surface.get_rect(center = (pos_x,pos_y))
screen.blit(pp_surface,pp_rect)
def static_mouth(space):
body = pymunk.Body(body_type = pymunk.Body.STATIC)
body.position = (430,400)
shape = pymunk.Circle(body, 50)
space.add(body,shape)
return shape
def draw_static_mouth(mouths):
for mouth in mouths:
pos_x = int(mouth.body.position.x)
pos_y = int(mouth.body.position.y)
mouth_rect = mouth_surface.get_rect(center = (pos_x,pos_y))
screen.blit(mouth_surface, mouth_rect)
pygame.init() #initiating pygame
screen = pygame.display.set_mode((600,600)) #creates display surface
clock = pygame.time.Clock() #creating game clock
space = pymunk.Space()
space.gravity = (0,400)
pp_surface = pygame.image.load('Drawing.png')
mouth_surface = pygame.image.load('Mouth.png')
pps = []
mouths = []
mouths.append(static_mouth(space))
while True: #game loop
for event in pygame.event.get(): #checks for user input
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
if event.type == event.MOUSEBUTTONDOWN:
pps.append(create_pp(space,event.pos))
screen.fill((217,217,217)) #backgroun color
draw_pps(pps)
draw_static_mouth(mouths)
space.step(1/50)
pygame.display.update() #renders frame
clock.tick(120) #limiting fps to 120
I think is this part went wrong if event.type == event.MOUSEBUTTONDOWN:
I think u could try this
if event.type == pygame.MOUSEBUTTONDOWN:
Related
I am trying to a blue window that is mostly made up of rectangles, which can be turned green when clicked by the mouse, but when I run the code all that I get is a black window, and I don't know why it happens. This is my code.
import pygame, sys
clock = pygame.time.Clock()
from pygame.locals import *
pygame.init()
pygame.display.set_caption("Worldbuilder")
global screen
screen = pygame.display.set_mode((600,600))
global click
click = False
class tile:
def __init__(self,x,y,tilesize):
global a
a = pygame.Rect(x,y,tilesize,tilesize)
def draw(self,type):
mx,my = pygame.mouse.get_pos()
if a.collidepoint((mx,my)):
if click:
if type == 0:
type = 1
else:
type = 0
if type == 0:
pygame.draw.rect(screen,(0,0,255),a)
if type == 1:
pygame.draw.rect(screen,(0,255,0),a)
global tilex, tiley
tilex = 0
tiley = 0
list = []
for i in range(1,12):
for i in range(1,12):
list.append(tile(tilex,tiley,50))
tilex += 50
tiley += 50
while True:
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
if event.type == MOUSEBUTTONDOWN:
if event.button == 1:
click = True
for i in list:
i.draw(0)
pygame.display.update()
clock.tick(60)
Read about Classes. a needs to be an attribute of the class tile instead of a global variable:
class tile:
def __init__(self,x,y,tilesize):
self.a = pygame.Rect(x,y,tilesize,tilesize)
# [...]
There are multiple problems when you generate the grid of tiles. This can be done much easier:
for i in range(12):
for j in range(12):
list.append(tile(i*50,j*50,50))
Complete example:
import pygame, sys
clock = pygame.time.Clock()
from pygame.locals import *
pygame.init()
pygame.display.set_caption("Worldbuilder")
global screen
screen = pygame.display.set_mode((600,600))
global click
click = False
class tile:
def __init__(self,x,y,tilesize):
self.a = pygame.Rect(x,y,tilesize,tilesize)
def draw(self,type):
mx,my = pygame.mouse.get_pos()
if self.a.collidepoint((mx,my)):
if click:
if type == 0:
type = 1
else:
type = 0
if type == 0:
pygame.draw.rect(screen,(0,0,255),self.a)
if type == 1:
pygame.draw.rect(screen,(0,255,0),self.a)
tilex = 0
tiley = 0
list = []
for i in range(12):
for j in range(12):
list.append(tile(i*50,j*50,50))
while True:
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
if event.type == MOUSEBUTTONDOWN:
if event.button == 1:
click = True
for i in list:
i.draw(0)
pygame.display.update()
clock.tick(60)
I'm creating a small game in pygame with obstacles that fall from the top of the screen to the bottom. At each event tick, an obstacle is created. However, at each new tick (1500milliseconds) the current obstacle is removed before it can reach the bottom and a new one is created. I need the obstacles to stay on the screen while new ones are generated.
I'm trying to get this done with classes and functions only.
So I want to create an obstacle_movement() function within the obstacle class.
Can you help please?
My code is below.
import pygame
import sys
from random import randint
from pygame import surface
import time
import os
class obstacle(pygame.sprite.Sprite):
def __init__(self):
super().__init__()
Obstacle_directory = r'C:\\Users\\ctcar\\Documents\\CompSci\\GameDev\\selfgame\\Graphics\\Obstacles'
obstacle_lst = []
self.obstacle_frames = []
for filename in sorted(os.listdir(Obstacle_directory), key = len):
if filename.endswith('.png'):
obstacle_lst.append('Graphics/Obstacles/' + filename)
for sprite in obstacle_lst:
alpha_sprite = pygame.image.load(sprite).convert_alpha()
self.obstacle_frames.append(alpha_sprite)
y_pos = -20
self.obstacle_idx = 0
self.frames = self.obstacle_frames
self.image = self.frames[self.obstacle_idx]
self.rect = self.image.get_rect(midbottom = (randint(50, 750), y_pos))
def obstacle_animation(self):
self.obstacle_idx += 0.1
if self.obstacle_idx >= len(self.frames):
self.obstacle_idx = 0
self.image = self.frames[int(self.obstacle_idx)]
def update(self):
self.obstacle_animation()
self.rect.y += 4
obstacle_group = pygame.sprite.GroupSingle()
obstacle_timer = pygame.USEREVENT + 1
pygame.time.set_timer(obstacle_timer, randint(1000, 1100))
game_active = True
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
if game_active:
screen.blit(sky_surface,(0,0))
screen.blit(ground_surface,(100,710))
if event.type == obstacle_timer:
obstacle_group.add(obstacle())
obstacle_group.draw(screen)
obstacle_group.update()
pygame.display.update()
clock.tick(60)
You need to use a pygame.sprite.Group insterad of a pygame.sprite.GroupSingle:
obstacle_group = pygame.sprite.GroupSingle()
obstacle_group = pygame.sprite.Group()
See obstacle_group = pygame.sprite.GroupSingle():
The GroupSingle container only holds a single Sprite. When a new Sprite is added, the old one is removed.
Furthermore, the events must be handled in the event loop:
game_active = True
run = True
while run:
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
if game_active:
if event.type == obstacle_timer:
obstacle_group.add(obstacle())
if game_active:
screen.blit(sky_surface,(0,0))
screen.blit(ground_surface,(100,710))
obstacle_group.draw(screen)
obstacle_group.update()
pygame.display.update()
clock.tick(60)
pygame.quit()
sys.exit()
import pygame
from sys import exit
import random
WIDTH, HEIGHT = 1400,750
FPS = 60
HEADWAY_GAP = 40
vehicleColor = {0:"red",1:"blue",2:"yellow"}
directions = ["Right", "Left"]
classofVehicle = ["Car","Bike","Bus"]
coord = {"Right":(0,300), "Left":(1400,350)}
objects = {"Right":[],"Left":[]}
pygame.init()
myWindow = pygame.display.set_mode((WIDTH, HEIGHT))
clock = pygame.time.Clock()
road = pygame.image.load("Required_images/Road/Road_final.png")
class Vehicle(pygame.sprite.Sprite):
def __init__(self, ClassofVehicle, Color_Code, direction, pos):
super().__init__()
self.Class = ClassofVehicle
self.Color_Code = Color_Code
self.direction = direction
self.pos = pos
path = "Required_images/"+ClassofVehicle+"/"+ClassofVehicle+"_"+Color_Code+".png"
self.image = pygame.image.load(path)
self.rect = self.image.get_rect()
if self.direction == "Right":
self.rect.midright = pos
else:
self.rect.midleft = pos
self.index = len(objects[direction])-1
def movingVehicles(self):
if self.direction == "Right":
if self.index == 0 or (self.rect.x + self.rect.width < objects[self.direction][self.index].rect.x - HEADWAY_GAP):
self.rect.x += 1
elif self.direction == "Left":
if self.index == 0 or (self.rect.x - self.rect.width > objects[self.direction][self.index].rect.x + HEADWAY_GAP):
self.rect.x -= 1
def update(self):
self.movingVehicles()
Object_timer = pygame.USEREVENT+1
pygame.time.set_timer(Object_timer, 1000)
objectsGroup = pygame.sprite.Group()
def generatingObjects():
Dir = random.choice(directions)
po = coord[Dir]
color_code = random.choice([0,1,2])
cla = random.choice(classofVehicle)
object = Vehicle(cla,vehicleColor[color_code],Dir,po)
objectsGroup.add(object)
objects[Dir].append(object)
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
exit()
if event.type == Object_timer:
generatingObjects()
myWindow.fill((0,0,0))
objectsGroup.update()
objectsGroup.draw(myWindow)
pygame.display.update()
clock.tick(FPS)
I have created a sprite class and a sprite group. I also created an user defined event to generate vehicles for every 1000ms. To display the vehicles on the screen instead of looping through all the elements of the sprite group separately I used group_name.draw() method. But when I run the code, some of the images are getting stuck on the screen for some time and are moving after sometime. I tried to look for any error in the logic but I couldn't find it. If you have any knowledge or able to find the error, please help and also any kind of suggestions are appreciated.
It is a matter of Indentation. You have to draw the scene in the application loop instead of after the application loop:
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
exit()
if event.type == Object_timer:
generatingObjects()
# INDENTATION
#->|
myWindow.fill((0,0,0))
objectsGroup.update()
objectsGroup.draw(myWindow)
pygame.display.update()
clock.tick(FPS)
make sure to indent the elements in your while loop and use a pygame.display.flip() at the very end of your loop.
so it looks like
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
exit()
if event.type == Object_timer:
generatingObjects()
myWindow.fill((0,0,0))
objectsGroup.update()
objectsGroup.draw(myWindow)
clock.tick(FPS)
pygame.display.flip()
I've been working on a sorting application in python using pygame for visual purposes, and now I am experiencing an error which I am not sure how to fix. My code was working perfectly fine, and then I started getting an error which was saying "pygame.error: video system not initialized". Here is my code:
import pygame
import random
import keyboard
pygame.font.init()
lines = [random.randint(1,25) for i in range(100)]
def line_draw():
array_items = len(lines)
line_color = (0,0,0)
line_width = int(650 / array_items)
list_pos = 1
for i in lines:
start_x = (800 / (array_items + 1)) * list_pos
start_y = 600
end_x = start_x
end_y = 600 - (i * 20)
pygame.draw.line(gameDisplay, line_color, (start_x, start_y), (end_x, end_y), line_width)
list_pos = list_pos + 1
def refill():
gameDisplay.fill((255,255,255))
line_draw()
pygame.display.update()
pygame.time.delay(3)
def bubble_sort():
exchange = True
elements = len(lines)
passes_remaining = elements - 1
while passes_remaining > 0 and exchange:
exchange = False
pygame.event.pump()
for i in range(passes_remaining):
if lines[i] > lines[i+1]:
exchange = True
temp = lines[i]
lines[i] = lines[i+1]
lines[i+1] = temp
refill()
passes_remaining = passes_remaining - 1
run = True
while run:
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_o:
bubble_sort()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_r:
lines = [random.randint(1,25) for i in range(100)]
line_draw()
gameDisplay.fill((255, 255, 255))
line_draw()
pygame.display.update()
You have to initialized to pygame modules (e.g. pygame.init()) and you must initialize a window or screen for display with pygame.display.set_mode, before the application loop:
import pygame
# [...]
pygame.init()
pygame.display.set_mode((640, 480))
# [...]
run = True
while run:
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
# [...]
pygame.quit()
I'm making the program, that blits the 2D array as 2D map of tiles. The self.tile_size variable is used to scale the tile image that will be blit.
I want the Q to make it smaller, and E to make it bigger. The problem is, that output in in pygame window is not what i wanted. The image in link shows what happened, when i ran a program and tried to make image bigger. Image of output
Here's my code:
import pygame
from pygame.locals import *
pygame.init()
import math, sys, os, random, time
from a_star import *
tiles_list = [
pygame.image.load('Floor.png'),
pygame.image.load('Wall.png'),
]
PLAN_W = 20
PLAN_H = 20
PLAN_STATUS = [[True for i in range(PLAN_W)]for j in range(PLAN_H)]
OBSTACLES = [
[0,0],
[0,1],
[0,2]]
obsta(OBSTACLES, PLAN_STATUS) # function imported from a_star that change PLAN_STATUS cells from OBSTACLES to False
class World():
def __init__(self):
self.screen_width = 800
self.screen_height = 600
self.screen = pygame.display.set_mode((self.screen_width, self.screen_height))
self.clock = pygame.time.Clock()
self.bg_color = (255,255,255)
self.tile_size = 48
self.map_status = PLAN_STATUS
self.tiles_list = tiles_list
self.scale_change = 0
self.run()
def scale_tiles(self):
print(self.tile_size)
self.new_list = []
for i in self.tiles_list:
i = pygame.transform.scale(i, (self.tile_size, self.tile_size))
self.new_list.append(i)
self.tiles_list = self.new_list
def render_map(self):
print(self.tile_size)
'''
self.screen.fill(self.bg_color)
for x in range(PLAN_H):
for y in range(PLAN_W):
if self.map_status[y][x]:
tile = self.tiles_list[0]
elif not self.map_status[y][x]:
tile = self.tiles_list[1]
self.screen.blit(tile, (x*self.tile_size, y*self.tile_size))
'''
self.screen.blit(self.tiles_list[0], (400, 300))
def run(self):
while True:
self.events = pygame.event.get()
self.keys = pygame.key.get_pressed()
self.mouse_pos = pygame.mouse.get_pos()
self.mouse_but = pygame.mouse.get_pressed()
#UPDATE
self.screen.fill(self.bg_color)
#self.scale_tiles()
self.render_map()
pygame.display.flip()
#EVENTS
if self.keys[ord('e')] == 1:
self.tile_size += 1
self.scale_tiles()
if self.keys[ord('q')] == 1:
self.tile_size -= 1
self.scale_tiles()
'''for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_q:
print('q')
self.scale_change = -1
if event.key == pygame.K_e:
print('e')
self.scale_change = 1
if event.type == pygame.KEYUP:
if event.key == pygame.K_q or event.key == pygame.K_e:
print('stopped key')
self.scale_change = 0'''
self.clock.tick(50)
if __name__=="__main__":
main = World()
Where's the problem in my code?
Thank you for the help
Floor.png
Use the images/surfaces in the original, global tiles_list to create the new_list not the already scaled images in self.tiles_list, otherwise it seems to increase the impreciseness with every scaling.
for i in tiles_list: not for i in self.tiles_list:.