A moving rectangle becomes stuck after hitting the edge of the window - python-3.x

I created a rectangle in the middle of the window, and used key 'w', 's', 'a', 'd', to move it. My problem is every time the rectangle hits the edge of the window is becomes stuck and cannot move any more.
import pygame, sys, time
from pygame.locals import *
class Tile:
bcolor = pygame.Color('black')
rcolor = pygame.Color('white')
def __init__(self, surface):
self.surface = surface
self.size = 30
self.x = self.surface.get_width()//2 - self.size//2
self.y = self.surface.get_height()//2 - self.size//2
self.rect = pygame.Rect(self.x, self.y, self.size, self.size)
self.speed = 10
self.rcolor = Tile.rcolor
self.bcolor = Tile.bcolor
def draw(self):
pygame.draw.rect(self.surface, self.rcolor, self.rect)
def moveup(self):
if self.rect.top < self.speed:
self.speed = self.rect.top
self.rect.move_ip(0, -self.speed)
def movedown(self):
maxbottom = self.surface.get_height()
if maxbottom - self.rect.bottom < self.speed:
self.speed = maxbottom - self.rect.bottom
self.rect.move_ip(0,self.speed)
def moveleft(self):
if self.rect.left < self.speed:
self.speed = self.rect.left
self.rect.move_ip(-self.speed, 0)
def moveright(self):
maxright = self.surface.get_width()
if maxright - self.rect.right < self.speed:
self.speed = maxright - self.rect.right
self.rect.move_ip(self.speed, 0)
def handlekeydown(self, key):
if key == K_w:
self.moveup()
if key == K_s:
self.movedown()
if key == K_a:
self.moveleft()
if key == K_d:
self.moveright()
def update(self):
self.surface.fill(self.bcolor)
self.draw()
def main():
pygame.init()
pygame.key.set_repeat(20, 20)
surfacesize = (500,400)
title = 'Practice'
framedelay = 0.02
surface = pygame.display.set_mode(surfacesize, 0, 0)
pygame.display.set_caption(title)
tile = Tile(surface)
gameover = False
tile.draw()
pygame.display.update()
while True:
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
if event.type == KEYDOWN and not gameover:
tile.handlekeydown(event.key)
tile.update()
pygame.display.update()
time.sleep(framedelay)
main()

