天天看點

tkinter推箱子小遊戲源碼

init.py

import tkinter
from BoxGame.Move import Move
from BoxGame.Map import Map
from BoxGame.init_paint import init_paint
def main():
    # 建立一個視窗windows
    windows = tkinter.Tk()
    # 架構長寬設定為500x500,表頭設定為‘推箱子小遊戲’
    # 箱子尺寸為64x64
    s = 64
    pa = init_paint(windows,"640x640","推箱子小遊戲",s)
    # 畫出遊戲開始界面
    pa.paint_windows()
    # 進入消息循環
    windows.mainloop()
if __name__ == '__main__':
    main()

           

init_paint.py

import tkinter
from BoxGame.Move import Move
from BoxGame.Map import Map
from BoxGame.Role import Role
# 引入字型子產品
import tkinter.font as tkFont
class init_paint:
    """
    視窗繪制
        1.視窗的繪制-paint_windows
            i,選擇關卡-nextPass
        2.地圖的繪制-paint_canvas
        3.人物的繪制
        4.人物的移動-init_move
    """
    cvs,image_role,image_role_file,image_file1,lb,bt,s = None,None,None,None,None,None,0
    image_bg,image_bt = None,None
    def __init__(self,windows,size,title,s):
        self.windows = windows
        self.size = size
        self.title = title
        self.map = Map.map1[0]
        self.s = s
    def paint_windows(self):
        global lb,bt,image_bg,image_bt
        self.windows.geometry(self.size)
        self.windows.title(string=self.title)
        # 菜單制作
        menubase = tkinter.Menu(self.windows)
        menubar = tkinter.Menu(menubase)
        menulist_cs = ["遊戲開始", "第一關", "第二關","退出遊戲"]
        for x in menulist_cs:
            menubar.add_separator()
            if x == "第二關":
                menubar.add_command(label=x,command=self.nextPass)
            else:
                menubar.add_command(label=x)
        menubase.add_cascade(label="遊戲", menu=menubar)
        menubase.add_cascade(label="幫助")
        self.windows["menu"] = menubase
        image_bg = tkinter.PhotoImage(file='image/bg1.png')
        image_bt = tkinter.PhotoImage(file='image/begin.png')
        cvs_bg = tkinter.Canvas(self.windows, width=640, heigh=640)
        cvs_bg.create_image(0, 0, anchor='nw', image=image_bg)

        ft = tkFont.Font(family='宋體', size=40, weight=tkFont.BOLD)
        cvs_bg.create_text(320,200,anchor='center',text="推箱子小遊戲",font=ft,fill="orangered")
        bt = tkinter.Button(self.windows,image=image_bt,text="遊戲開始",cursor="hand2",command=self.paint_canvas)
        cvs_bg.pack()
        bt.place(relx=0.5, rely=0.5, anchor="center")
        self.cvs_bg = cvs_bg
        self.bt = bt
    def paint_canvas(self):
        """
        初始化地圖資訊:
            1、清空遊戲開始界面
            2、畫牆、箱子
        :return: None
        """
        if self.cvs_bg != None:
            self.cvs_bg.pack_forget()
        if self.bt != None:
            self.bt.place_forget()
        global cvs,image_role_file,image_role,image_file1
        # 建立一個畫布
        cvs = tkinter.Canvas(self.windows, width=640, heigh=640, bg="gray")
        # 畫出地圖的圍牆和箱子
        gamemap = Map(cvs, self.map)
        gamemap.setBoxGrade()
        gamemap.draw()
        # 設定遊戲角色初始位置、圖檔,畫出遊戲角色
        place_x = self.s+(self.s-37)/2
        place_y = self.s*9
        role = Role(place_x,place_y,"image/role.png")
        role.setImage(cvs)
        image_role = role.getImage()
        cvs.pack()
        Move(self.s, self.s*9, self.map, cvs,self.windows,image_role)
    def nextPass(self):
        self.map = Map.map1[1]


           

Role.py

