I made a platformer, but something went wrong - python

I have started with making a platformer, but my first attempt was a big failure.
The code is:
import pygame as p
p.init()
win = p.display.set_mode((1280, 720))
p.display.set_caption('Project')
player = [p.image.load('sprite/cube.jpg')]
bg = [p.image.load('sprite/bgone.jpg')]
clock = p.time.Clock()
x = 1280 / 2
y = 720 / 1.5
width = 56
height = 60
speed = 10
delaytime = 50
jump = False
jumpspeed = 10
anim = 0
def draw():
global anim
global x
global y
if anim + 1 >= 30:
anim = 0
win.blit(bg, (0, 0))
win.blit(player, (x, y))
p.display.update()
run = True
while run:
clock.tick(30)
for event in p.event.get():
if event.type == p.QUIT:
run = False
k = p.key.get_pressed()
if k [p.K_LEFT] and x > 5:
x = x - speed
if k [p.K_RIGHT] and x < (1280 - width - 5):
x = x + speed
if k [p.K_a] and x > 5:
x = x - speed
if k [p.K_d] and x < (1280 - width - 5):
x = x + speed
if k [p.K_SPACE]:
jump = True
if not jump:
bhop = False
if jump:
speed = 15
if jumpspeed >= -10:
if jumpspeed < 0:
y += (jumpspeed ** 2) / 2
else:
y -= (jumpspeed ** 2) / 2
jumpspeed -= 1
else:
jump = False
jumpspeed = 10
speed = 10
draw()
p.quit()
quit()
The error is:
Traceback (most recent call last):
File "it dosen't matter", line 68, in <module>
draw()
File "it dosen't matter", line 30, in draw
win.blit(bg, (0, 0))
TypeError: argument 1 must be pygame.Surface, not list
I don't know what is this. I watched a lot of videos but nobody helped, so i tried ALL ide's i know, but all give that error. Tried to re-write the programm, but still i see this. What am i doing wrong?

The error message is quite clear: if you call blit() the first argument has to be a Surface, not a list.
Looking at your code
bg = [p.image.load('sprite/bgone.jpg')]
...
win.blit(bg, (0, 0))
we see that you indeed pass a list as first argument to the blit function.
It's not clear why you put the background image into a list in the first place, so just change your code to
bg = p.image.load('sprite/bgone.jpg').convert()
...
win.blit(bg, (0, 0))
convert() ensures the bg-Surface has the same pixel format as the display Surface, which is important for the game's performance.

Related

I've been making conway's game of life in python, why doesn't it work?

So there must be something wrong with the code which detects wether it should be alive or not in Cell.update(), but the glider i hardcoded in is not working as intended. The first and second generations work as intended, but on the third it dies out. Anyone know what the problem is? I know the code is a bit messy, but I'm quite new to python so it is expected. Thanks in advance!
Here is the code:
import pygame
"""
rules:
1. Any live cell with two or three live neighbours survives.
2. Any dead cell with three live neighbours becomes a live cell.
3. All other live cells die in the next generation. Similarly, all other dead cells stay dead.
number cells on screen = 32x18
cell size = 30x30
"""
# variables
WIDTH = 960
HEIGHT = 540
TITLE = "Conway's Game Of Life"
GRID_COLOUR = (200, 200, 200)
BG_COLOUR = (255, 255, 255)
grid = [[False] * 32] * 18
cells = []
live_queue = []
die_queue = []
# window
wn = pygame.display.set_mode((WIDTH, HEIGHT), vsync=1)
pygame.display.set_caption(TITLE)
# classes
class Cell:
def __init__(self, x, y, alive, index_x, index_y):
self.x = x
self.y = y
self.alive = alive
self.indexX = index_x
self.indexY = index_y
def die(self):
self.alive = False
def live(self):
self.alive = True
def get_index(self):
return self.indexX, self.indexY
def update(self):
grid_temp = grid[self.indexY]
grid_temp.pop(self.indexY)
grid_temp.insert(self.indexY, self.alive)
grid.pop(self.indexY)
grid.insert(self.indexX, grid_temp)
adjacent_alive = 0
for i in cells:
if i.x == self.x - 30 and i.y == self.y and i.alive:
adjacent_alive += 1
elif i.x == self.x + 30 and i.y == self.y and i.alive:
adjacent_alive += 1
elif i.x == self.x and i.y == self.y - 30 and i.alive:
adjacent_alive += 1
elif i.x == self.x and i.y == self.y + 30 and i.alive:
adjacent_alive += 1
elif i.x == self.x - 30 and i.y == self.y - 30 and i.alive:
adjacent_alive += 1
elif i.x == self.x - 30 and i.y == self.y + 30 and i.alive:
adjacent_alive += 1
elif i.x == self.x + 30 and i.y == self.y - 30 and i.alive:
adjacent_alive += 1
elif i.x == self.x + 30 and i.y == self.y + 30 and i.alive:
adjacent_alive += 1
if self.alive:
if adjacent_alive < 2:
return False
elif adjacent_alive > 3:
return False
else:
return True
if not self.alive:
if adjacent_alive == 3:
return True
else:
return False
def render(self):
if self.alive:
pygame.draw.rect(wn, (0, 0, 0), (self.x, self.y, 30, 30))
# functions
def render_grid():
for y in range(0, HEIGHT, 30):
pygame.draw.line(wn, GRID_COLOUR, (0, y), (WIDTH, y))
for x in range(0, WIDTH, 30):
pygame.draw.line(wn, GRID_COLOUR, (x, 0), (x, HEIGHT))
def parse_to_x_y(x, y):
return x * 30, y * 30
def parse_to_index(x, y):
return int(x / 30), int(y / 30)
indexX = 0
indexY = 0
x_pos = 0
y_pos = 0
for y_ in range(18):
for x_ in range(32):
cells.append(Cell(x_pos, y_pos, False, indexX, indexY))
indexX += 1
x_pos += 30
y_pos += 30
x_pos = 0
indexY += 1
cells[2].live()
cells[35].live()
cells[65].live()
cells[66].live()
cells[67].live()
# main loop
fps = 1
clock = pygame.time.Clock()
while True:
# start_time = time.time()
wn.fill(BG_COLOUR)
for item in cells:
item.render()
render_grid()
# events loop
for event in pygame.event.get():
if event.type == pygame.QUIT:
quit()
for item in cells:
if item.update():
live_queue.append(item)
else:
die_queue.append(item)
for i in live_queue:
i.live()
for i in die_queue:
i.die()
pygame.display.update()
clock.tick(fps)
# end_time = time.time()
# print(round(1 / (end_time - start_time)), "fps")
The problem is that you don't reset your queues in the main loop.
So add this before adding to the queues:
live_queue = [] # <----
die_queue = [] # <----
for item in cells:
if item.update():
live_queue.append(item)
else:
die_queue.append(item)
Some other remarks
You never use grid or grid_temp in a useful way. Even the operations you make on them are strange. Any way, you can just remove all references to them.
You never use the indexX or indexY attributes, nor the method around it, nor the corresponding arguments to the constructor. All that can go.
You should avoid scanning all the cells just to find the (up to) 8 neighbors of one cell: this has a bad impact on performance.
I agree with commenter Rabbid76, in that you need to update the entire grid at once, not cell by cell. This is usually done by using two separate grids, an "previous state" grid and a "new state grid". Loop through each position in the "new state" grid and calculate its number of live neighbors using the "previous state" grid. After the entire "new state" grid is calculated, you can copy to "new state" grid to the "old state" grid.
Another fatal flaw in your algorithm is grid = [[False] * 32] * 18. This will not work as expected in Python. With this code, each row is a reference to the same array. For instance, the expression grid[0] is grid[1] will evaluate to True. If you set a certain cell in the grid to true, the entire column will be set to true. You can fix this via the code:
grid=[]
for r in range(18):
row=[]
for c in range(32):
row.append(False)
grid.append(row)
Though it isn't directly related to the bug, I suggest a bit of a redesign of your algorithm. It is not really needed to encapsulate each cell in a class; doing so creates a redundancy between the grid and list of cells. This also leads you to identify cells by their pixel position (hence the i.x == self.x - 30 clause), which can easily lead to bugs. I suggest checking adjacent indices in the grid variable instead. Try looking into https://www.geeksforgeeks.org/conways-game-life-python-implementation/ for some inspiration.

Why does my pygame collision detections not work? [duplicate]

This question already has answers here:
How do I detect collision in pygame?
(5 answers)
Closed 1 year ago.
Im relatively new to Python and Pygame. I'm making a game where a circle appears at a random location on the window and you have to touch it to get a point. I've programmed it to teleport to another random location when you touch the circle. The problem is when I try to detect collision between the circle and the player it basically teleport the circle non-stop. I also made a print function which prints hi when it detects collision and it also prints non-stop. I usually try to figure out the problem, but I really don't see what Im doing wrong, I'd appreciate all help given.
enter code here
import pygame
import random
vel = 2
pygame.init()
pygame.font.init()
fps = 60
win = pygame.display.set_mode((900, 500), pygame.RESIZABLE)
pygame.display.set_caption("Test")
#icon = pygame.image.load('icon.png')
#pygame.display.set_icon(icon)
background = pygame.image.load('Background.png')
ghost = pygame.image.load("ghost.png")
ghostrect = ghost.get_rect()
circle = pygame.image.load("circle.png")
circlerect = circle.get_rect()
def main():
a = random.randint(0, 900)
b = random.randint(0, 500)
clock = pygame.time.Clock()
run = True
while run:
keys_pressed = pygame.key.get_pressed()
if keys_pressed[pygame.K_d] and ghostrect.x + 55 <= 900:
ghostrect.x += vel
if keys_pressed[pygame.K_a] and ghostrect.x + 5 >= 0:
ghostrect.x -= vel
if keys_pressed[pygame.K_s] and ghostrect.y + 63 <= 500:
ghostrect.y += vel
if keys_pressed[pygame.K_w] and ghostrect.y >= 0:
ghostrect.y -= vel
if circlerect.colliderect(ghostrect):
a = random.randint(0, 900)
b = random.randint(0, 500)
win.blit(background, (0, 0))
win.blit(circle, (a, b))
win.blit(ghost, (ghostrect.x + 500, ghostrect.y + 210))
pygame.display.update()
clock.tick(fps)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
if __name__ == "__main__":
main()
You haven't set ghostrect's value. By default, pygame.Rect objects position values are 0. You also have not set circlerect's value, so its position is also at (0, 0).
Therefore, right now if circlerect.colliderect(ghostrect): will always return true.
All you need to do is to give them position values to fix the problem.
Give ghostrect some position. I have chosen (100, 100), that's completely up yo you.
ghostrect = ghost.get_rect()
#give the rect some position value
ghostrect.x = 100
ghostrect.y = 100
Give circlerect the random position instead of assigning it to a and b.
def main():
#remove them
#a = random.randint(0, 900) #this
#b = random.randint(0, 500) #and this
circlerect.x = random.randint(0, 900)#add this
circlerect.y = random.randint(0, 500)#and add this
#...
while run:
#...
if circlerect.colliderect(ghostrect):
#remove this
#a = random.randint(0, 900) #this
#b = random.randint(0, 500) #and this
circlerect.x = random.randint(0, 900)#add this
circlerect.y = random.randint(0, 500)#and add this
Then draw the circle at this position instead of a and b.
win.blit(circle, (circlerect.x, circlerect.y))

When I start this code, i found a problem with error Traceback (most recent call last) in my code with pygame module

