python tkinter實現連連看遊戲
阿新 • • 發佈:2020-11-17
需要自己新增圖片素材呦
執行效果:
完整程式碼
#!/usr/bin/env python # -*- coding: utf-8 -*- # @Date : 2017-10-02 15:19:24 # @Author : Salamander ([email protected]) # @Link : http://51lucy.com import os,random import tkinter as tk import tkinter.messagebox from PIL import Image,ImageTk class MainWindow(): __gameTitle = "連連看遊戲" __windowWidth = 700 __windowHeigth = 500 __icons = [] __gameSize = 10 # 遊戲尺寸 __iconKind = __gameSize * __gameSize / 4 # 小圖片種類數量 __iconWidth = 40 __iconHeight = 40 __map = [] # 遊戲地圖 __delta = 25 __isFirst = True __isGameStart = False __formerPoint = None EMPTY = -1 NONE_LINK = 0 STRAIGHT_LINK = 1 ONE_CORNER_LINK = 2 TWO_CORNER_LINK = 3 def __init__(self): self.root = tk.Tk() self.root.title(self.__gameTitle) self.centerWindow(self.__windowWidth,self.__windowHeigth) self.root.minsize(460,460) self.__addComponets() self.extractSmallIconList() self.root.mainloop() def __addComponets(self): self.menubar = tk.Menu(self.root,bg="lightgrey",fg="black") self.file_menu = tk.Menu(self.menubar,tearoff=0,fg="black") self.file_menu.add_command(label="新遊戲",command=self.file_new,accelerator="Ctrl+N") self.menubar.add_cascade(label="遊戲",menu=self.file_menu) self.root.configure(menu=self.menubar) self.canvas = tk.Canvas(self.root,bg = 'white',width = 450,height = 450) self.canvas.pack(side=tk.TOP,pady = 5) self.canvas.bind('<Button-1>',self.clickCanvas) def centerWindow(self,width,height): screenwidth = self.root.winfo_screenwidth() screenheight = self.root.winfo_screenheight() size = '%dx%d+%d+%d' % (width,height,(screenwidth - width)/2,(screenheight - height)/2) self.root.geometry(size) def file_new(self,event=None): self.iniMap() self.drawMap() self.__isGameStart = True def clickCanvas(self,event): if self.__isGameStart: point = self.getInnerPoint(Point(event.x,event.y)) # 有效點選座標 if point.isUserful() and not self.isEmptyInMap(point): if self.__isFirst: self.drawSelectedArea(point) self.__isFirst= False self.__formerPoint = point else: if self.__formerPoint.isEqual(point): self.__isFirst = True self.canvas.delete("rectRedOne") else: linkType = self.getLinkType(self.__formerPoint,point) if linkType['type'] != self.NONE_LINK: # TODO Animation self.ClearLinkedBlocks(self.__formerPoint,point) self.canvas.delete("rectRedOne") self.__isFirst = True if self.isGameEnd(): tk.messagebox.showinfo("You Win!","Tip") self.__isGameStart = False else: self.__formerPoint = point self.canvas.delete("rectRedOne") self.drawSelectedArea(point) # 判斷遊戲是否結束 def isGameEnd(self): for y in range(0,self.__gameSize): for x in range(0,self.__gameSize): if self.__map[y][x] != self.EMPTY: return False return True ''' 提取小頭像陣列 ''' def extractSmallIconList(self): imageSouce = Image.open(r'images\NARUTO.png') for index in range(0,int(self.__iconKind)): region = imageSouce.crop((self.__iconWidth * index,self.__iconWidth * index + self.__iconWidth - 1,self.__iconHeight - 1)) self.__icons.append(ImageTk.PhotoImage(region)) ''' 初始化地圖 存值為0-24 ''' def iniMap(self): self.__map = [] # 重置地圖 tmpRecords = [] records = [] for i in range(0,int(self.__iconKind)): for j in range(0,4): tmpRecords.append(i) total = self.__gameSize * self.__gameSize for x in range(0,total): index = random.randint(0,total - x - 1) records.append(tmpRecords[index]) del tmpRecords[index] # 一維陣列轉為二維,y為高維度 for y in range(0,self.__gameSize): if x == 0: self.__map.append([]) self.__map[y].append(records[x + y * self.__gameSize]) ''' 根據地圖繪製圖像 ''' def drawMap(self): self.canvas.delete("all") for y in range(0,self.__gameSize): point = self.getOuterLeftTopPoint(Point(x,y)) im = self.canvas.create_image((point.x,point.y),image=self.__icons[self.__map[y][x]],anchor='nw',tags = 'im%d%d' % (x,y)) ''' 獲取內部座標對應矩形左上角頂點座標 ''' def getOuterLeftTopPoint(self,point): return Point(self.getX(point.x),self.getY(point.y)) ''' 獲取內部座標對應矩形中心座標 ''' def getOuterCenterPoint(self,point): return Point(self.getX(point.x) + int(self.__iconWidth / 2),self.getY(point.y) + int(self.__iconHeight / 2)) def getX(self,x): return x * self.__iconWidth + self.__delta def getY(self,y): return y * self.__iconHeight + self.__delta ''' 獲取內部座標 ''' def getInnerPoint(self,point): x = -1 y = -1 for i in range(0,self.__gameSize): x1 = self.getX(i) x2 = self.getX(i + 1) if point.x >= x1 and point.x < x2: x = i for j in range(0,self.__gameSize): j1 = self.getY(j) j2 = self.getY(j + 1) if point.y >= j1 and point.y < j2: y = j return Point(x,y) ''' 選擇的區域變紅,point為內部座標 ''' def drawSelectedArea(self,point): pointLT = self.getOuterLeftTopPoint(point) pointRB = self.getOuterLeftTopPoint(Point(point.x + 1,point.y + 1)) self.canvas.create_rectangle(pointLT.x,pointLT.y,pointRB.x - 1,pointRB.y - 1,outline = 'red',tags = "rectRedOne") ''' 消除連通的兩個塊 ''' def ClearLinkedBlocks(self,p1,p2): self.__map[p1.y][p1.x] = self.EMPTY self.__map[p2.y][p2.x] = self.EMPTY self.canvas.delete('im%d%d' % (p1.x,p1.y)) self.canvas.delete('im%d%d' % (p2.x,p2.y)) ''' 地圖上該點是否為空 ''' def isEmptyInMap(self,point): if self.__map[point.y][point.x] == self.EMPTY: return True else: return False ''' 獲取兩個點連通型別 ''' def getLinkType(self,p2): # 首先判斷兩個方塊中圖片是否相同 if self.__map[p1.y][p1.x] != self.__map[p2.y][p2.x]: return { 'type': self.NONE_LINK } if self.isStraightLink(p1,p2): return { 'type': self.STRAIGHT_LINK } res = self.isOneCornerLink(p1,p2) if res: return { 'type': self.ONE_CORNER_LINK,'p1': res } res = self.isTwoCornerLink(p1,p2) if res: return { 'type': self.TWO_CORNER_LINK,'p1': res['p1'],'p2': res['p2'] } return { 'type': self.NONE_LINK } ''' 直連 ''' def isStraightLink(self,p2): start = -1 end = -1 # 水平 if p1.y == p2.y: # 大小判斷 if p2.x < p1.x: start = p2.x end = p1.x else: start = p1.x end = p2.x for x in range(start + 1,end): if self.__map[p1.y][x] != self.EMPTY: return False return True elif p1.x == p2.x: if p1.y > p2.y: start = p2.y end = p1.y else: start = p1.y end = p2.y for y in range(start + 1,end): if self.__map[y][p1.x] != self.EMPTY: return False return True return False def isOneCornerLink(self,p2): pointCorner = Point(p1.x,p2.y) if self.isStraightLink(p1,pointCorner) and self.isStraightLink(pointCorner,p2) and self.isEmptyInMap(pointCorner): return pointCorner pointCorner = Point(p2.x,p1.y) if self.isStraightLink(p1,p2) and self.isEmptyInMap(pointCorner): return pointCorner def isTwoCornerLink(self,p2): for y in range(-1,self.__gameSize + 1): pointCorner1 = Point(p1.x,y) pointCorner2 = Point(p2.x,y) if y == p1.y or y == p2.y: continue if y == -1 or y == self.__gameSize: if self.isStraightLink(p1,pointCorner1) and self.isStraightLink(pointCorner2,p2): return {'p1': pointCorner1,'p2': pointCorner2} else: if self.isStraightLink(p1,pointCorner1) and self.isStraightLink(pointCorner1,pointCorner2) and self.isStraightLink(pointCorner2,p2) and self.isEmptyInMap(pointCorner1) and self.isEmptyInMap(pointCorner2): return {'p1': pointCorner1,'p2': pointCorner2} # 橫向判斷 for x in range(-1,self.__gameSize + 1): pointCorner1 = Point(x,p1.y) pointCorner2 = Point(x,p2.y) if x == p1.x or x == p2.x: continue if x == -1 or x == self.__gameSize: if self.isStraightLink(p1,'p2': pointCorner2} class Point(): def __init__(self,x,y): self.x = x self.y = y def isUserful(self): if self.x >= 0 and self.y >= 0: return True else: return False ''' 判斷兩個點是否相同 ''' def isEqual(self,point): if self.x == point.x and self.y == point.y: return True else: return False ''' 克隆一份物件 ''' def clone(self): return Point(self.x,self.y) ''' 改為另一個物件 ''' def changeTo(self,point): self.x = point.x self.y = point.y MainWindow()
以上就是python tkinter實現連連看遊戲的詳細內容,更多關於python tkinter連連看的資料請關注我們其它相關文章!