Just look at this piece of code:
def moveup(self):
if self.rect.top < self.speed:
self.speed = self.rect.top
self.rect.move_ip(0, -self.speed)
Once you move to the top of the screen, self.rect.top becomes 0, which is smaller than self.speed, so the condition of the if statement is True and in the next line you set self.speed to 0, hence all your move_ip calls won't move the Rect (because self.speed is now 0).
If you want to prevent the Rect from leaving the screen, better just use clamp_ip:
...
def moveup(self):
self.rect.move_ip(0, -self.speed)
def movedown(self):
self.rect.move_ip(0,self.speed)
def moveleft(self):
self.rect.move_ip(-self.speed, 0)
def moveright(self):
self.rect.move_ip(self.speed, 0)
def handlekeydown(self, key):
if key == K_w:
self.moveup()
if key == K_s:
self.movedown()
if key == K_a:
self.moveleft()
if key == K_d:
self.moveright()
self.rect.clamp_ip(pygame.display.get_surface().get_rect())
...
(There are some other issues with your code, but that's another topic.)

Related

How does one make collisions for sprites in pygame?

I'm trying to make collisions for my basic 2D game using pygame. I've run into an issue where the game won't start and i'm getting an error.
playercolidecheck = MyPlayer.collide(v)
File "C:\Users\marti\Desktop\Python\PyMine\PyMineFile.py", line 53,
in collide
return pygame.sprite.spritecollideany(self, enemies)
File "C:\Users\marti\AppData\Local\Programs\Python\Python37\lib\site-
packages\pygame\sprite.py", line 1586, in spritecollideany
spritecollide = sprite.rect.colliderect
AttributeError: 'Player' object has no attribute 'rect'
I have tried to to make my own custom collision but to no avail. Here is the code for the project:
import pygame
pygame.mixer.init()
pygame.init()
win = pygame.display.set_mode((800,600))
pygame.display.set_caption("PyMine")
clock = pygame.time.Clock()
#Images
dirtimage = pygame.image.load("dirt.png")
grassimage = pygame.image.load("grass.png")
woodimage = pygame.image.load("wood.png")
playerimage = pygame.image.load("player.png")
pygame.display.set_icon(grassimage)
drawlist = []
class Block:
def __init__(self,ID,x,y,add,w,h):
self.ID = ID
self.x = x
self.y = y
self.w = w
self.h = h
if add == True:
drawlist.append(self)
def main(self):
if self.ID == 0:
win.blit(dirtimage, (self.x,self.y))
if self.ID == 1:
win.blit(grassimage, (self.x,self.y))
if self.ID == 2:
win.blit(woodimage, (self.x,self.y))
class Player:
def __init__(self,add,x,y,):
self.x = x
self.y = y
if add == True:
drawlist.append(self)
def main(self):
win.blit(playerimage, (self.x,self.y))
def DONTUSE(self,TargetX,TargetY):
if TargetX > self.x or TargetX < self.x or TargetY > self.y or TargetY < self.y: return False
return True
def collide(self, enemies):
return pygame.sprite.spritecollideany(self, enemies)
MyBlock1 = Block(0,160,160,True,32,32)
MyBlock2 = Block(1,32,0,True,32,32)
MyBlock3 = Block(2,64,0,True,32,32)
MyPlayer = Player(False,96,0)
run = True
while run:
keys = pygame.key.get_pressed()
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
MyPlayer.x -= 32
if event.key == pygame.K_RIGHT:
MyPlayer.x += 32
win.fill((255,255,255))
MyPlayer.main()
for v in drawlist:
v.main()
playercolidecheck = MyPlayer.collide(v)
if playercolidecheck == True:
MyPlayer.y -= 0.1
pygame.draw.rect(win,(255,25,25),[MyPlayer.x,MyPlayer.y,16,16])
MyPlayer.y += 0.1
pygame.display.update()
clock.tick(60)
pygame.quit()
quit()
It gives me an error and it doesn't display anything on the screen. Altough it opens a window and names it and gives it its icon.
Your Player class does not have a pygame rect object, which is required for the spritecollideany function. So passing self into this line:
return pygame.sprite.spritecollideany(self, enemies)
You are passing your own custom class Player to the function, you need to add a rect object to your class so pygame knows where it is.
So instead of using self.x self.y for player you should have a self.rect initialized at the start and use self.rect.x, self.rect.y for those variables. Making sure to update this rect as your player moves. This puts things in a format that pygame understands.

Pygame screen gets cleared on flip, but only once

So I am trying to recreate Minesweeper in pygame. Since I am only drawing a single image over my current screen when a player clicks, I do not have frames. The problem is, when the player first clicks and I draw one image a flip the display. The first time I do that, it clears the background. After that, it doesn't clear the previous images. If I try and call flip first thing, nothing happens. I tried to flip after every image (Just trying things) and nothing changed.
Code:
import pygame, random, os, sys, math
pygame.init()
font = pygame.font.SysFont('Sans Serif 7', 15)
screenX = 1240
screenY = 720
sprites = pygame.image.load(os.path.dirname(os.path.abspath(__file__)) + "\\Minesweeper\\ImageSheet.png")
spriteList = []
#tiles = 16px, icons = 26px
class Minefield():
def __init__(self, width, height, mines, surface):
self.width = width
self.height = height
self.mine = sprites.subsurface(80, 49, 16, 16)
self.rows = []
self.surface = surface
for i in range(0, width):
self.rows.append([])
for i2 in range(0, height):
self.rows[i].append(-2)
for i in range(0, mines):
print(len(self.rows))
print(len(self.rows[1]))
x = random.randint(0, width-1)
y = random.randint(0, height-1)
print(x)
print(y)
self.rows[x][y]
self.render()
def clicked(self, rawPos):
pos = (math.floor(rawPos[0]/16), math.floor(rawPos[1]/16))
val = self.rows[pos[0]][pos[1]]
if val == -2:
mines = 1
if not pos[0] == 0 and not pos[1] == 0 and self.rows[pos[0]-1][pos[1]-1] == -1:
mines += 1
if not pos[0] == 0 and self.rows[pos[0]-1][pos[1]] == -1:
mines += 1
if not pos[0] == 0 and not pos[1] == self.height and self.rows[pos[0]-1][pos[1]+1] == -1:
mines += 1
if not pos[1] == 0 and self.rows[pos[0]][pos[1]-1] == -1:
mines += 1
if not pos[1] == self.height and self.rows[pos[0]][pos[1]+1] == -1:
mines += 1
if not pos[1] == 0 and not pos[0] == self.width and self.rows[pos[0]+1][pos[1]-1] == -1:
mines += 1
if not pos[0] == self.width and self.rows[pos[0]+1][pos[1]] == -1:
mines += 1
if not pos[1] == self.height and not pos[0] == self.width and self.rows[pos[0]+1][pos[1]+1] == -1:
mines += 1
print(mines)
self.surface.blit(spriteList[mines], (pos[0]*16, pos[1]*16))
pygame.display.flip()
elif val == -1:
playing = False
return
def render(self):
for i in range(0, self.width):
for i2 in range(0, self.height):
self.surface.blit(spriteList[0], (i*16, i2*16))
pygame.display.flip()
class Main():
def __init__(self):
self.screen = pygame.display.set_mode((screenX, screenY), pygame.RESIZABLE)
spriteList.append(sprites.subsurface(16, 49, 16, 16))
for i in range(0, 8):
print(i*16)
spriteList.append(sprites.subsurface(i*16, 65, 16, 16))
self.field = Minefield(50, 30, 30, self.screen)
def gameloop(self):
while True:
for event in pygame.event.get():
if event.type == pygame.VIDEORESIZE:
screenX = event.w
screenY = event.h
self.screen = pygame.display.set_mode((event.w, event.h), pygame.RESIZABLE)
if event.type == pygame.QUIT:
return
if event.type == pygame.MOUSEBUTTONUP:
pos = pygame.mouse.get_pos()
self.field.clicked(pos)
def stop(self):
pygame.display.quit()
pygame.quit()
sys.exit("Window Closed")
main = Main()
main.gameloop()
main.stop()
What I want:
On player click the only change is a 1 appears over the cell, but instead the background gets painted over by black.
pygame.display.set_mode() creates a new window surface. You've to render the background after recreating the window surface in the resize event. When the window was initialized, then immediately 1 resize event is pending.
def gameloop(self):
while True:
for event in pygame.event.get():
if event.type == pygame.VIDEORESIZE:
screenX = event.w
screenY = event.h
self.screen = pygame.display.set_mode((event.w, event.h), pygame.RESIZABLE)
self.field.render() # <-------------
Note, when the window was resized and the window surface is recreated then the entire scene has to be redrawn.
Probably your game will work only, if the window is not resizable. When you resize the window, then a new event occurs. The surface is recreated and the background is redrawn, but the "clicked" fields are lost. So they would have to be redrawn, too.

Need suggestions for fixing ABC error?

I'm creating a boid flocking simulator and getting some errors. Suspecting they are issued by wrong usage of ABC. But I can't fix the error, been trying for a day.
the primary issue is in the Check_input class. flyers is somehow undefined and I'm trying to append them to the FlyerList if the input is registered.
Linked the whole code for full perspective.
from precode import Vector2D, intersect_rectangle_circle, intersect_circles
from abc import ABC, abstractmethod
from config import *
import pygame
class Flyer(ABC):
#abstractmethod
def draw(self):
pass
#abstractmethod
def move(self):
pass
class Boids(Flyer):
def __init__(self):
self.radius = 7
self.pos = Vector2D(100,100)
self.speed = Vector2D(1,1)
pass
def draw(self,screen):
pygame.draw.circle(screen, black, (int(self.pos.x), int(self.pos.y)),
self.radius)
pass
def move(self):
self.pos += self.speed
if self.pos.x + self.radius >= screen_res[0]:
self.speed.x *= -1
if self.pos.x - self.radius <= 0:
self.speed.x = self.speed.x * -1
if self.pos.y - self.radius >= 0:
self.speed.y *= -1
if self.pos.y + self.radius < screen_res[1]:
self.speed.y *= -1
pass
class Hoiks(Flyer):
def __init__(self):
self.radius = 9
self.pos = Vector2D(200,200)
self.speed = Vector2D(8,8)
def draw(self,screen):
pygame.draw.circle(screen, red, (int(self.pos.x), int(self.pos.y)),
self.radius)
pass
def move(self):
self.pos += self.speed
if self.pos.x + self.radius >= screen_res[0]:
self.speed.x *= -1
if self.pos.x - self.radius <= 0:
self.speed.x *= -1
if self.pos.y - self.radius >= 0:
self.speed.y *= -1
if self.pos.y + self.radius < screen_res[1]:
self.speed.y *= -1
class FlyerList():
flyers = []
def move_all(self):
for flyer in self.flyers:
flyer.move()
def draw_all(self):
for flyer in self.flyers:
flyer.draw()
class Check_input():
def boidspawn(self, event):
if event.type == pygame.MOUSEBUTTONDOWN:
flyers.append(Boids)
def hoikspawn(self, event):
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
flyers.append(Hoiks)
class Game:
def __init__(self):
pygame.init()
self.flyer_list = FlyerList()
self.check_input = Check_input()
def Gameloop(self,event):
while 1:
self.flyer_list.move_all()
self.flyer_list.draw_all()
self.check_input.boidspawn(event)
self.check_input.hoikspawn(event)
# self.check_collision()
def game_code():
# pygame.init()
game = Game()
boid = Boids()
hoik = Hoiks()
bats = FlyerList
check = Check_input()
screen = pygame.display.set_mode(screen_res)
clock = pygame.time.Clock()
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT or event.type == pygame.KEYDOWN and
event.key == pygame.K_ESCAPE:
exit()
pygame.draw.rect(screen, (255,255,255), (0, 0, screen.get_width(),
screen.get_height()))
time_passed = clock.tick(30) # limit to 30FPS
time_passed_seconds = time_passed / 1000.0 # convert to seconds
x, y = pygame.mouse.get_pos()
game.Gameloop(event)
pygame.display.update()
if __name__ == '__main__':
game_code()

Getting an error message in pygame

import pygame
import random
from os import path
img_dir = path.join(path.dirname(__file__), 'img')
snd_dir = path.join(path.dirname(__file__), 'sound')
WIDTH = 800
HEIGHT = 600
FPS = 50
WHITE=(255, 255, 255)
BLACK=(0, 0, 0)
RED=(255, 0, 0)
GREEN=(0, 255, 0)
BLUE=(0, 0, 255)
YELLOW=(255, 255, 0)
pygame.init()
pygame.mixer.init()
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("My Game")
clock = pygame.time.Clock()
font_name = pygame.font.match_font('arial')
end = True
def start_screen():
draw_text(screen, "SPACE SHOOTING", 70, WIDTH/2, HEIGHT/4)
draw_text(screen, "INSTRUCTIONS", 25, WIDTH/2, HEIGHT/2)
draw_text(screen, "Press Left arrow key to move left", 20, WIDTH/2, HEIGHT*2/3.5)
draw_text(screen, "Press Right arrow key to move right", 20, WIDTH/2, HEIGHT*2/3.3)
draw_text(screen, "Spacebar to shoot", 20, WIDTH/2, HEIGHT*2/3.1)
draw_text(screen, "Press a key to begin", 20, WIDTH/2, HEIGHT*3/4)
pygame.display.flip()
wait = True
while wait:
clock.tick(FPS)
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
if event.type == pygame.KEYUP:
if event.key == pygame.K_SPACE:
wait = False
def draw_text(surf, text, size, x, y):
font = pygame.font.Font(font_name, size)
text_surface = font.render(text, True, WHITE)
text_rect = text_surface.get_rect()
text_rect.midtop = (x, y)
surf.blit(text_surface, text_rect)
class Player(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.transform.scale(player_img, (50, 38))
self.image.set_colorkey(BLACK)
self.rect = self.image.get_rect()
self.radius = 20
self.rect.centerx = WIDTH/2
self.rect.bottom = HEIGHT - 10
self.speedx = 0
def update(self):
self.speedx = 0
keystate = pygame.key.get_pressed()
if keystate[pygame.K_LEFT]:
self.speedx = -5
if keystate[pygame.K_RIGHT]:
self.speedx = 5
self.rect.x += self.speedx
if self.rect.right > WIDTH:
self.rect.right = WIDTH
if self.rect.left < 0:
self.rect.left = 0
def shoot(self):
bullet = Bullets(self.rect.centerx, self.rect.top)
all_sprites.add(bullet)
bullets.add(bullet)
class Aliens(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = aliens_img
self.image.set_colorkey(BLACK)
self.rect = self.image.get_rect()
self.radius = int(self.rect.width*.85/2)
self.rect.x = random.randrange(WIDTH - self.rect.width)
self.rect.y = random.randrange(-100, -40)
self.speedy = random.randrange(1, 8)
def update(self):
self.rect.y += self.speedy
if self.rect.top > HEIGHT + 10 or self.rect.left < -25 or self.rect.right > WIDTH + 20:
self.rect.x = random.randrange(WIDTH - self.rect.width)
self.rect.y = random.randrange(-100, -40)
self.speedy = random.randrange(1, 8)
class SuperAliens(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = superaliens_img
self.image.set_colorkey(BLACK)
self.rect = self.image.get_rect()
self.radius = int(self.rect.width*.85/2)
self.rect.x = random.randrange(WIDTH - self.rect.width)
self.rect.y = random.randrange(-100, -40)
self.speedy = random.randrange(1, 8)
self.speedx = random.randrange(-3, 3)
def update(self):
self.rect.x += self.speedx
self.rect.y += self.speedy
if self.rect.top > HEIGHT + 10 or self.rect.left < -25 or self.rect.right > WIDTH + 20:
self.rect.x = random.randrange(WIDTH - self.rect.width)
self.rect.y = random.randrange(-100, -40)
self.speedy = random.randrange(1, 8)
def shoot1(self):
sbullet = SBullets(self.rect.centerx, self.rect.bottom)
all_sprites.add(sbullet)
bullets.add(sbullet)
class SBullets(pygame.sprite.Sprite):
def __init__(self, x, y):
pygame.sprite.Sprite.__init__(self)
self.image = sbullet_img
self.image.set_colorkey(BLACK)
self.rect = self.image.get_rect()
self.rect.bottom = y
self.rect.centerx = x
self.speedy = +10
def update(self):
self.rect.y += self.speedy
if self.rect.top < 0:
self.kill()
class Bullets(pygame.sprite.Sprite):
def __init__(self, x, y):
pygame.sprite.Sprite.__init__(self)
self.image = bullet_img
self.image.set_colorkey(BLACK)
self.rect = self.image.get_rect()
self.rect.bottom = y
self.rect.centerx = x
self.speedy = -10
def update(self):
self.rect.y += self.speedy
if self.rect.bottom < 0:
self.kill()
class Explode(pygame.sprite.Sprite):
def __init__(self, center, size):
pygame.sprite.Sprite.__init__(self)
self.size = size
self.image = explode[self.size][0]
self.rect = self.image.get_rect()
self.rect.center = center
self.frame = 0
self.last_update = pygame.time.get_ticks()
self.frame_rate = 2
def update(self):
now = pygame.time.get_ticks()
if now - self.last_update > self.frame_rate:
self.last_update = now
self.frame += 1
if self.frame == len(explode[self.size]):
self.kill()
else:
center = self.rect.center
self.image = explode[self.size][self.frame]
self.rect = self.image.get_rect()
self.rect.center = center
background = pygame.image.load(path.join(img_dir, "back.png")).convert()
background_rect = background.get_rect()
player_img = pygame.image.load(path.join(img_dir, "playerShip2_blue.png")).convert()
superaliens_img = pygame.image.load(path.join(img_dir, "enemyBlack4.png")).convert()
aliens_img = pygame.image.load(path.join(img_dir, "enemyBlack1.png")).convert()
bullet_img = pygame.image.load(path.join(img_dir, "laserRed16.png")).convert()
sbullet_img = pygame.image.load(path.join(img_dir, "laserRed11.png")).convert()
explode = {}
explode['super']=[]
explode['small']=[]
for i in range(9):
filename = 'regularExplosion02.png'.format(1)
img = pygame.image.load(path.join(img_dir, filename)).convert()
img.set_colorkey(BLACK)
img_super = pygame.transform.scale(img, (75, 75))
explode ['super'].append(img_super)
img_small = pygame.transform.scale(img, (32, 32))
explode ['small'].append(img_small)
#pygame.mixer.music.load(path.join(snd_dir, 'Orbital.mp3'))
#pygame.mixer.music.set_volume(0.4)
#pygame.mixer.music.play(loops=-1)
end_game = True
running = True
while running:
if end_game:
start_screen()
end_game = False
all_sprites = pygame.sprite.Group()
aliens = pygame.sprite.Group()
superaliens = pygame.sprite.Group()
bullets = pygame.sprite.Group()
sbullets = pygame.sprite.Group()
player = Player()
all_sprites.add(player)
for i in range(5):
m = Aliens()
all_sprites.add(m)
aliens.add(m)
for j in range(1):
n = SuperAliens()
all_sprites.add(n)
superaliens.add(n)
score = 0
clock.tick(FPS)
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
player.shoot()
all_sprites.update()
hits = pygame.sprite.groupcollide(aliens, bullets, True, True)
for hit in hits:
score += 1
m = Aliens()
expl = Explode(hit.rect.center, 'small')
all_sprites.add(expl)
all_sprites.add(m)
aliens.add(m)
hits = pygame.sprite.groupcollide(superaliens, bullets, True, True)
for hitt in hits:
score += 5
n = SuperAliens()
expl1 = Explode(hitt.rect.center, 'super')
all_sprites.add(expl1)
all_sprites.add(n)
superaliens.add(n)
hits = pygame.sprite.spritecollide(player, aliens, True)
for hit in hits:
expl = Explode(hit.rect.center, 'small')
all_sprites.add(expl)
if hits:
end_game = True
hits = pygame.sprite.spritecollide(player, superaliens, True)
for hitt in hits:
expl1 = Explode(hitt.rect.center, 'super')
all_sprites.add(expl1)
if hits:
end_game = True
screen.fill(BLACK)
screen.blit(background, background_rect)
all_sprites.draw(screen)
draw_text(screen,"SCORE" +str(score), 22, WIDTH/2, 10)
#after drwing everything flip the display
pygame.display.flip()
pygame.quit()
Sorry for the bad formatting but couldn't upload it with the proper formatting. Its my first pygame, so im not good in it. The program is working good, but every time when i close the window, its is showing me this error.
Traceback (most recent call last):
File "/Users/Documents/game.py", line 221, in
start_screen()
File "/Users/Documents/game.py", line 41, in start_screen
for event in pygame.event.get():
pygame.error: video system not initialized
I was also trying to make the super aliens shoot randomly towards the player, and that thing is not working as well.A little help would be appreciated. Thanks
After the line:
pygame.quit()
put:
exit()
Basically, pygame.quit() tells pygame that you are done with it. After you call it in your event loop, pygame no longer can draw things to the screen, but you still try to make it do so later in your program. Calling exit() makes python exit so that pygame is not told to draw anything.

Python, please help me that why my rect cant move

I was trying to make a basic game using pygame, but the rectangle i created can not move after i press the key, please teach me how to fix it,thank you
import pygame, sys, time
from pygame.locals import *
class Tile:
def __init__(self,surface):
self.surface = surface
self.x = 250
self.y = 200
self.position = (self.x, self.y)
self.color = pygame.Color('red')
self.speed = 5
self.size = 30
self.rect = pygame.Rect(self.position[0],self.position[1],self.size,self.size)
def draw(self):
pygame.draw.rect(self.surface,self.color,self.rect)
def moveUp(self):
if self.rect.top < self.speed:
self.speed = self.rect.top
self.y = self.y - self.speed
def moveDown(self):
maxBottom = self.surface.get_height()
if maxBottom - self.rect.bottom < self.speed:
self.speed = maxBottom - self.rect.bottom
self.y = self.y + self.speed
def moveLeft(self):
if self.rect.left < self.speed:
self.speed = self.rect.left
self.x = self.x - self.speed
def moveRight(self):
maxRight = self.surface.get_width()
if maxRight - self.rect.right < self.speed:
self.speed = maxRight - self.rect.right
self.x = self.x + self.speed
def move(self,key):
if key == K_w:
self.moveUp()
if key == K_s:
self.moveDown()
if key == K_a:
self.moveLeft()
if key == K_d:
self.moveRight()
def main():
pygame.init()
pygame.key.set_repeat(20, 20)
surfaceSize = (500, 400)
windowTitle = 'Pong'
frameDelay = 0.01
surface = pygame.display.set_mode(surfaceSize, 0, 0)
pygame.display.set_caption(windowTitle)
gameOver = False
tile = Tile(surface)
tile.draw()
pygame.display.update()
while True:
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
if event.type == KEYDOWN and not gameOver:
tile.move(event.key)
pygame.display.update()
time.sleep(frameDelay)
main()
I was trying to make a basic game using pygame, but the rectangle i created can not move after i press the key, please teach me how to fix it,thank you
You're only updating your own x and y variables, and not the PyGame ones for the rect, you can fix it quickest in the draw function, but it's really an updating operation so should go in those functions:
def draw(self):
self.rect.top = self.y # You need to update the position of the rect
self.rect.left = self.x # and not just your own x, y variables.
pygame.draw.rect(self.surface,self.color,self.rect)
Then your indentation for updating the display is off, but you need an extra line anyway:
while True:
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
if event.type == KEYDOWN and not gameOver:
tile.move(event.key)
surface.fill((0, 0, 0)) # Fill the screen with black to hide old rect
tile.draw() # Re-draw the tile in new position
pygame.display.update() # Update the display
Last thing to fix, don't use time.sleep for the frame delay, use PyGame's inbuilt clock function. Here's a tutorial: https://www.youtube.com/watch?v=pNjSyBlbl_Q&nohtml5=False
Your if statements looks suspect to me:
if self.rect.left < self.speed
How is self.speed related to self.rect.left?
You should instead be shifting the entire rect by self.speed in the direction you want. Try that.
I also find adding print statements throughout the code and looking at the console can help a lot. An even better solution would be to use a debugger.

Resources