Advertisement
here2share

# Tk_snake.py

Oct 25th, 2016
182
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 9.73 KB | None | 0 0
  1. # Tk_snake.py
  2.  
  3. from Tkinter import *
  4. import random
  5. import time
  6.  
  7. r=54
  8. step=15
  9. long=10
  10. init_moveSpeed = 250
  11. init_snakeX=[]
  12. init_snakeY=[]
  13. for z in range(long):
  14.     init_snakeX.append(r+z*step)
  15.     init_snakeY.append(r-2)
  16.  
  17. class SnakeGame():
  18.  
  19.     def __init__(self):
  20.         # moving step for snake and food
  21.         self.step=15
  22.         # game score
  23.         self.gamescore=-10
  24.  
  25.         # to initialize the snake in the range of (x1,y1,x2,y1)            
  26.         # the number should be calculated cautiously
  27.         self.snakeX=init_snakeX[:]
  28.         self.snakeY=init_snakeY[:]
  29.  
  30.         # to initialize food list
  31.         self.foodX=[0]
  32.         self.foodY=[0]
  33.         self.eat = 0
  34.         # to initialize the moving direction
  35.         # move[] one element = one self.step
  36.         self.snakeDirection = 'Right'  
  37.         self.snakeMove = [1, 0]
  38.         self.moveSpeed = init_moveSpeed
  39.         # to draw the game frame
  40.         window = Tk()
  41.         window.geometry("600x400+300+100")
  42.         window.maxsize(600,400)
  43.         window.minsize(600,400)
  44.         window.title("Snake game")
  45.  
  46.         #create frames to contain different widgets
  47.         self.frame1=Frame(window, borderwidth = 4, relief = RIDGE)
  48.         self.frame2=Frame(window, bg = 'white', borderwidth = 2, relief = RAISED)
  49.         self.canvas=Canvas(self.frame1, bg = 'yellow', width = 600, height = 360)
  50.         self.score_label=Label(self.frame2, height = 40)
  51.  
  52.         #pack widgets
  53.         self.frame1.pack()
  54.         self.frame2.pack(fill=BOTH)
  55.         self.score_label.pack(side=LEFT)
  56.         self.canvas.pack(fill=BOTH)
  57.  
  58.         #draw game scene
  59.         self.draw_wall()
  60.         self.draw_score()
  61.         self.draw_food("eat", self.eat)
  62.         self.draw_snake()
  63.  
  64.         #start game
  65.         self.play()
  66.  
  67.         window.mainloop()
  68.  
  69.     "=== View Part ==="    
  70.     def draw_wall(self):
  71.         """
  72.            It creates a wall:
  73.              (8,6)  <-  575(38*15,9~583)  ->  (584,6)
  74.                  =             
  75.                 345
  76.           (23*15,7~351)
  77.                  =  
  78.              (8,352)                          (584,352)
  79.         """
  80.         self.canvas.create_rectangle(6, 4, 583, 355, outline = "blue", width=6)
  81.  
  82.     def draw_score(self):
  83.         """
  84.             It updates the score(+10) and then displays in the label.
  85.         """
  86.         self.score()                        # score model
  87.         self.score_label.config(text = "Score: " \
  88.         + str(self.gamescore) + "\t\tLevel: " + str(self.gamescore/100))    # score view
  89.  
  90.     def draw_food(self, mode="eat", eatno=-1):
  91.         """
  92.             It gets a random position for the food and draws it.\n
  93.             mode "eat" is for when the snake eats a food.
  94.                 call it like draw_food("eat", 3).\n
  95.             mode "new" is for when the snake upgrades.
  96.                 call it like draw_food("new")
  97.         """
  98.         if mode == "eat":
  99.             self.canvas.delete("food"+str(eatno))
  100.             self.foodX[eatno], self.foodY[eatno] = self.random_food()   #food model
  101.             self.canvas.create_rectangle(self.foodX[eatno],self.foodY[eatno],
  102.                                          self.foodX[eatno]+self.step, self.foodY[eatno]+self.step,\
  103.                                          fill="red" ,tags="food"+str(eatno))     #food view
  104.  
  105.         elif mode == "new":
  106.             x, y= self.random_food()
  107.             self.foodX.append(x)
  108.             self.foodY.append(y)
  109.             no = len(self.foodX)-1
  110.             self.canvas.create_rectangle(self.foodX[no],self.foodY[no],
  111.                                          self.foodX[no]+self.step, self.foodY[no]+self.step,\
  112.                                          fill="red" ,tags="food"+str(no))
  113.  
  114.     def draw_snake(self, mode = "normal"):
  115.         """
  116.             It lets the snake go one step forward and then draws the snake.\n
  117.             *I don't want to see the snake head going through the wall,
  118.             so I don't allow drawing that.\n
  119.             *To make changing directions quicker, I made this function
  120.             support going back(mode = "back"), as the snack always go forward one more step before turning(
  121.             the 'one more step' can be only observed when the snakeSpeed is very low, so
  122.             with initial time interval smaller than 300(that's relatively fast,
  123.             which is normally given in the template), you will not even notice it.
  124.             I noticed it because I begin with a low speed.)
  125.         """
  126.         if mode == "back":
  127.             x,y=self.snake("back")                  # snake model
  128.             #we don't need to re-draw it, just correcting the data is enough
  129.         else:
  130.             self.canvas.delete("snake")
  131.             x,y=self.snake()                    # snake model
  132.             for i in range(len(x)):          # snake view
  133.                 if 9<=x[i]<=564 and 7<=y[i]<=351:   #no going through!!      
  134.                     self.canvas.create_rectangle(x[i],y[i],x[i]+self.step,y[i]+self.step, fill="orange",tags='snake')  
  135.     "=== Model Part ==="
  136.     # food model
  137.     def random_food(self):   
  138.         """
  139.             It returns a randomized position which is not in the snake body.
  140.         """
  141.         while True:
  142.             x = random.randrange(9,569,self.step)
  143.             y = random.randrange(7,337,self.step)
  144.             if not(x in self.snakeX and y in self.snakeY):
  145.                 #if this position isn't in the snake body
  146.                 return x, y
  147.  
  148.     # snake model
  149.     def snake(self, mode = "normal"):
  150.         """
  151.             This function changes self.snakeX[] and self.snakeY[] for the next
  152.             position, and returns this two list. \n
  153.             As is explained in draw_snake(), we need to add mode"normal" to make
  154.             the reactions on turnings faster.  
  155.         """
  156.         length = len(self.snakeX)
  157.         if mode == "back":
  158.             for i in range(length-1, 0, -1):
  159.                 self.snakeX[i] = self.snakeX[i-1]
  160.                 self.snakeY[i] = self.snakeY[i-1]
  161.             self.snakeX[0] -= self.snakeMove[0] * self.step
  162.             self.snakeY[0] -= self.snakeMove[1] * self.step
  163.         elif mode == "normal"
  164.             for i in range(0, length-1):
  165.                 self.snakeX[i] = self.snakeX[i+1]
  166.                 self.snakeY[i] = self.snakeY[i+1]
  167.             self.snakeX[length-1] += self.snakeMove[0] * self.step
  168.             self.snakeY[length-1] += self.snakeMove[1] * self.step
  169.         return self.snakeX, self.snakeY
  170.     #score model   
  171.     def score(self):
  172.         """
  173.             This function runs when the snake gets score(eats food) and also
  174.         """
  175.         level = self.gamescore / 100
  176.         if level < 0:
  177.            level = 0
  178.         self.gamescore += 10
  179.         if self.gamescore / 100 > level:
  180.             #if upgrade
  181.             #change speed
  182.             self.moveSpeed -= 30
  183.             if self.moveSpeed <= 0:
  184.                 #make sure speed > 0
  185.                 self.moveSpeed = 30
  186.             #add food
  187.             self.draw_food("new")
  188.  
  189.     "=== Control Part ==="   
  190.     def iseated(self):
  191.         #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:
  192.         for i in range(0, len(self.foodX)):    
  193.             if self.snakeX[len(self.snakeX)-1] == self.foodX[i] and self.snakeY[len(self.snakeY)-1] == self.foodY[i]:
  194.                 self.eat = i     
  195.                 return True
  196.         return False
  197.  
  198.     def isdead(self):
  199.         """
  200.            If the snake eats itself or hits the wall, return True\n
  201.            else return False
  202.         """
  203.         l = len(self.snakeX)
  204.  
  205.         if self.snakeX[l-1] < 9 or self.snakeX[l-1] > 564 or self.snakeY[l-1] < 7 or self.snakeY[l-1] > 351:
  206.             return True
  207.         for i in range(0, l-1):
  208.             if self.snakeX[l-1] == self.snakeX[i] and self.snakeY[l-1] == self.snakeY[i]:
  209.                 return True
  210.         return False
  211.     def move(self, event):
  212.         #avoid senseless direction changing  
  213.         u=(event.keysym == 'Up' or event.keysym == 'w') and self.snakeDirection != 'Up' and self.snakeDirection != 'Down'
  214.         d=(event.keysym == 'Down' or event.keysym == 's') and self.snakeDirection != 'Up' and self.snakeDirection != 'Down'
  215.         l=(event.keysym == 'Left' or event.keysym == 'a') and self.snakeDirection != 'Left' and self.snakeDirection != 'Right'
  216.         r=(event.keysym == 'Right' or event.keysym == 'd') and self.snakeDirection != 'Left' and self.snakeDirection != 'Right'
  217.         #avoid unreasonable movements        
  218.         if u or d or l or r:  
  219.             if u:
  220.                 self.draw_snake("back")
  221.                 self.snakeDirection = 'Up'
  222.                 self.snakeMove = [0, -1]
  223.  
  224.             if d:
  225.                 self.draw_snake("back")        
  226.                 self.snakeDirection = 'Down'
  227.                 self.snakeMove = [0, 1]
  228.  
  229.             if l:
  230.                 self.draw_snake("back")
  231.                 self.snakeDirection = 'Left'
  232.                 self.snakeMove = [-1, 0]
  233.  
  234.             if r:
  235.                 self.draw_snake("back")          
  236.                 self.snakeDirection = 'Right'
  237.                 self.snakeMove = [1, 0]  
  238.             self.canvas.unbind("<Key>")
  239.             '''
  240.             Because I've made the reaction on turnings so fast,
  241.             I have to use an extra iseated() to eat food directly when turning.
  242.             Otherwise, things will be that when a food is beside your head(but not in
  243.             your direction), you press a key to turn to eat it,
  244.             but you just end up going through it, leaving it where it was!!
  245.             snake snake snake snake =>   snake snake , not   snake snake
  246.             food                         snake             food(also snake of course)
  247.                                          snake             snake
  248.             '''
  249.             if self.iseated():
  250.                 self.snakeX.append(self.foodx)
  251.                 self.snakeY.append(self.foody)
  252.                 self.draw_food("eat", self.eat)
  253.                 self.draw_score()
  254.             self.draw_snake()
  255.             self.canvas.update()   
  256.  
  257.     def play(self):
  258.  
  259.         self.canvas.config(highlightthickness = 0)
  260.         self.canvas.focus_set()
  261.         while not self.isdead():
  262.             self.canvas.bind("<Key>", self.move)
  263.             if self.iseated():
  264.                 self.snakeX.append(self.foodX[self.eat])
  265.                 self.snakeY.append(self.foodY[self.eat])
  266.                 self.draw_food("eat", self.eat)
  267.                 self.draw_score()
  268.                 self.draw_snake("back")#if not, the snake will go forward two steps                            
  269.             self.draw_snake()
  270.             self.canvas.update()
  271.             self.canvas.after(self.moveSpeed)
  272.         self.gameover()  
  273.  
  274.     def gameover(self):
  275.         self.canvas.unbind("<Key>")
  276.         self.canvas.create_text(360,70,text = "Game Over! Score: {}, Level: {}.\
  277.         \nPress ESC to quit.\nPress spacebar to restart.".format(self.gamescore, self.gamescore/100), font = "Helvetica -30 bold")
  278.         self.canvas.bind("<space>", self.restart)
  279.     def restart(self,event):
  280.         if event.keysym == 'Escape':
  281.             quit()
  282.         else:
  283.             self.canvas.delete(ALL)
  284.             self.gamescore=-10
  285.             # to initialize the snake in the range of (x1,y1,x2,y1)            
  286.             # the number should be calculated cautiously
  287.             self.snakeX=init_snakeX[:]
  288.             self.snakeY=init_snakeY[:]
  289.  
  290.             # to initialize food list
  291.             self.foodX=[0]
  292.             self.foodY=[0]
  293.             self.eat = 0
  294.             # to initialize the moving direction
  295.             # move[] one element = one self.step
  296.             self.snakeDirection = 'Right'  
  297.             self.snakeMove = [1, 0]
  298.             self.moveSpeed = init_moveSpeed
  299.  
  300.             self.draw_wall()
  301.             self.draw_score()
  302.             self.draw_snake()
  303.             self.draw_food("eat", self.eat)
  304.             self.play()
  305. SnakeGame()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement