Here is my code. I am following a tutorial for making a snake game in python.
import math, random, pygame
class cube(object):
rows = 20
w = 500
def __init__(self,start,dirnx=1,dirny=0,color=(255,0,0)):
self.pos = start
self.dirnx = 1
self.dirny = 0
self.color = color
def move(self, dirnx, dirny):
self.dirnx = dirnx
self.dirny = dirny
self.pos = (self.pos[0] + self.dirnx, self.pos[1] + self.dirny)
def draw(self, surface, eyes=False):
dis = self.w // self.rows
i = self.pos[0]
j = self.pos[1]
pygame.draw.rect(surface, self.color, (i*dis+1,j*dis+1, dis-2, dis-2))
if eyes:
centre = dis//2
radius = 3
circleMiddle = (i*dis+centre-radius,j*dis+8)
circleMiddle2 = (i*dis + dis -radius*2, j*dis+8)
pygame.draw.circle(surface, (0,0,0), circleMiddle, radius)
pygame.draw.circle(surface, (0,0,0), circleMiddle2, radius)
class snake(object):
body = []
turns = {}
def __init__(self, color, pos):
self.color = color
self.head = cube(pos)
self.body.append(self.head)
self.dirnx = 0
self.dirny = 1
def move():
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
keys = pygame.key.get_pressed()
for key in keys:
if keys[pygame.K_LEFT]:
self.dirnx = -1
self.dirny = 0
self.turns[self.head.pos[:]] = [self.dirnx, self.dirny]
elif keys[pygame.K_RIGHT]:
self.dirnx = 1
self.dirny = 0
self.turns[self.head.pos[:]] = [self.dirnx, self.dirny]
elif keys[pygame.K_UP]:
self.dirnx = 0
self.dirny = -1
self.turns[self.head.pos[:]] = [self.dirnx, self.dirny]
elif keys[pygame.K_DOWN]:
self.dirnx = 0
self.dirny = 1
self.turns[self.head.pos[:]] = [self.dirnx, self.dirny]
for i, c in enumerate(self.body):
p = c.pos[:]
if p in self.turns:
turn = self.turns
c.move(turn[0], turn[1])
if i == len(self.body)-1:
self.turns.pop(p)
else:
if c.dirnx == -1 and c.pos[0] <= 0: c.pos = (c.rows-1, c.pos[1])
elif c.dirnx == 1 and c.pos[0] >= c.rows-1: c.pos = (0,c.pos[1])
elif c.dirny == 1 and c.pos[1] >= c.rows-1: c.pos = (c.pos[0], 0)
elif c.dirny == -1 and c.pos[1] <= 0: c.pos = (c.pos[0],c.rows-1)
else: c.move(c.dirnx, c.dirny)
def reset(self, pos):
pass
def addCube(self):
tail = self.body[-1] #-1 is the last element in that list
dx, dy = tail.dirnx, tail.dirny #dx and dy is direction of x and direction of y
if dx == 1 and dy == 0:
self.body.append(cube((tail.pos[0]-1,tail.pos[1])))
elif dx == -1 and dy == 0:
self.body.append(cube((tail.pos[0]+1,tail.pos[1])))
elif dx == 0 and dy == 1:
self.body.append(cube((tail.pos[0],tail.pos[1]-1)))
elif dx == 0 and dy == -1:
self.body.append(cube((tail.pos[0],tail.pos[1]+1)))
self.body[-1].dirnx = dx
self.body[-1].dirny = dy
def draw(self, surface):
for i, c in enumerate(self.body):
if i==0:
c.draw(surface, True)
else:
c.draw(surface)
def drawGrid(w, rows, surface):
sizeBtwn = w // rows
x = 0
y = 0
for l in range(rows):
x = x + sizeBtwn
y = y + sizeBtwn
pygame.draw.line(surface, (255,255,255), (x,0),(x,w))
pygame.draw.line(surface, (255,255,255), (0,y),(w,y))
def redrawWindow(surface):
global width, rows, s, snack #ADD snack to this line
surface.fill((0,0,0))
s.draw(surface)
snack.draw(surface) #NEW
drawGrid(width, rows, surface)
pygame.display.update()
def randomSnack(rows, item):
positions = item.body
while True:
x = random.randrange(rows)
y = random.randrange(rows)
if len(list(filter(lambda z:z.pos == (x,y), positions))) > 0:
continue
else:
break
return (x.y)
def message_box(subject, content):
pass
def main(self):
global width, rows, s, snack
self.move = move
width = 500
height = 500
rows = 20
win = pygame.display.set_mode((width, width))
s = snake ((255,0,0), (10,10))
snack = cube(randomSnack(rows, s), color = (0,255,0))
flag = True
clock = pygame.time.Clock()
while flag:
pygame.time.delay(50)
clock.tick(10)
s.move()
if s.body[0] == snake.pos: #Checks if the head collides with the snack
s.addCube() #Adds a new cube to the snake
snack = cube(randomSnack(rows, s), color=(0,255,0)) #Creates a new snack object
redrawWindow(win)
main()
But then I keep getting this error which I can't seem to fix:
Traceback (most recent call last):
File "C:\Users\Ammar Khan\AppData\Local\Programs\Python\Python37\Snake Game Tutorial #4.py", line 186, in <module> main()
TypeError: main() missing 1 required positional argument: 'self'
In the code, the indenting shows that your main ()
function is in your snake
class, and so are all the methods from drawGrid()
down. You need shift them all the back by one indent to take them out of the class. Then get rid of the self
argument in your def main()
. That should fix that issue.
Another thing I noticed is that your move()
method that is within the snake()
class is missing the self argument that it should have. It should be move(self)
. All instance methods in a class MUST have a self
argument as their first argument (actually self
is just the agreed upon convention for the name, it could be anything but you should use self
or it will be confusing). You do not call it by passing that argument, it gets filled in by python with a reference to the instance.
A lot of beginner python programmers get thrown by this when they first start making their own classes. It may seem confusing, since there that argument is not there when you call it, and so it may seem like you are calling it with one argument too few.
I will illustrate how it works. If you had a class player
and wanted to call its update()
method, you would call player.update(...)
with whatever args it needed. Python when calling that instance method, takes the instance reference player
and puts it in front of all the '...' arguments that you passed yourself and it ends up in the self
parameter. That is how the instance method gets its reference to its own instance that it can use to access its internal attributes. I hope that helps clarify this.
I noticed two other things:
1) You have two definitions of class cube()
in your code. The second one overwrites the first causing it to be ignored though. They start off the same, so perhaps that is a typo or copy and past error?
2) You seem to have a typo here:
if s.body[0] == snake.pos: #Checks if the head collides with the snack
From the comment, I believe that it should be snack.pos
, not snake.