Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- # Tk_snake.py
- from Tkinter import *
- import random
- import time
- r=54
- step=15
- long=10
- init_moveSpeed = 250
- init_snakeX=[]
- init_snakeY=[]
- for z in range(long):
- init_snakeX.append(r+z*step)
- init_snakeY.append(r-2)
- class SnakeGame():
- def __init__(self):
- # moving step for snake and food
- self.step=15
- # game score
- self.gamescore=-10
- # to initialize the snake in the range of (x1,y1,x2,y1)
- # the number should be calculated cautiously
- self.snakeX=init_snakeX[:]
- self.snakeY=init_snakeY[:]
- # to initialize food list
- self.foodX=[0]
- self.foodY=[0]
- self.eat = 0
- # to initialize the moving direction
- # move[] one element = one self.step
- self.snakeDirection = 'Right'
- self.snakeMove = [1, 0]
- self.moveSpeed = init_moveSpeed
- # to draw the game frame
- window = Tk()
- window.geometry("600x400+300+100")
- window.maxsize(600,400)
- window.minsize(600,400)
- window.title("Snake game")
- #create frames to contain different widgets
- self.frame1=Frame(window, borderwidth = 4, relief = RIDGE)
- self.frame2=Frame(window, bg = 'white', borderwidth = 2, relief = RAISED)
- self.canvas=Canvas(self.frame1, bg = 'yellow', width = 600, height = 360)
- self.score_label=Label(self.frame2, height = 40)
- #pack widgets
- self.frame1.pack()
- self.frame2.pack(fill=BOTH)
- self.score_label.pack(side=LEFT)
- self.canvas.pack(fill=BOTH)
- #draw game scene
- self.draw_wall()
- self.draw_score()
- self.draw_food("eat", self.eat)
- self.draw_snake()
- #start game
- self.play()
- window.mainloop()
- "=== View Part ==="
- def draw_wall(self):
- """
- It creates a wall:
- (8,6) <- 575(38*15,9~583) -> (584,6)
- =
- 345
- (23*15,7~351)
- =
- (8,352) (584,352)
- """
- self.canvas.create_rectangle(6, 4, 583, 355, outline = "blue", width=6)
- def draw_score(self):
- """
- It updates the score(+10) and then displays in the label.
- """
- self.score() # score model
- self.score_label.config(text = "Score: " \
- + str(self.gamescore) + "\t\tLevel: " + str(self.gamescore/100)) # score view
- def draw_food(self, mode="eat", eatno=-1):
- """
- It gets a random position for the food and draws it.\n
- mode "eat" is for when the snake eats a food.
- call it like draw_food("eat", 3).\n
- mode "new" is for when the snake upgrades.
- call it like draw_food("new")
- """
- if mode == "eat":
- self.canvas.delete("food"+str(eatno))
- self.foodX[eatno], self.foodY[eatno] = self.random_food() #food model
- self.canvas.create_rectangle(self.foodX[eatno],self.foodY[eatno],
- self.foodX[eatno]+self.step, self.foodY[eatno]+self.step,\
- fill="red" ,tags="food"+str(eatno)) #food view
- elif mode == "new":
- x, y= self.random_food()
- self.foodX.append(x)
- self.foodY.append(y)
- no = len(self.foodX)-1
- self.canvas.create_rectangle(self.foodX[no],self.foodY[no],
- self.foodX[no]+self.step, self.foodY[no]+self.step,\
- fill="red" ,tags="food"+str(no))
- def draw_snake(self, mode = "normal"):
- """
- It lets the snake go one step forward and then draws the snake.\n
- *I don't want to see the snake head going through the wall,
- so I don't allow drawing that.\n
- *To make changing directions quicker, I made this function
- support going back(mode = "back"), as the snack always go forward one more step before turning(
- the 'one more step' can be only observed when the snakeSpeed is very low, so
- with initial time interval smaller than 300(that's relatively fast,
- which is normally given in the template), you will not even notice it.
- I noticed it because I begin with a low speed.)
- """
- if mode == "back":
- x,y=self.snake("back") # snake model
- #we don't need to re-draw it, just correcting the data is enough
- else:
- self.canvas.delete("snake")
- x,y=self.snake() # snake model
- for i in range(len(x)): # snake view
- if 9<=x[i]<=564 and 7<=y[i]<=351: #no going through!!
- self.canvas.create_rectangle(x[i],y[i],x[i]+self.step,y[i]+self.step, fill="orange",tags='snake')
- "=== Model Part ==="
- # food model
- def random_food(self):
- """
- It returns a randomized position which is not in the snake body.
- """
- while True:
- x = random.randrange(9,569,self.step)
- y = random.randrange(7,337,self.step)
- if not(x in self.snakeX and y in self.snakeY):
- #if this position isn't in the snake body
- return x, y
- # snake model
- def snake(self, mode = "normal"):
- """
- This function changes self.snakeX[] and self.snakeY[] for the next
- position, and returns this two list. \n
- As is explained in draw_snake(), we need to add mode"normal" to make
- the reactions on turnings faster.
- """
- length = len(self.snakeX)
- if mode == "back":
- for i in range(length-1, 0, -1):
- self.snakeX[i] = self.snakeX[i-1]
- self.snakeY[i] = self.snakeY[i-1]
- self.snakeX[0] -= self.snakeMove[0] * self.step
- self.snakeY[0] -= self.snakeMove[1] * self.step
- elif mode == "normal":
- for i in range(0, length-1):
- self.snakeX[i] = self.snakeX[i+1]
- self.snakeY[i] = self.snakeY[i+1]
- self.snakeX[length-1] += self.snakeMove[0] * self.step
- self.snakeY[length-1] += self.snakeMove[1] * self.step
- return self.snakeX, self.snakeY
- #score model
- def score(self):
- """
- This function runs when the snake gets score(eats food) and also
- """
- level = self.gamescore / 100
- if level < 0:
- level = 0
- self.gamescore += 10
- if self.gamescore / 100 > level:
- #if upgrade
- #change speed
- self.moveSpeed -= 30
- if self.moveSpeed <= 0:
- #make sure speed > 0
- self.moveSpeed = 30
- #add food
- self.draw_food("new")
- "=== Control Part ==="
- def iseated(self):
- #if self.snakeX[len(self.snakeX)-1]+self.snakeMove[0]*self.step == self.foodx and self.snakeY[len(self.snakeY)-1]+self.snakeMove[1]*self.step == self.foody:
- for i in range(0, len(self.foodX)):
- if self.snakeX[len(self.snakeX)-1] == self.foodX[i] and self.snakeY[len(self.snakeY)-1] == self.foodY[i]:
- self.eat = i
- return True
- return False
- def isdead(self):
- """
- If the snake eats itself or hits the wall, return True\n
- else return False
- """
- l = len(self.snakeX)
- if self.snakeX[l-1] < 9 or self.snakeX[l-1] > 564 or self.snakeY[l-1] < 7 or self.snakeY[l-1] > 351:
- return True
- for i in range(0, l-1):
- if self.snakeX[l-1] == self.snakeX[i] and self.snakeY[l-1] == self.snakeY[i]:
- return True
- return False
- def move(self, event):
- #avoid senseless direction changing
- u=(event.keysym == 'Up' or event.keysym == 'w') and self.snakeDirection != 'Up' and self.snakeDirection != 'Down'
- d=(event.keysym == 'Down' or event.keysym == 's') and self.snakeDirection != 'Up' and self.snakeDirection != 'Down'
- l=(event.keysym == 'Left' or event.keysym == 'a') and self.snakeDirection != 'Left' and self.snakeDirection != 'Right'
- r=(event.keysym == 'Right' or event.keysym == 'd') and self.snakeDirection != 'Left' and self.snakeDirection != 'Right'
- #avoid unreasonable movements
- if u or d or l or r:
- if u:
- self.draw_snake("back")
- self.snakeDirection = 'Up'
- self.snakeMove = [0, -1]
- if d:
- self.draw_snake("back")
- self.snakeDirection = 'Down'
- self.snakeMove = [0, 1]
- if l:
- self.draw_snake("back")
- self.snakeDirection = 'Left'
- self.snakeMove = [-1, 0]
- if r:
- self.draw_snake("back")
- self.snakeDirection = 'Right'
- self.snakeMove = [1, 0]
- self.canvas.unbind("<Key>")
- '''
- Because I've made the reaction on turnings so fast,
- I have to use an extra iseated() to eat food directly when turning.
- Otherwise, things will be that when a food is beside your head(but not in
- your direction), you press a key to turn to eat it,
- but you just end up going through it, leaving it where it was!!
- snake snake snake snake => snake snake , not snake snake
- food snake food(also snake of course)
- snake snake
- '''
- if self.iseated():
- self.snakeX.append(self.foodx)
- self.snakeY.append(self.foody)
- self.draw_food("eat", self.eat)
- self.draw_score()
- self.draw_snake()
- self.canvas.update()
- def play(self):
- self.canvas.config(highlightthickness = 0)
- self.canvas.focus_set()
- while not self.isdead():
- self.canvas.bind("<Key>", self.move)
- if self.iseated():
- self.snakeX.append(self.foodX[self.eat])
- self.snakeY.append(self.foodY[self.eat])
- self.draw_food("eat", self.eat)
- self.draw_score()
- self.draw_snake("back")#if not, the snake will go forward two steps
- self.draw_snake()
- self.canvas.update()
- self.canvas.after(self.moveSpeed)
- self.gameover()
- def gameover(self):
- self.canvas.unbind("<Key>")
- self.canvas.create_text(360,70,text = "Game Over! Score: {}, Level: {}.\
- \nPress ESC to quit.\nPress spacebar to restart.".format(self.gamescore, self.gamescore/100), font = "Helvetica -30 bold")
- self.canvas.bind("<space>", self.restart)
- def restart(self,event):
- if event.keysym == 'Escape':
- quit()
- else:
- self.canvas.delete(ALL)
- self.gamescore=-10
- # to initialize the snake in the range of (x1,y1,x2,y1)
- # the number should be calculated cautiously
- self.snakeX=init_snakeX[:]
- self.snakeY=init_snakeY[:]
- # to initialize food list
- self.foodX=[0]
- self.foodY=[0]
- self.eat = 0
- # to initialize the moving direction
- # move[] one element = one self.step
- self.snakeDirection = 'Right'
- self.snakeMove = [1, 0]
- self.moveSpeed = init_moveSpeed
- self.draw_wall()
- self.draw_score()
- self.draw_snake()
- self.draw_food("eat", self.eat)
- self.play()
- SnakeGame()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement