The program is supposed to make 3 squares and move them to the right. That works well. However, there are 2 squares that move down even though there are no functions to do that. there are only 3 square creating functions but there are 2 more that appear
import pygame
import random
import time
enemyCoordList = []
pygame.init()
rand = random.Random()
screen = pygame.display.set_mode((1000, 600))
px = 30
py = 30
def enemy(x, y, sizex=30, sizey=30, health=0, speed=6,):
# pygame.draw.rect(screen, (0, 255, 0), pygame.Rect(x, y, sizex, sizey))
enemyCoordList.append(x)
enemyCoordList.append(y)
def drawEnemy():
for l in range(len(enemyCoordList)-1):
# print(range(len(enemyCoordList)))
pygame.draw.rect(screen, (0, 255, 0), pygame.Rect(enemyCoordList[l], enemyCoordList[l+1], 50, 50))
enemy(30, 30)
enemy(50, 50)
enemy(100,100)
print(enemyCoordList)
run = True
while run:
time.sleep(0.05)
screen.fill((9, 68, 43))
drawEnemy()
for i in range(len(enemyCoordList)):
#print(i)
if i % 2 != 0:
#print(i)
continue
# print(enemyCoordList)
#print(i)
enemyCoordList[i] += 1
# for i in enemyCoordList:
pygame.display.update()
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
pygame.quit()
A coordinate has 2 components so:
for l in range(len(enemyCoordList)-1):
for l in range(0, len(enemyCoordList), 2):
Correct drawEnemy function:
def drawEnemy():
for l in range(0, len(enemyCoordList), 2):
pygame.draw.rect(screen, (0, 255, 0), pygame.Rect(enemyCoordList[l], enemyCoordList[l+1], 50, 50))
However, it would be much easier to work with a list of coordinate pairs (list of lists):
import pygame
import random
import time
pygame.init()
rand = random.Random()
screen = pygame.display.set_mode((1000, 600))
def enemy(x, y, sizex=30, sizey=30, health=0, speed=6):
enemyCoordList.append([x, y])
def drawEnemy():
for x, y in enemyCoordList:
pygame.draw.rect(screen, (0, 255, 0), pygame.Rect(x, y, 50, 50))
enemyCoordList = []
enemy(30, 30)
enemy(50, 50)
enemy(100,100)
print(enemyCoordList)
run = True
while run:
time.sleep(0.05)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
for pos in enemyCoordList:
pos[0] += 1
screen.fill((9, 68, 43))
drawEnemy()
pygame.display.update()
pygame.quit()
Related
I made a script, which should take the user input of a mathematical function (f(x)=...) and draw it. I used pygame for that because I want to use that mechanic for a game.
I have to run the code of a function once without any output once, but after that, it flawlessly works
heres the code:
import pygame
def replace_x(function):
f = lambda x: eval(function)
return f
def convert_y(y_coords):
y_coords = 540 - y_coords
return y_coords
def convert_x(x_coord):
x_coord = x_coord + 960
return x_coord
# variables
background_colour = (255, 255, 255)
screen = pygame.display.set_mode((1920, 1080))
running = True
current_y = 0
previous_y = 0
pygame.init()
pygame.display.set_caption('Mathe Kreativarbeit')
screen.fill(background_colour)
pygame.display.flip()
function_input = input("Funktion: ")
function_input = function_input.replace("^", "**")
pygame.display.flip()
for x_coords in range(-15, 17):
f = replace_x(function_input)
current_y = convert_y(f(x_coords))
previous_y = convert_y(f(x_coords - 1))
start_pos = (convert_x((x_coords - 1) * 60), previous_y)
end_pos = (convert_x(x_coords * 60), current_y)
print(start_pos)
print(end_pos)
pygame.draw.aaline(screen, (0, 0, 0), start_pos, end_pos)
pygame.display.flip()
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
Create a list of points from the function:
f = replace_x(function_input)
pt_list = []
for x in range(-20, 20):
pt_list.append((x, f(x)))
Either print the list of points:
print(pt_list)
or print the list in a loop:
for pt in pt_list:
print(pt)
Create a list of screen coordinates from the list of point:
coord_list = []
for pt in pt_list:
x = round(convert_x(pt[0] * 20))
y = round(convert_y(pt[1]))
coord_list.append((x, y))
Draw the curve in the application loop with pygame.draw.aalines():
clock = pygame.time.Clock()
running = True
while running:
clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
pygame.draw.aalines(screen, (0, 0, 0), False, coord_list)
pygame.display.flip()
pygame.quit()
Example for input x**3:
I'm trying to create a animation that runs around a shape. The method I came up with is similar to the snake game, drawing the desired part and refresh it with white screen.
For example, if I want to draw a linear line animation, with the max animated length of 3:
lst = [1, 2, 3]
dummy_lst = [1, 1, 1, 2, 3, 3, 3]
colored_position = [[1,1,1], [1,1,2], [1,2,3], [2,3,3], [3,3,3]] # if the numbers overlapped, it draws the same place which is fine
and then I iterate the colored_position to get the animation done.
The real code:
import pygame
import sys
SCREEN_WIDTH = 800
CELLSIZE = 10
x, y = 150, 200
position = [[x+CELLSIZE*i, y] for i in range(50)] +\
[[x+CELLSIZE*50, y+CELLSIZE*i] for i in range(50)] +\
[[x+CELLSIZE*50-CELLSIZE*i, y+CELLSIZE*50]for i in range(50)] +\
[[x, y+CELLSIZE*50-CELLSIZE*i]for i in range(50)]
# creates fake firsts and lasts
def dummy_list(list, length):
return [list[0]]*(length-1) + list + [list[-1]]*(length-1)
def main():
pygame.init()
clock = pygame.time.Clock()
screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_WIDTH))
count = 0
while True:
clock.tick(10)
screen.fill((255, 255, 255))
dummy = dummy_list(position, 50)
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
count = 0
while count < 1: # I could chaget this to see many times it rotates
for i in range(len(dummy)-50+1):
for j in range(9): # change this to adjust how wide the colored part is
pygame.draw.rect(screen, (255, 0, 0), pygame.Rect(
dummy[i+j][0], dummy[i+j][1], CELLSIZE, CELLSIZE), 0)
pygame.display.update()
screen.fill((255, 255, 255))
count += 1
pygame.display.update()
But it seems very hard-coding. since I have to know each part of the desired position's Xs and Ys. What's the smarter way to complete the task?
You want to move the object along a path. I don't see any problem in defining the path through a list of points.
However you can write a function that generates the list of points from a pygame.Rect object:
def generate_positions(rect, step):
return [[x, rect.top] for x in range(rect.left, rect.right, step)] +\
[[rect.right, y] for y in range(rect.top, rect.bottom, step)] +\
[[x, rect.bottom] for x in range(rect.right, rect.left, -step)] +\
[[rect.left, y] for y in range(rect.bottom, rect.top, -step)]
CELLSIZE = 10
x, y = 150, 200
position = generate_positions(pygame.Rect(x, y, 50*CELLSIZE, 50*CELLSIZE), CELLSIZE)
I recommend to use the application loop to draw the snake:
import pygame
import sys
SCREEN_WIDTH = 800
def generate_positions(rect, step):
return [[x, rect.top] for x in range(rect.left, rect.right, step)] +\
[[rect.right, y] for y in range(rect.top, rect.bottom, step)] +\
[[x, rect.bottom] for x in range(rect.right, rect.left, -step)] +\
[[rect.left, y] for y in range(rect.bottom, rect.top, -step)]
CELLSIZE = 10
x, y = 150, 200
position = generate_positions(pygame.Rect(x, y, 10*CELLSIZE, 10*CELLSIZE), CELLSIZE)
def main():
pygame.init()
clock = pygame.time.Clock()
screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_WIDTH))
current_point = None
snake_len = 9
while True:
clock.tick(10)
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
current_point = -snake_len
screen.fill((255, 255, 255))
if current_point != None:
for i in range(max(0, current_point), min(len(position), current_point+snake_len)):
pygame.draw.rect(screen, (255, 0, 0), pygame.Rect(*position[i], CELLSIZE, CELLSIZE), 0)
current_point += 1
if current_point >= len(position):
current_point = None
pygame.display.update()
main()
I have made a code that renders 2 different random numbers on screen, but it justs keep updating the numbers. I want the program to stop updating those numbers once the first 2 appear on screen. Here is the code:
import pygame
import random
pygame.init()
clock = pygame.time.Clock()
surface = pygame.display.set_mode((600, 400))
pygame.display.set_caption("Projecte MatZanfe")
font = pygame.font.SysFont('comicsans', 50)
base_font = pygame.font.Font(None, 32)
user_text = ''
color_active = pygame.Color('lightskyblue3')
def start_the_game():
# Variables
is_correct = False
points = 0
x = random.randint(0,10)
y = random.randint(0,10)
z = x + y
surface.fill((255,70,90))
text = font.render (str(x) + "+" + str(y), True, (255,255,255))
input_rect = pygame.Rect(200,200,180,50)
pygame.draw.rect(surface,color_active,input_rect)
text_surface = base_font.render(user_text,True,(255,255,255))
surface.blit(text_surface, input_rect)
surface.blit(text,(260,120))
input_rect.w = max(100,text_surface.get_width()+10)
running = True
while running:
clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
start_the_game()
pygame.display.update()
pygame.quit()
Maybe using an if statement would be the solution, but I can't figure out where and what should I introduce to the code. How would you do it?
As #jasonharper suggested, you probably are better off with two functions, one to initialize things and another to display the game:
def start_the_game():
x = random.randint(0, 10)
y = random.randint(0, 10)
return x, y
def display_the_game(x, y):
# Variables
is_correct = False
points = 0
z = x + y
surface.fill((255, 70, 90))
text = font.render(str(x) + "+" + str(y), True, (255, 255, 255))
input_rect = pygame.Rect(200, 200, 180, 50)
pygame.draw.rect(surface, color_active, input_rect)
text_surface = base_font.render(user_text, True, (255, 255, 255))
surface.blit(text_surface, input_rect)
surface.blit(text, (260, 120))
input_rect.w = max(100, text_surface.get_width() + 10)
x, y = start_the_game()
while running:
clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
display_the_game(x, y)
pygame.display.update()
pygame.quit()
By putting random.randint in a function outside the loop, it will only be called once.
I don't know how to detect when my mouse is on 2 rect and choose (if two rect has an action) the action. For example, in Windows, when two windows are one over the other, it's the first window that will be selected. I want to do exactly the same thing.
import pygame
class Rectangle(pygame.sprite.Sprite):
def __init__(self, screen, rect, x, y, color, name):
super().__init__()
self.screen = screen
self.name = name
self.screen_str = str(screen)
self.rect = rect
self.color = color
self.x, self.y = x, y
self.r = pygame.Surface((self.rect[2], self.rect[3]), pygame.SRCALPHA)
self.rect = self.r.get_rect()
self.rect.x, self.rect.y = x, y
self.r.fill(self.color)
pygame.init()
screen = pygame.display.set_mode((1280, 720))
pygame.display.set_caption("PyStoneTest")
width, height = screen.get_size()
background_default = "image\Settings\Wallpaper\default_1.jpg"
D = {}
D["Rect2"] = Rectangle(screen, (0, 200, width, 70), 0,
50, (255, 255, 0), "Rect2")
D["Rect1"] = Rectangle(screen, (0, 100, width-200, 200), 0,
100, (255, 0, 255), "Rect1")
Programme = ["Rect1", "Rect2"]
while True:
background = pygame.image.load(background_default).convert()
background = pygame.transform.scale(background, (width, height))
for event in pygame.event.get():
x,y = pygame.mouse.get_pos()
if event.type == pygame.QUIT:
pygame.quit()
for element in Programme:
if D[element].rect.collidepoint(x,y) and event.type == pygame.MOUSEBUTTONDOWN:
del Programme[Programme.index(D[element].name)]
Programme.append(D[element].name)
print(Programme)
screen.blit(background, (0, 0))
for element in Programme:
screen.blit(D[element].r, D[element].rect)
pygame.display.update()
You should first run for-loop to check all windows and use last one which collides with mouse.
elif event.type == pygame.MOUSEBUTTONDOWN:
last = None
for element in Programme:
if D[element].rect.collidepoint(event.pos):
last = element
if last:
Programme.remove(last)
Programme.append(last)
print(Programme)
Or you would have to check in reverse order - from last to first - and break loop on first matching rectangle.
elif event.type == pygame.MOUSEBUTTONDOWN:
last = None
for element in reversed(Programme):
if D[element].rect.collidepoint(event.pos):
last = element
break
if last:
Programme.remove(last)
Programme.append(last)
print(Programme)
Minimal working code with other changes
import pygame
# --- classes ---
class Rectangle(pygame.sprite.Sprite):
# I skip `x,y` because I have it in `rect`
def __init__(self, screen, rect, color, name):
super().__init__()
self.screen = screen
self.color = color
self.name = name
self.rect = pygame.Rect(rect)
self.image = pygame.Surface(self.rect.size, pygame.SRCALPHA)
self.image.fill(self.color)
def draw(self):
self.screen.blit(self.image, self.rect)
# --- functions ---
# empty
# --- main ---
pygame.init()
screen = pygame.display.set_mode((1280, 720))
screen_rect = screen.get_rect() # it can be useful to center elements on screen - `d[name].rect.center = screen_rect.center`
pygame.display.set_caption("PyStoneTest")
# raw string
background_default = r"image\Settings\Wallpaper\default_1.jpg"
# load and rescale before `while`-loop
background = pygame.image.load(background_default).convert()
background = pygame.transform.scale(background, screen_rect.size)
d = {} # PEP8: `lower_case_names` for variable
d["Rect2"] = Rectangle(screen, (0, 0, screen_rect.width-100, 70), (255, 255, 0), "Rect2")
d["Rect2"].rect.center = screen_rect.center
d["Rect1"] = Rectangle(screen, (0, 0, 70, screen_rect.height-100), (255, 0, 255), "Rect1")
d["Rect1"].rect.center = screen_rect.center
programme = ["Rect1", "Rect2"] # PEP8: `lower_case_names` for variable
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
exit() # to skip rest of while-loop
elif event.type == pygame.MOUSEBUTTONDOWN:
selected = None
for name in programme:
if d[name].rect.collidepoint(event.pos):
selected = name
if selected and selected != programme[-1]:
programme.remove(selected)
programme.append(selected)
print('after replace:', programme)
screen.blit(background, (0, 0))
for name in programme:
d[name].draw()
pygame.display.update()
I cannot help with your code since I cannot understand what you are doing but I can offer my own solution. Since pygame renders thigs that are drawn later on the top, you can change the rendering order of your rectangles by checking which rectangle is being clicked and swapping it with the last rectangle in your list.
Here is an example. The colors in my example change weirdly but that's because I am generating them on the fly just to be able to tell the different between the different rects. You shouldn't have this problem.
import pygame
pygame.init()
screen = pygame.display.set_mode((1280, 720))
pygame.display.set_caption("PyStoneTest")
rects = []
for i in range(10):
rects.append(pygame.Rect(i * 25, 100, 30, 30))
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
screen.fill((0, 0, 0))
c = 1
for rect in rects:
pygame.draw.rect(screen, (c, 100, 100), rect)
c += 20
clicked = pygame.mouse.get_pressed()
x,y = pygame.mouse.get_pos()
for rect in rects:
if (rect.collidepoint(x, y) and clicked[0]):
#swap it
rects[-1][:], rect[:] = rect[:], rects[-1][:]
pygame.display.update()
Apologies in advance if this is a simple fix but I couldn't find anything on it. I am relatively new to pygame but I can't understand why when I run this the first bar that is drawn is always half cut off. To me anyway I should start a 0,400 and draw from 0 across 40 and then up. If this is not the case please enlighten a curious mind
from pygame import *
import pygame, sys, random
pygame.init()
screen = pygame.display.set_mode((1000,400))
colour = (0, 255, 0)
array = []
x, y, z, b = -80, 0, 0, 0
flag = True
for c in range(5):
array.append(random.randint(100, 400));
for c in array:
print c
while True:
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
if len(array) == z:
flag = False
if flag == True:
b = array[z]
x += 80
z += 1
pygame.draw.line(screen, colour, (x, 400), (x, (400-b)), 40)
pygame.display.update()
pygame is drawing a line from (0,400) to (0, 400-b), with line thickness 40.
Here is an way to shift the lines so each is fully visible:
for i, b in enumerate(array):
x = i*80 + 20 # <-- add 20 to shift by half the linewidth
pygame.draw.line(screen, colour, (x, 400), (x, (400-b)), 40)
import sys
import random
import pygame
pygame.init()
screen = pygame.display.set_mode((1000,400))
colour = (0, 255, 0)
array = [random.randint(100, 400) for c in range(5)]
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
linewidth = 40
for i, b in enumerate(array):
x = i*linewidth*2 + linewidth//2
pygame.draw.line(screen, colour, (x, 400), (x, (400-b)), linewidth)
pygame.display.update()