大家好,It's been a long time since I updated the article on the theme of the game..復工以來,因忙於工作,The pace of ideation games has slowed down,請大家諒解.
The game I bring to you today is called《蛇棋》,Not necessarily many people have played,But the rules are simpler,Ask brother would rather call it the simplified version of monopoly.One aspect of choosing this game is because there are few similar tutorials(Ask brother always thinking about bringing forth new ideas ),Another aspect can learn through the game to the realization of the role of basic movements and object-oriented programming.
因為內容比較多,還是和之前一樣,分為上下篇:
上篇 —— Set up and the basic logic game interface
下篇 —— Animation implementation and algorithm of moving chess pieces
一般是2到4個玩家,In the mobile made up of a series of grid map,Players roll the dice to determine the number of points to advance,If you encounter the end of the ladder,proceed to the top of the ladder,If you encounter the snake,稱為“蛇吻”,Has slipped to the location of the mouse.The first character to reach the finish line wins,But the number of points on the dice must be equal to the number of steps to finally reach the end,If is greater than the number,the chess piece moves backwards.
This program has been simplified to some extent,Only two players are provided(人機大戰),and the map is10 x 10composed of square grids,方便計算.
游戲截圖:
by convention,First draw the flow chart of the game.棋類、The process of turn-based games is relatively simple,Is nothing but players alternate execution of the same program,Then after each move, determine whether the victory condition is met,Finally, it is up to the player to decide whether to start a new battle.
The simple flow chart of Snake Chess is as follows:
Ask brother downloaded the chessboard picture of Snake chess from the Internet,色彩比較鮮艷、Resolution can also.But because I didn't draw the chessboard myself,So it can't be accurate to the size of each grid,But this number to us in the face to locate mobile piece is very important.Ask elder brother after repeated measurement and experiment,The width of each grid of the chessboard in the picture is obtained as58像素,高度為63像素.記住這兩個數字,後面會用到.
游戲背景、標題,相信大家已經很熟悉了.ask brother or useCanvasDraw the game interface,The size of the window is the size of the background chessboard image..
直接上代碼:
from tkinter import *
root = Tk()
root.geometry('1000x750+300+100')
root.title('蛇棋')
root.resizable(0,0)
cv = Canvas(root, width=1000,height=750,bg='lightyellow')
bg = PhotoImage(file=r"image\snake\bg.png")
cv_bg = cv.create_image(500,375,image = bg)
cv.pack()
root.mainloop()
The part of the original rule description of the picture is a bit redundant here,And we also need to place a window on the right that scrolls to display the current game information,So insert a text box with a scroll bar in its place ScrolledText組件.注意,This component needs to start fromtkinter的子模塊scrolledtext中,So you need to import the module first.
在CavansInsert this text box on the canvas,to block the part of the rule description(Horizontal ordinate for repeated testing).
import tkinter.scrolledtext as ts
info=ts.ScrolledText(root,width=25, height=17)
cv.create_window(890,390,window=info)
below the text box,We place an area where we roll the dice,並添加一個按鈕,This way when the player presses the button,the dice will roll,then randomly get a point,Is the player or computer chess pieces to steps forward.
About the animation of the dice,I have in the previous article,大家可以參考 Python動畫制作:用tkinter模擬擲骰子
You can copy the code directly,But ask brother used a global variable in the previous articlei,Used to determine the starting picture position of the dice roll.這裡,We can use another way of writing,Write the callback function of the button aslambda匿名函數,Then pass parameters to the functioni.Finally adjust the horizontal and vertical coordinates,放置在合適的位置.
import random
def roll(i):
btn['state']=DISABLED
if i<13:
cv.itemconfig(image1,image=dice_rotate[i])
root.after(50,lambda :roll(i+1))
else:
res = random.randint(1,6)
cv.itemconfig(image1,image=dice[res-1])
dice_rotate = [PhotoImage(file=r'image\snake\roll.gif', format=f'gif -index {
i}') for i in range(13)]
dice = [PhotoImage(file=f'image\snake\{
i+1}.png') for i in range(6)]
image1 = cv.create_image(880,580,image=dice[0])
btn = Button(root, text='擲骰子',command=lambda :roll(0))
cv.create_window(880,680,window=btn)
其中lambda匿名函數 lambda :roll(0) 以及 lambda :roll(i+1) Equivalent to the following writing,just omittedfun這個名字(That's why it's called an anonymous function.):
def fun():
roll(i+1)
To get random dice roll results,別忘記導入random模塊,生成1到6之間的隨機整數.
當然,We don't want players constantly press the button,So after pressing the button,It is necessary to set it toDISABLED,禁用狀態,Behind players dice turn again to restart it.實現效果如下:
According to the flow chart we drew before,當游戲開始的時候(Including when the game is over and the player chooses to restart the game),We need to let the player choose the pieces that represent them,So need to pop up a window,And provide pawns for players to choose.
In fact, this can also be done in the sameCanvasimplementation on canvas,On the canvas to create oneLabel組件,Then click after when the player,刪除Label.But using subwindows is a bit more flexible,The player can move its position,Can also be freely laid out on subwindows,Don't worry about affecting the main window.
The component that creates the child window isToplevel(),You can put it in a custom function at the start of the game,It is called when we start the game.為此,We need to create the following custom functions:
To facilitate repeated calls,We started a custom game function,這樣,當游戲結束的時候,If the player chooses to continue the game,This function can be called again.
There are not many environment variables that need to be initialized in the game start function in this game.The dice button(Prevent players from rolling the dice without picking a piece)、Disable the input function of the scrolling text box(This text box is used to display game information,Does not allow player input),然後就要通過Toplevel()創建一個子窗口.
the size of the child window、The title and other parameters are the same as the main window,這裡不再贅述.The function to be implemented by this sub-window is also very simple,only three components,一個標簽,used to prompt the player,Select pieces here,兩個按鈕(Because of the man-machine war,only two pieces),A picture of the two pieces is displayed on the button,Cases if the player pressed the corresponding pawn,Then the chess piece is initialized through the callback function.
def start_game():
global tl
btn['state']=DISABLED
info['state']=DISABLED
tl = Toplevel(root)
tl.geometry('220x150+690+400')
tl.title('游戲開始')
tl.resizable(0,0)
tl.wm_transient(root)
Label(tl,text='Please select a chess piece').place(x=80,y=10)
Button(tl,image=player_img[0],command=lambda :choose_piece(0)).place(x=50,y=50)
Button(tl,image=player_img[1],command=lambda :choose_piece(1)).place(x=120,y=50)
player_img = [PhotoImage(file=f'image\snake\p{
i+1}.png') for i in range(2)]
start_game()
To display an image on a button, you only need to put the button'simageThe parameter can be set to the picture.Because there are only two pieces, the computer and the player,So you only need to prepare two pictures.Ask elder brother here using the chess pieces images as an example,You can choose the picture you like.
When the player presses the button of the pawn,Automatically call another custom function choose_piece() Used to initialize the player's pawn(Draw at the starting position in the lower left corner of the chess card),並創建一個players的列表,used to indicate the order of the pieces.The part about the initialization of the pieces,We use object-oriented functionality,後面會介紹,Here you can first to comment out it.
def choose_piece(img):
# global players
# P1 = Piece("Player", cv, (30,650),player_img[img])
# P2 = Piece("電腦", cv, (50,655),player_img[1-img])
# players=[P1,P2]
info_update("游戲開始")
info_update("Ask the player to roll the dice first")
btn['state']=NORMAL
tl.destroy()
Because our rules default player to act first,So then we can show in the message box“Ask the player to roll the dice first”這樣的信息.(A random variable can be added to determine who moves first,大家可以思考一下如何實現)
Finally, the dice button back,Then use the child window'sdestroy()方法將其銷毀.
Because the content of the text box will be updated frequently,So we need to create a function that updates the textbox info_update(),方便調用,The effect of implementation is only need to pass need to display the text into it,will automatically appear in the last line of the text box,Also move the scrollbar to the last line.
代碼如下:
def info_update(content):
info['state']=NORMAL
info.insert(END, content+'\n')
info.see('end')
info['state']=DISABLED
文本框的 insert() keyword used by method“END”Indicates to start inserting at the end of the existing content of the text box,then escape the symbol\nmeans insert a newline at the end,to continue inserting text at the end the next time the function is called.
文本框的 see(‘end’) method will automatically scroll the scroll bar down,The last line displayed.如果不調用這個函數,Although the text will also be updated normally,but if there is too much,We need to manually pull the scroll bar to the bottom to see.
函數的最後,Also remember to set the state of the textbox to disabled,Because we don't want the player to manually modify the information in the text box.
最後,測試效果,沒有問題:
Object-oriented programming is actually such a concept,put inanimate things、conceptual materialization,變成有“生命”的物體,就像“成精”了.These objects have their own properties(名字、年齡等),還有自己的方法(會跑、跳、攻擊、死亡等等).There is a concept called game programmingSprite,Represents various objects that appear on the screen:主角、敵人、道具等等.——Many Chinese translations are too elegant,稱其“精靈”,其實翻譯成“妖精”也無不可.Specifically, these were originally inanimate,But it was materialized and appeared on the game screen“living object”們.
Since these objects are created,他們的“屬性”Has been followed,Calls can be viewed at any time.比如這個例子裡,After we customize the chess piece as an object,You can define its position on the chessboard as the attribute of the chess piece,這樣,If we want to know where the pawn is now,Just call its properties to see at a glance.This is one of the benefits of custom chess pieces.
And the method of the object is for all instances in the object.比如這個例子裡,We have two pawns, the player and the computer,belong to the chess category,then when we assign this class“移動”的方法時,Both chess pieces“會”移動了.只不過,The direction in which each piece moves、距離、Ways and so on are determined according to the pieces of the current position in the board.換句話說,When the pieces to perform their own methods,You need to call your own properties,Then we don't need to specify parameters,As long as tell piece to move to where.This is another benefit.
自定義類的方法使用 “class 類名” 就可以.Requirements for class names,same as the rules for variables,But in order to distinguish it from ordinary variables,The general convention is to capitalize the first letter.
To give our pawns“妖精”attribute,We need to define an initialization function,Then define these variables in the function.Let's sort it out,Look at the pieces need which attributes:
結合這些信息,The code to initialize the chess piece class is as follows:
class Piece:
def __init__(self,name,cv,co,bg):
self.name = name
self.cv = cv
self.id = cv.create_image(co,image = bg)
self.pos = 0
Note that we are just in the main program initialization function in pieces,根據用戶的選擇,to define the picture of the chess piece and draw the coordinates of the picture.實際上,This is how the class is instantiated,Just call the class name,Then pass in the properties of the class in the parameter.So we based on the attributes of the chess piece class just defined,Pass in the following parameters in order:
def choose_piece(img):
global players
P1 = Piece("Player", cv, (30,650),player_img[img])
P2 = Piece("電腦", cv, (50,655),player_img[1-img])
players=[P1,P2]
The coordinate parameter here is what I tried many times,Combine the width on the board and the distance to move behind,To make two pieces staggered,So a more suitable coordinate pair is obtained.You can also change to other numbers as the initial position of the pieces on the board.
顯而易見,The first method of chess pieces is to move.We want to show an effect of the pieces jumping forward,如下圖所示,It is bound to need to define a method of chess beating.
When the pawn moves to both sides,When need to move up,Or a ladder and head of the snake,需要向上、向下移動時,to define another way to move:
Definition of these two moving methods,We will introduce it in detail in the next article.