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()
Related
I have a global variable, 'is_game_on' set to 'False' to start with. I have a turtle which responds to .ondrag() function. My program works perfectly fine if I change the 'is_game_on' variable to 'True' (The main program runs in a while loop when 'is_game_on' is 'True').
In the same Screen I have created turtle (a text- 'Click to start') in the top right of the screen, which I want to return 'is_game_on' = 'True' when the mouse is clicked on it so that the rest of my program starts working there after. However, my screen gets closed when I click the mouse. I think this is because of the command screen.exitonclick() at the end. Appreciate any suggestions how to avoid this problem.
Below is my code. I want to start with 'is_game_on == False' and with the output a static display. Then when I click the mouse on 'Click to Start', a mechanism to trigger 'is_game_on" as True and then the ball starts bouncing up and down.
from turtle import Screen, Turtle
import time
# is_game_on = False
is_game_on = True
def click(i, j):
global is_game_on
if i >= 250 and j >= 300:
is_game_on = True
print(is_game_on)
return is_game_on
class Ball(Turtle):
def __init__(self):
super().__init__()
self.shape('circle')
self.color('black')
self.shapesize(stretch_wid=2, stretch_len=2)
self.penup()
self.speed(6)
self.goto(0, -355)
self.x_move = 0
self.y_move = 1
self.move_speed = 10
def move(self):
xcor_new = self.xcor() + self.x_move
ycor_new = self.ycor() + self.y_move
self.goto(xcor_new, ycor_new)
def bounce_y(self):
self.y_move *= -1
class Paddle(Turtle):
def __init__(self):
super().__init__()
self.shape('square')
self.penup()
self.goto(0, -380)
self.color('blue')
self.shapesize(stretch_wid=.5, stretch_len=10)
def move(self,i, j):
self.goto(i, -380)
class Start(Turtle):
def __init__(self):
super().__init__()
self.penup()
self.goto(250, 300)
self.color('blue')
self.shapesize(stretch_wid=4, stretch_len=10)
self.hideturtle()
self.write('Click to Start', font=('Arial', 35, 'bold'))
screen = Screen()
screen.colormode(255)
screen.bgcolor('white')
screen.setup(1200, 800)
screen.tracer(0)
paddle = Paddle()
ball = Ball()
screen.listen()
paddle.ondrag(paddle.move)
screen.onclick(click)
start = Start()
while is_game_on:
time.sleep(0)
screen.update()
ball.move()
if ball.ycor() >= 375:
ball.bounce_y()
if (abs(ball.xcor() - paddle.xcor()) < 120) and ball.ycor() == -355:
ball.bounce_y()
screen.update()
screen.exitonclick()
After lot of trial and errors and lot of web searches, I found the solution.
The screen closing problem can be simply avoided by importing turtle and adding turtle.done() command just before screen.exitonclick() command. The complete code will be.
from turtle import Screen, Turtle
import time
import turtle
is_game_on = False
# is_game_on = True
def click(i, j):
global is_game_on
if i >= 250 and j >= 300:
is_game_on = True
print(is_game_on)
return is_game_on
class Ball(Turtle):
def __init__(self):
super().__init__()
self.shape('circle')
self.color('black')
self.shapesize(stretch_wid=2, stretch_len=2)
self.penup()
self.speed(6)
self.goto(0, -355)
self.x_move = 0
self.y_move = 1
self.move_speed = 10
def move(self):
xcor_new = self.xcor() + self.x_move
ycor_new = self.ycor() + self.y_move
self.goto(xcor_new, ycor_new)
def bounce_y(self):
self.y_move *= -1
class Paddle(Turtle):
def __init__(self):
super().__init__()
self.shape('square')
self.penup()
self.goto(0, -380)
self.color('blue')
self.shapesize(stretch_wid=.5, stretch_len=10)
def move(self,i, j):
self.goto(i, -380)
class Start(Turtle):
def __init__(self):
super().__init__()
self.penup()
self.goto(250, 300)
self.color('blue')
self.shapesize(stretch_wid=4, stretch_len=10)
self.hideturtle()
self.write('Click to Start', font=('Arial', 35, 'bold'))
screen = Screen()
screen.colormode(255)
screen.bgcolor('white')
screen.setup(1200, 800)
screen.tracer(0)
paddle = Paddle()
ball = Ball()
screen.listen()
paddle.ondrag(paddle.move)
screen.onclick(click)
start = Start()
while is_game_on:
time.sleep(0)
screen.update()
ball.move()
if ball.ycor() >= 375:
ball.bounce_y()
if (abs(ball.xcor() - paddle.xcor()) < 120) and ball.ycor() == -355:
ball.bounce_y()
screen.update()
turtle.done()
screen.exitonclick()
The animation can work by moving the while loop into the click() function. The code will be as follows.
from turtle import Screen, Turtle
import time
import turtle
is_game_on = False
# is_game_on = True
def click(i, j):
global is_game_on
if i >= 250 and j >= 300:
is_game_on = True
print(is_game_on)
while is_game_on:
time.sleep(0)
screen.update()
ball.move()
if ball.ycor() >= 375:
ball.bounce_y()
if (abs(ball.xcor() - paddle.xcor()) < 120) and ball.ycor() == -355:
ball.bounce_y()
return is_game_on
class Ball(Turtle):
def __init__(self):
super().__init__()
self.shape('circle')
self.color('black')
self.shapesize(stretch_wid=2, stretch_len=2)
self.penup()
self.speed(6)
self.goto(0, -355)
self.x_move = 0
self.y_move = 1
self.move_speed = 10
def move(self):
xcor_new = self.xcor() + self.x_move
ycor_new = self.ycor() + self.y_move
self.goto(xcor_new, ycor_new)
def bounce_y(self):
self.y_move *= -1
class Paddle(Turtle):
def __init__(self):
super().__init__()
self.shape('square')
self.penup()
self.goto(0, -380)
self.color('blue')
self.shapesize(stretch_wid=.5, stretch_len=10)
def move(self,i, j):
self.goto(i, -380)
class Start(Turtle):
def __init__(self):
super().__init__()
self.penup()
self.goto(250, 300)
self.color('blue')
self.shapesize(stretch_wid=4, stretch_len=10)
self.hideturtle()
self.write('Click to Start', font=('Arial', 35, 'bold'))
screen = Screen()
screen.colormode(255)
screen.bgcolor('white')
screen.setup(1200, 800)
screen.tracer(0)
paddle = Paddle()
ball = Ball()
screen.listen()
paddle.ondrag(paddle.move)
screen.onclick(click)
start = Start()
screen.update()
turtle.done()
screen.exitonclick()
I would like to use the RubberBand to zoom in and out relative to the size of the box I would like to zoom in the view to fit whatever is inside the block to the full view.
Can anyone help?
The zoom in and out with the mouse works as expected.
You can see in the code the rubberband works but I don't know how to make the zoom relative to the size of the box.
code:
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
import sys
from math import sqrt
class Point(QGraphicsItem):
def __init__(self, x, y):
super(Point, self).__init__()
self.setFlag(QGraphicsItem.ItemIsSelectable, True)
self.rectF = QRectF(0, 0, 30, 30)
self.x=x
self.y=y
self._brush = QBrush(Qt.black)
def setBrush(self, brush):
self._brush = brush
self.update()
def boundingRect(self):
return self.rectF
def paint(self, painter=None, style=None, widget=None):
painter.fillRect(self.rectF, self._brush)
def hoverMoveEvent(self, event):
point = event.pos().toPoint()
print(point)
QGraphicsItem.hoverMoveEvent(self, event)
class Viewer(QGraphicsView):
photoClicked = pyqtSignal(QPoint)
rectChanged = pyqtSignal(QRect)
def __init__(self, parent):
super(Viewer, self).__init__(parent)
self.rubberBand = QRubberBand(QRubberBand.Rectangle, self)
self.setMouseTracking(True)
self.origin = QPoint()
self.changeRubberBand = False
self._zoom = 0
self._empty = True
self._scene = QGraphicsScene(self)
self.setTransformationAnchor(QGraphicsView.AnchorUnderMouse)
self.setResizeAnchor(QGraphicsView.AnchorUnderMouse)
self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
self.setFrameShape(QFrame.NoFrame)
self.area = float()
self.setPoints()
def setItems(self):
self.data = {'x': [-2414943.8686, -2417160.6592, -2417160.6592, -2417856.1783, -2417054.7618, -2416009.9966, -2416012.5232, -2418160.8952, -2418160.8952, -2416012.5232, -2417094.7694, -2417094.7694], 'y': [10454269.7008,
10454147.2672, 10454147.2672, 10453285.2456, 10452556.8132, 10453240.2808, 10455255.8752, 10455183.1912, 10455183.1912, 10455255.8752, 10456212.5959, 10456212.5959]}
maxX = max(self.data['x'])
minX = min(self.data['x'])
maxY = max(self.data['y'])
minY = min(self.data['y'])
distance = sqrt((maxX-minX)**2+(maxY-minY)**2)
self.area = QRectF(minX, minY, distance, distance)
for i,x in enumerate(self.data['x']):
x = self.data['x'][i]
y = self.data['y'][i]
p = Point(x,y)
p.setPos(x,y)
self._scene.addItem(p)
self.setScene(self._scene)
def fitInView(self, scale=True):
rect = QRectF(self.area)
if not rect.isNull():
self.setSceneRect(rect)
unity = self.transform().mapRect(QRectF(0, 0, 1, 1))
self.scale(1 / unity.width(), 1 / unity.height())
viewrect = self.viewport().rect()
scenerect = self.transform().mapRect(rect)
factor = min(viewrect.width() / scenerect.width(),
viewrect.height() / scenerect.height())
self.scale(factor, factor)
self._zoom = 0
def setPoints(self):
self._zoom = 0
self.setItems()
self.setDragMode(True)
self.fitInView()
def wheelEvent(self, event):
if event.angleDelta().y() > 0:
factor = 1.25
self._zoom += 1
else:
factor = 0.8
self._zoom -= 1
if self._zoom > 0:
self.scale(factor, factor)
elif self._zoom == 0:
self.fitInView()
else:
self._zoom = 0
def mousePressEvent(self, event):
if event.button() == Qt.LeftButton:
self.origin = event.pos()
self.rubberBand.setGeometry(QRect(self.origin, QSize()))
self.rectChanged.emit(self.rubberBand.geometry())
self.rubberBand.show()
self.changeRubberBand = True
return
#QGraphicsView.mousePressEvent(self,event)
elif event.button() == Qt.MidButton:
self.viewport().setCursor(Qt.ClosedHandCursor)
self.original_event = event
handmade_event = QMouseEvent(QEvent.MouseButtonPress,QPointF(event.pos()),Qt.LeftButton,event.buttons(),Qt.KeyboardModifiers())
QGraphicsView.mousePressEvent(self,handmade_event)
super(Viewer, self).mousePressEvent(event)
def mouseReleaseEvent(self, event):
if event.button() == Qt.LeftButton:
self.origin = event.pos()
self.rubberBand.setGeometry(QRect(self.origin, QSize()))
self.changeRubberBand = False
QGraphicsView.mouseReleaseEvent(self,event)
elif event.button() == Qt.MidButton:
self.viewport().setCursor(Qt.OpenHandCursor)
handmade_event = QMouseEvent(QEvent.MouseButtonRelease,QPointF(event.pos()),Qt.LeftButton,event.buttons(),Qt.KeyboardModifiers())
QGraphicsView.mouseReleaseEvent(self,handmade_event)
super(Viewer, self).mouseReleaseEvent(event)
def mouseMoveEvent(self, event):
if self.changeRubberBand:
self.rubberBand.setGeometry(QRect(self.origin, event.pos()).normalized())
self.rectChanged.emit(self.rubberBand.geometry())
QGraphicsView.mouseMoveEvent(self,event)
super(Viewer, self).mouseMoveEvent(event)
class Window(QWidget):
def __init__(self):
super(Window, self).__init__()
self.viewer = Viewer(self)
self.btnLoad = QToolButton(self)
self.btnLoad.setText('Load Points')
self.btnLoad.clicked.connect(self.loadPoints)
VBlayout = QVBoxLayout(self)
VBlayout.addWidget(self.viewer)
HBlayout = QHBoxLayout()
HBlayout.setAlignment(Qt.AlignLeft)
HBlayout.addWidget(self.btnLoad)
VBlayout.addLayout(HBlayout)
def loadPoints(self):
self.viewer.setPoints()
if __name__ == '__main__':
import sys
app = QApplication(sys.argv)
window = Window()
window.setGeometry(500, 300, 800, 600)
window.show()
sys.exit(app.exec_())
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.
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.)
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.