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)
Related
I am trying to make a python program to draw a line and turn it into a circle with an animation using pygame, yet I haven't even gotten through the drawing-the-line code. I have noticed that python is changing the wrong or both items in a list that contains the starting point when the user presses down the left click, stored as the first item, and the current point of the user's mouse as the second.
This is generally what I want it to do: https://youtu.be/vlqZ0LubXCA
Here are the outcomes with and without the lines that update the 2nd item:
with:
without:
As you can see, or read in the descriptions, the line is necessary to cover the previous frame.
I have marked the lines that change the outcome with arrows:
import pygame, PIL, random
print('\n')
#data
bubbles = []
color_options = [[87, 184, 222]]
pressed = False
released = False
bubline_start = []
background = [50, 25, 25]
size = [500, 500]
#pygame
display = pygame.display.set_mode(size)
pygame.init()
#functions
def new_bub_color():
color_index = random.randint(0, len(color_options)-1)
lvl = random.randrange(85, 115)
bub_color = []
for val in color_options[color_index]:
bub_color.append(val*(lvl/100))
return bub_color
def bubble_line():
global display, pressed, bubline_start, released, bubbles, color_options
if len(bubbles) > 0:
if not bubbles[-1][0] == 0:
#first frame of click
bub_color = new_bub_color()
bubbles.append([0, bub_color, [bubline_start, list(pygame.mouse.get_pos())]])
pygame.draw.line(display, bub_color, bubline_start, pygame.mouse.get_pos())
else:
#draw after drags
pygame.draw.line(display, bubbles[-1][1], bubbles[-1][2][0], list(pygame.mouse.get_pos()))
bubbles[-1][2][1] = list(pygame.mouse.get_pos())# <-- HERE
else:
#first bubble
bub_color = new_bub_color()
bubbles.append([0, bub_color, [bubline_start, list(pygame.mouse.get_pos())]])
pygame.draw.line(display, bub_color, bubline_start, pygame.mouse.get_pos())
if released:
bubbles[-1][0] = 1
bubbles[-1][2][1] = list(pygame.mouse.get_pos())# <-- HERE
released = False
def cover_prev_frame():
global bubbles, background, size
min_pos = []
max_pos = []
for bubble in bubbles:
min_pos = bubble[2][0]
max_pos = bubble[2][0]
for point in bubble[2]:
#x min and max
if point[0] < min_pos[0]:
min_pos[0] = point[0]
elif point[0] > max_pos[0]:
max_pos[0] = point[0]
#y min and max
if point[1] < min_pos[1]:
min_pos[1] = point[1]
elif point[1] > max_pos[1]:
max_pos[1] = point[1]
max_pos = [max_pos[0]-min_pos[0]+1, max_pos[1]-min_pos[1]+1]
if type(background) == str:
#image background
later = True
elif type(background) == list:
#solid color background
pygame.draw.rect(display, background, pygame.Rect(min_pos, max_pos))
while True:
pygame.event.pump()
events = pygame.event.get()
for event in events:
if event.type == pygame.QUIT:
pygame.quit()
elif event.type == pygame.MOUSEBUTTONDOWN and not pressed:
bubline_start = list(pygame.mouse.get_pos())
pressed = True
elif event.type == pygame.MOUSEBUTTONUP and pressed:
pressed = False
released = True
cover_prev_frame()
if pressed or released:
bubble_line()
try:
pygame.display.update()
except:
break
if not bubbles[-1][0] == 0: is False as long as the mouse is not released. Therefore add many line segments, each starting at bubline_start and ending at the current mouse position.
You must redraw the scene in each frame. bubbles is a list of bubbles and each bubble has a list of points. Add a new point to the last bubble in the list while the mouse is held down. Start a new bubble when the mouse is pressed and end a bubble when it is released. This greatly simplifies your code.
Minimal example
import pygame, random
size = [500, 500]
pygame.init()
display = pygame.display.set_mode(size)
clock = pygame.time.Clock()
pressed = False
bubbles = []
background = [50, 25, 25]
run = True
while run:
clock.tick(100)
events = pygame.event.get()
for event in events:
if event.type == pygame.QUIT:
run = False
elif event.type == pygame.MOUSEBUTTONDOWN:
start_pos = list(event.pos)
bubble_color = pygame.Color(0)
bubble_color.hsla = (random.randrange(0, 360), 100, 50, 100)
bubbles.append((bubble_color, [start_pos]))
pressed = True
elif event.type == pygame.MOUSEMOTION and pressed:
new_pos = list(event.pos)
if len(bubbles[-1][1]) > 0 and bubbles[-1][1] != new_pos:
bubbles[-1][1].append(new_pos)
elif event.type == pygame.MOUSEBUTTONUP:
pressed = False
end_pos = list(event.pos)
if len(bubbles[-1][1]) > 0 and bubbles[-1][1] != end_pos:
bubbles[-1][1].append(list(event.pos))
display.fill(background)
for i, bubble in enumerate(bubbles):
if len(bubble[1]) > 1:
closed = not pressed or i < len(bubbles) - 1
pygame.draw.lines(display, bubble[0], closed, bubble[1], 3)
pygame.display.update()
pygame.quit()
For the animation I propose to create a class that represents a bubble and a method animate that slowly turns the polygon into a circle.
Minimal example
import pygame, random
size = [500, 500]
pygame.init()
display = pygame.display.set_mode(size)
clock = pygame.time.Clock()
class Bubble:
def __init__(self, start):
self.color = pygame.Color(0)
self.color.hsla = (random.randrange(0, 360), 100, 50, 100)
self.points = [list(start)]
self.closed = False
self.finished = False
def add_point(self, point, close):
self.points.append(list(point))
self.closed = close
if self.closed:
x_, y_ = list(zip(*self.points))
x0, y0, x1, y1 = min(x_), min(y_), max(x_), max(y_)
rect = pygame.Rect(x0, y0, x1-x0, y1-y0)
self.center = rect.center
self.radius = max(*rect.size) // 2
def animate(self):
if self.closed and not self.finished:
cpt = pygame.math.Vector2(self.center) + (0.5, 0.5)
self.finished = True
for i, p in enumerate(self.points):
pt = pygame.math.Vector2(p)
v = pt - cpt
l = v.magnitude()
if l + 0.5 < self.radius:
self.finished = False
v.scale_to_length(min(self.radius, l+0.5))
pt = cpt + v
self.points[i] = [pt.x, pt.y]
def draw(self, surf):
if self.finished:
pygame.draw.circle(surf, self.color, self.center, self.radius, 3)
elif len(self.points) > 1:
pygame.draw.lines(surf, self.color, self.closed, self.points, 3)
bubbles = []
pressed = False
background = [50, 25, 25]
run = True
while run:
clock.tick(100)
events = pygame.event.get()
for event in events:
if event.type == pygame.QUIT:
run = False
elif event.type == pygame.MOUSEBUTTONDOWN:
bubbles.append(Bubble(event.pos))
pressed = True
elif event.type == pygame.MOUSEMOTION and pressed:
bubbles[-1].add_point(event.pos, False)
elif event.type == pygame.MOUSEBUTTONUP:
bubbles[-1].add_point(event.pos, True)
pressed = False
for bubble in bubbles:
bubble.animate()
display.fill(background)
for bubble in bubbles:
bubble.draw(display)
pygame.display.update()
pygame.quit()
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 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:
I'm trying to animate a sprite using a loop such that each time the loop runs through the position number for an image in an array increases by one. I keep getting "UnboundLocalError: local variable 'Antic' referenced before assignment". There is
Antic = 0
Antic = int(Antic)
# Global constants
StAnmtn = ["Images/PlayerVampireStanding1.png", "
Images/PlayerVampireStanding2.png",
"Images/PlayerVampireStanding3.png","Images/PlayerVampireStanding4.png",
"Images/PlayerVampireStanding5.png", "Images/PlayerVampireStanding6.png",
"Images/PlayerVampireStanding7.png", "Images/PlayerVampireStanding8.png"]
`
at the start and
def main():
""" Main Program """
pygame.init()
clock = pygame.time.Clock() # creates clock to limit frames per
second
FPS = 60 # sets max speed of min loop
SCREENSIZE = SCREENWIDTH, SCREENHEIGHT = 1300, 700 # sets size of
screen/window
screen = pygame.display.set_mode(SCREENSIZE) # creates window and game
screen
pygame.display.set_caption("Count Acheron")
# Create the player
player = Player()
# Create all the levels
level_list = []
level_list.append( Level_01(player) )
# Set the current level
current_level_no = 0
current_level = level_list[current_level_no]
active_sprite_list = pygame.sprite.Group()
player.level = current_level
player.rect.x = 340
player.rect.y = SCREEN_HEIGHT - player.rect.height
active_sprite_list.add(player)
# Loop until the user clicks the close button.
done = False
# Used to manage how fast the screen updates
clock = pygame.time.Clock()
# -------- Main Program Loop -----------
while not done:
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
player.go_left()
if event.key == pygame.K_RIGHT:
player.go_right()
if event.key == pygame.K_UP:
player.jump()
if event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT and player.change_x < 0:
player.stop()
if event.key == pygame.K_RIGHT and player.change_x > 0:
player.stop()
if Antic > 6:
Antic = 0
else:
Antic += 1
# Update the player.
active_sprite_list.update()
# Update items in the level
current_level.update()
# ALL CODE TO DRAW SHOULD GO BELOW THIS COMMENT
current_level.draw(screen)
active_sprite_list.draw(screen)
# ALL CODE TO DRAW SHOULD GO ABOVE THIS COMMENT
# Limit to 60 frames per second
clock.tick(60)
# Go ahead and update the screen with what we've drawn.
pygame.display.flip()
# Be IDLE friendly. If you forget this line, the program will 'hang'
# on exit.
pygame.quit()
if __name__ == "__main__":
main()
as the loop. What it doesn't seem to like is the snippet of code
if Antic > 6:
Antic = 0
else:
Antic += 1
How do I fix this?
Personally I've never used pygame's sprite module.
import pygame
class character:
def __init__(self, x, y):
self.x = x
self.y = y
self.sprites = [pygame.image.load("img1.png"), pygame.image.load("img2.png")]
self.frame = 0
def draw(self, surface):
surface.blit(self.sprites[self.frame], (self.x, self.y))
self.frame += 1
if self.frame > len(self.sprites) - 1: self.frame = 0
pygame.init()
DS = pygame.display.set_mode((1280, 720))
clock = pygame.time.Clock()
c = character(640, 360)
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT or (event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE):
pygame.quit()
c.draw(DS)
pygame.display.update()
clock.tick(30)
DS.fill((0, 0, 0))
Needed to globalise the function ("global Antic" in the main loop)
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:.