import tkinter
class Role:
    """
    類屬性:
        image_role_file:tkinter.PhotoImage對象
        image_role:canvas.create_image對象,用于角色的移動move
    """
    image_role_file,image_role = None,None
    def __init__(self,place_x,place_y,image_file):
        """
        構造函數:執行個體初始化
        :param place_x:初始化位置-橫坐标
        :param place_y:初始化位置-縱坐标
        :param image_file:遊戲角色的圖檔路徑
        """
        self.place_x = place_x
        self.place_y = place_y
        self.image_file = image_file
    def setImage(self,cvs):
        """
        設定create_image遊戲角色執行個體對象
        :param cvs:canvas畫布
        :return:
        """
        global image_role_file,image_role
        image_role_file = tkinter.PhotoImage(file=self.image_file)
        image_role = cvs.create_image(self.place_x, self.place_y, anchor='nw', image=image_role_file, tag="role")
    def getImage(self):
        return image_role

           

Map.py

import tkinter
class Map:
        """
        類屬性:
                wall_file:tkinter.PhotoImage對象-牆
                box_file:tkinter.PhotoImage對象-箱子
                blue_file:tkinter.PhotoImage對象-目标點
                img_x:繪圖時的x軸坐标
                img_y:繪圖時的y軸坐标
                all_grade:對應目标點數量
                map地圖:暫時先在Map中設定,新版本放到json中
        """
        wall_file,box_file,blue_file,img_x,img_y = None,None,None,0,0
        all_grade = 0
        map1 = [[[1, 1, 1, 1, 1, 1, 3, 1, 1, 1],
                [1, 0, 0, 0, 0, 0, 0, 0, 0, 1],
                [1, 0, 0, 0, 0, 0, 0, 0, 0, 1],
                [1, 0, 0, 2, 0, 0, 0, 0, 0, 1],
                [1, 0, 0, 0, 1, 0, 0, 0, 0, 1],
                [1, 0, 0, 0, 0, 0, 2, 0, 0, 1],
                [1, 0, 0, 0, 0, 0, 0, 0, 0, 1],
                [1, 0, 0, 0, 0, 0, 0, 0, 0, 1],
                [1, 0, 0, 0, 0, 0, 0, 0, 0, 1],
                [1, 0, 1, 1, 1, 1, 3, 1, 1, 1]],#1_end
                [[1, 1, 1, 1, 1, 1, 3, 1, 1, 1],
                [1, 0, 0, 0, 0, 0, 0, 0, 0, 1],
                [1, 1, 1, 1, 1, 1, 0, 1, 1, 1],
                [1, 0, 0, 2, 0, 0, 0, 0, 0, 1],
                [1, 0, 0, 0, 1, 0, 0, 0, 0, 1],
                [1, 0, 0, 0, 0, 0, 2, 0, 0, 1],
                [1, 0, 0, 0, 0, 0, 0, 0, 0, 1],
                [1, 0, 0, 0, 0, 0, 0, 0, 0, 1],
                [1, 0, 0, 0, 0, 0, 0, 0, 0, 1],
                [1, 0, 1, 1, 1, 1, 3, 1, 1, 1]]]
        """
        map中:0為空地,1為圍牆,2為箱子,3是目标地
        """
        def __init__(self,cvs,map):
                """
                :param cvs:canvas畫布對象
                :param map:地圖二維數組
                """
                self.cvs = cvs
                self.map = map
        def setBoxGrade(self):
                """
                擷取所有目标點的位置,指派給類屬性
                :return:
                """
                for x in self.map:
                        for y in x:
                                if y == 3:
                                        Map.all_grade += 1
        def draw(self):
                """
                第一次繪制地圖:
                 i、根據地圖的二維數組來繪制,1為牆,2為箱子,3為目标點
                :return:
                """
                global img_x,img_y,wall_file,box_file,blue_file
                img_x = 0
                img_y = 0
                wall_file = tkinter.PhotoImage(file='image/wall.png')
                box_file = tkinter.PhotoImage(file='image/box.png')
                blue_file = tkinter.PhotoImage(file="image/point.png")
                for x in self.map:
                        for y in x:
                                if y == 1:
                                        self.cvs.create_image(img_x, img_y, anchor='nw', image=wall_file,tag="wall")
                                elif y ==2:
                                        self.cvs.create_image(img_x, img_y, anchor='nw', image=box_file,tag="box")
                                elif y ==3:
                                        self.cvs.create_image(img_x+(64-32)/2, img_y+(64-32)/2, anchor='nw', image=blue_file,tag="blue")
                                img_x += 64
                        img_x = 0
                        img_y += 64
        def againDrawBox(self):
                """
                目的:重繪箱子的位置
                要點:需要把PhotoImage設定為全局變量,create_image()才能在畫布上顯示
                :return: None
                """
                global img_x,img_y,box_file
                img_x = 0
                img_y = 0
                self.cvs.delete("box")
                box_file = tkinter.PhotoImage(file='image/box.png')
                for x in self.map:
                        for y in x:
                                if y ==2:
                                        self.cvs.create_image(img_x, img_y, anchor='nw', image=box_file,tag="box")
                                img_x += 64
                        img_x = 0
                        img_y += 64


           

Move.py

import tkinter
from BoxGame.Map import Map
# 引入字型子產品
import tkinter.font as tkFont
class Move:
    level = 1
    grade = 0
    image_bg = None

    def __init__(self,place_x,place_y,map,cvs,windows,image_role):
        self.pl_x = place_x
        self.pl_y = place_y
        self.map = map
        self.cvs = cvs
        # 移動
        """
        在移動時:
            若移動方向為空地,則是對+1或者-1部分地圖進行探查是否可移動
            若移動方向為箱子,則是對+2或者-2部分地圖進行探查是否可移動
        """
        windows.bind_all("<KeyPress-Up>", lambda event: self.upClick(event, image_role, cvs))
        windows.bind_all("<KeyPress-Left>", lambda event: self.leftClick(event, image_role, cvs))
        windows.bind_all("<KeyPress-Right>", lambda event: self.rightClick(event, image_role, cvs))
        windows.bind_all("<KeyPress-Down>", lambda event: self.downClick(event, image_role, cvs))

    def add_x(self):
        # 靠牆角時的情況,不然會超出索引
        if int(self.pl_x/64)+1 > 9:
            return False
        wall = self.map[int(self.pl_y/64)][int(self.pl_x/64)+1]
        if self.pl_x <= 64*9:
            if wall == 0:
                self.pl_x += 64
                return True
            elif wall == 2 or wall == 3:
                if int(self.pl_x/64)+2 > 9:
                    return False
                box = self.map[int(self.pl_y/64)][int(self.pl_x/64)+2]
                if box == 0:
                    self.pl_x += 64
                    return "boxmove"
                if box == 3:
                    self.pl_x += 64
                    self.grade += 1
                    return "bluemove"
        return False
    def cut_x(self):
        if int(self.pl_x/64)-1 < 0:
            return False
        wall = self.map[int(self.pl_y/64)][int(self.pl_x/64)-1]
        if self.pl_x >=64:
            if wall == 0 or wall == 3:
                self.pl_x -= 64
                return True
            elif wall == 2:
                if int(self.pl_x/64)-2 < 0:
                    return False
                box = self.map[int(self.pl_y/64)][int(self.pl_x/64)-2]
                if box == 0:
                    self.pl_x -= 64
                    return "boxmove"
                if box == 3:
                    self.pl_x -= 64
                    self.grade += 1
                    return "bluemove"
        return False
    def add_y(self):
        if int(self.pl_y/64)+1 >9:
            return False
        wall = self.map[int(self.pl_y/64)+1][int(self.pl_x/64)]
        if self.pl_y <= 64*9:
            if wall == 0 or wall == 3:
                self.pl_y += 64
                return True
            elif wall == 2:
                if int(self.pl_y/64)+2 > 9:
                    return False
                box = self.map[int(self.pl_y/64)+2][int(self.pl_x/64)]
                if box == 0:
                    self.pl_y += 64
                    return "boxmove"
                if box == 3:
                    self.pl_y += 64
                    self.grade += 1
                    return "bluemove"
        return False
    def cut_y(self):
        if int(self.pl_y/64)-1 < 0:
            return False
        wall = self.map[int(self.pl_y/64)-1][int(self.pl_x/64)]
        if self.pl_y >=64:
            if wall == 0 or wall == 3:
                self.pl_y -= 64
                return True
            elif wall == 2:
                if int(self.pl_y/64)-2 < 0:
                    return False
                box = self.map[int(self.pl_y/64)-2][int(self.pl_x/64)]
                if box == 0:
                    self.pl_y -= 64
                    return "boxmove"
                if box == 3:
                    self.pl_y -= 64
                    self.grade += 1
                    return "bluemove"
        return False
    def upClick(self,event,img,cvs):
        move_id = self.cut_y()
        if move_id == True:
            cvs.move(img,0,-64)
        elif move_id == "boxmove":
            self.map[int(self.pl_y / 64)+ 0][int(self.pl_x / 64) ] = 0
            self.map[int(self.pl_y / 64)- 1][int(self.pl_x / 64) ] = 2
            Map(self.cvs, self.map).againDrawBox()
            cvs.move(img,0,-64)
        elif move_id == "bluemove":
            self.map[int(self.pl_y / 64)+ 0][int(self.pl_x / 64) ] = 0
            self.map[int(self.pl_y / 64)- 1][int(self.pl_x / 64) ] = 2
            Map(self.cvs, self.map).againDrawBox()
            cvs.move(img,0,-64)
            print("%d個箱子進洞啦"%(self.grade))
            self.gameover()
    def leftClick(self,event,img,cvs):
        move_id = self.cut_x()
        if move_id == True:
            cvs.move(img,-64,0)
        elif move_id == "boxmove":
            self.map[int(self.pl_y / 64)][int(self.pl_x / 64) + 0] = 0
            self.map[int(self.pl_y / 64)][int(self.pl_x / 64) - 1] = 2
            Map(self.cvs, self.map).againDrawBox()
            cvs.move(img, -64, 0)
        elif move_id == "bluemove":
            self.map[int(self.pl_y / 64)][int(self.pl_x / 64) + 0] = 0
            self.map[int(self.pl_y / 64)][int(self.pl_x / 64) - 1] = 2
            Map(self.cvs, self.map).againDrawBox()
            cvs.move(img, -64, 0)
            print("%d個箱子進洞啦"%(self.grade))
            self.gameover()
    def rightClick(self,event,img,cvs):
        move_id = self.add_x()
        if move_id == True:
            cvs.move(img,64,0)
        elif move_id == "boxmove":
            self.map[int(self.pl_y / 64)][int(self.pl_x / 64) + 0] = 0
            self.map[int(self.pl_y / 64)][int(self.pl_x / 64) + 1] = 2
            Map(self.cvs, self.map).againDrawBox()
            cvs.move(img, 64, 0)
        elif move_id == "bluemove":
            self.map[int(self.pl_y / 64)][int(self.pl_x / 64) + 0] = 0
            self.map[int(self.pl_y / 64)][int(self.pl_x / 64) + 1] = 2
            Map(self.cvs, self.map).againDrawBox()
            cvs.move(img, 64, 0)
            print("%d個箱子進洞啦" % (self.grade))
            self.gameover()
    def downClick(self,event,img,cvs):
        move_id = self.add_y()
        if move_id == True:
            cvs.move(img,0,64)
        elif move_id == "boxmove":
            self.map[int(self.pl_y / 64)+ 0][int(self.pl_x / 64) ] = 0
            self.map[int(self.pl_y / 64)+ 1][int(self.pl_x / 64) ] = 2
            Map(self.cvs, self.map).againDrawBox()
            cvs.move(img,0,64)
        elif move_id == "bluemove":
            # 改變地圖數組的值,0為空地,2為箱子
            self.map[int(self.pl_y / 64)+ 0][int(self.pl_x / 64) ] = 0
            self.map[int(self.pl_y / 64)+ 1][int(self.pl_x / 64) ] = 2
            # 重繪盒子位置
            Map(self.cvs, self.map).againDrawBox()
            # 角色移動
            cvs.move(img,0,64)
            print("%d個箱子進洞啦" % (self.grade))
            self.gameover()
    def gameover(self):
        global image_bg
        print(self.grade,Map.all_grade)
        print(len(Map.map1))
        # 當箱子到位數等于本地圖箱子總數時,進入下一個地圖
        if self.grade == Map.all_grade:
            # 當遊戲等級等于地圖清單長度
            if Move.level == len(Map.map1):
                self.cvs.pack_forget()
                image_bg = tkinter.PhotoImage(file='image/bg1.png')
                self.cvs.create_image(0, 0, anchor='nw', image=image_bg)
                ft = tkFont.Font(family='宋體', size=40, weight=tkFont.BOLD)
                self.cvs.create_text(320, 320, anchor='center', text="通關啦!", font=ft, fill="orangered")
                self.cvs.pack()
                return False
            self.cvs.pack_forget()
            Map.all_grade = 0
            self.grade = 0
            Move.level += 1
            map = Map(self.cvs,Map.map1[1])
            map.setBoxGrade()
            map.draw()
            # 把Move執行個體裡的地圖數組改變為第二張地圖,不然的話隻會重新繪圖,但是執行個體裡的地圖數組還是前一張地圖裡的
            self.map = Map.map1[1]
            self.cvs.pack()