I have problem with function. I starting learn pygame with video course, and this is my first pygame code. My .py code:
import pygame
pygame.init()
win = pygame.display.set_mode((1280, 720))
pygame.display.set_caption("text.")
walkaniml = pygame.image.load('left1.png')
walkanimr = pygame.image.load('right1.png')
stickmanStand = pygame.image.load('stickman.png')
clock = pygame.time.Clock()
x = 250
y = 400
widht = 271
height = 293
speed = 5
jump = False
jumplov = 10
left = False
right = False
animcount = 0
def drawcube():
global animcount
win.fill((255, 218, 185))
if animcount + 1 >= 24:
animcount = 0
if left:
win.blit(walkaniml(animcount // 1, (x, y)))
elif right:
win.blit(walkanimr(animcount // 1, (x, y)))
else:
win.blit(stickmanStand, (x, y))
pygame.display.update()
run = True
while run:
clock.tick(24)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT] and x > 1:
x -= speed
left = True
right = False
elif keys[pygame.K_RIGHT] and x < 1280 - widht - 1:
x += speed
left = False
right = True
else:
left = False
right = False
animcount = 0
if not(jump):
if keys[pygame.K_DOWN] and y < 720 - height - 1:
y += speed
if keys[pygame.K_SPACE]:
jump = True
else:
if jumplov >= -10:
if jumplov < 0:
y += (jumplov ** 2) / 3
else:
y -= (jumplov ** 2) / 3
jumplov -= 1
else:
jump = False
jumplov = 10
enter image description here
drawcube()
I wanna do a mini-game with stickman, and i found a very big problem, when I start game in cmd and I'm going to web to found decision, but.. I don't find him. Please guys, I realy need help((
walkaniml and walkanimr are pygame.Surface objects. You can't call an object:
win.blit(walkaniml(animcount // 1, (x, y)))
win.blit(walkaniml, (x, y))
If walkaniml and walkanimr are a list of Surfaces, you can get an element from the lists by it's index with subscription (even if the list contains only 1 element):
walkaniml = [ pygame.image.load('left1.png') ]
walkanimr = [ pygame.image.load('right1.png') ]
if left:
if animcount >= len(walkaniml):
animcount = 0
win.blit(walkaniml[animcount], (x, y))
elif right:
if animcount >= len(walkanimr):
animcount = 0
win.blit(walkanimr[animcount], (x, y))

Conway's Game of Life Python / PyGame printing error [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
This question does not appear to be about programming within the scope defined in the help center.
Closed 2 years ago.
Improve this question
I'm new to python and PyGame and wanted to get some experience by doing what i thought would be a simple project. I can't tell if my error is in my game logic or my PyGame printing. I created two function, one that fills the grid with random values and one that fills the grid with a "Blinker". The program runs without error, however, the rules of the game are not followed. For example, When the "blinker" is set, the program's second frame clears the screen instead of rotating the "blinker".
Any help diagnosing this problem would be appreciated!
import pygame
import random
pygame.init()
# Colors
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
# Sizes
size = (600, 600)
width = 20
height = 20
margin = 1
x_size = 600 / width
y_size = 600 / height
def init_grid():
return [[0 for x in range(x_size)] for y in range(y_size)]
def make_spinner(grind):
grid[0][0] = 1
grid[10][10] = 1
grid[10][11] = 1
grid[10][12] = 1
def random_grid(grid):
for x in range(x_size):
for y in range(y_size):
grid[x][y] = random.randint(0, 1)
def print_grid(screen, grid):
for x in range(x_size):
for y in range(y_size):
if grid[x][y] == 1:
pygame.draw.rect(
screen, BLACK, (x * width, y * height, width, height))
else:
pygame.draw.rect(
screen, BLACK, (x * width, y * height, width, height), margin)
def count_neighbours(grid, x, y):
count = 0
for i in range(-1, 1):
for j in range(-1, 1):
count += grid[x + i][y + j]
return count - grid[x][y]
def update_grid(grid):
next_grid = init_grid()
for x in range(x_size):
for y in range(y_size):
if x == 0 or x == x_size - 1 or y == 0 or y == y_size - 1:
next_grid[x][y] = 0
else:
count = count_neighbours(grid, x, y)
value = grid[x][y]
if value == 1 and (count == 2 or count == 3):
next_grid[x][y] = 1
elif value == 0 and count == 3:
next_grid[x][y] = 1
else:
next_grid[x][y] = 0
return next_grid
# Initialise game engine
screen = pygame.display.set_mode(size)
pygame.display.set_caption("The Game of Life")
running = True
clock = pygame.time.Clock()
grid = init_grid()
# random_grid(grid)
make_spinner(grid)
# Game loop
while running:
# Check for exit
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
screen.fill(WHITE)
print_grid(screen, grid)
next_grid = update_grid(grid)
pygame.display.update()
grid = next_grid
clock.tick(2)
pygame.quit()
Your count_neighbors function doesn't iterate over the right cells. range(-1,1) iterates over {-1,0} not {-1,0,1}.
Instead, use:
def count_neighbours(grid, x, y):
count = 0
for i in range(-1,2):
for j in range(-1,2):
count += grid[x + i][y + j]
return count - grid[x][y]

Bouncing Ball doesn't come back pygame

import pygame
pygame.init()
width = 400
hight = 600
screen = pygame.display.set_mode((width, hight))
pygame.display.set_caption("Engine")
dot = pygame.image.load("KreisSchwarz.png")
clock = pygame.time.Clock()
running = True
WHITE = (255, 255, 255)
# Set (x, y) for Dot
def updateDot(x, y):
screen.blit(dot, (x, y))
# Display Dot at (x, y)
def update(fps=30):
screen.fill(WHITE)
updateDot(x, y)
pygame.display.flip()
return clock.tick(fps)
# Quit if User closes the window
def evHandler():
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
running = False
yKoords = []
(x, y) = (300, 200)
t = 1 # time variable
a = 2 # acceleration constant
tol = 40 # tolerance
i = 0 # just some iterator
# MAIN LOOP
while running:
evHandler()
update()
y += a * (t ^ 2)
t += 1
yKoords.append(int(y))
i += 1
if (y < (hight + tol)) and (y > (hight - tol)):
y = 580
yKoords.reverse()
update()
for q in range(i):
evHandler()
y = yKoords[q]
update()
if q == i - 1: # Because i didn't write the Part for the Dot coming back down
running = False
This is my Code for a Ball accelerating down and then jumping back up.
My Problem is, that the code works fine until the if statement. There the Programm just displays the Ball at the last position in yKoords and waits until the for loop finishes. If i remove the for loop the Ball gets displayed at y=580 and stops but thats fine.
Please help i have no idea whats wrong about this.
Don't do a separate process loop in the main loop.
It is sufficient to invert the direction, when the ball bounce on the ground (abs(y - hight)) or the ball reaches the top (t == 0).
direction = 1
while running:
evHandler()
update()
y += (a * (t ^ 2)) * direction
t += direction
if abs(y - hight) < tol:
y = 580
t -= 1
direction *= -1
elif t == 0:
direction *= -1

Categories