- LEVEL 3
Ch.1 - Can you guess my password?
>>> variables
>>> if, elif and else
>>> functions
>>> while loops
>>> modules.
>>> variables
>>> if, elif and else
>>> functions
>>> while loops
>>> modules.
Ch.2 - Objects, classes and factories
>>> learn how to design classes
>>> learn how to make objects from classes
>>> start to build your own module
>>> learn how to build larger programs one bit at a time.
The MyPong Project:
Ch.3 - Creating the Table
>>> design a table class
>>> learn a bit more about the tkinter module
>>> build a simple graphical app.
>>> design a table class
>>> learn a bit more about the tkinter module
>>> build a simple graphical app.
Ch.4 - Making the Ball
>>> design a ball class
>>> learn how to add the ball to the table
>>> learn how to animate shapes in tkinter.
>>> design a ball class
>>> learn how to add the ball to the table
>>> learn how to animate shapes in tkinter.
Ch.5 - Building the Bats
>>> design a bat class
>>> learn how to add the bats to the table
>>> learn how objects communicate with each other.
>>> design a bat class
>>> learn how to add the bats to the table
>>> learn how objects communicate with each other.
Ch.6 - The Rules and Scoring
>>> stop the ball bouncing off the left and right walls
>>> add a scoring system to your game
>>> finish MyPong.
>>> stop the ball bouncing off the left and right walls
>>> add a scoring system to your game
>>> finish MyPong.
Bonus Chapter - Two more games
>>> see how useful lists are for storing objects in games
>>> see how to add many bricks at once using a loop
>>> see how flexible your ball, bat and table classes are
>>> produce two new games that can be further customised.
>>> see how useful lists are for storing objects in games
>>> see how to add many bricks at once using a loop
>>> see how flexible your ball, bat and table classes are
>>> produce two new games that can be further customised.
https://gist.github.com/renyuanL/3c0aaa6467d5e2e71ab3
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
''' | |
ryPong.py | |
乒乓球 | |
呂仁園,2014/07/06 | |
''' | |
import random | |
import tkinter | |
class 桌類: | |
def __init__(我,窗, | |
色= "black", | |
網色= "green", | |
寬= 600, | |
高= 400, | |
垂直網= True, | |
水平網= True): | |
我.寬= 寬 | |
我.高= 高 | |
我.色= 色 | |
我.布= tkinter.Canvas(窗, | |
bg= 我.色, | |
height= 我.高, | |
width= 我.寬) | |
我.布.pack() | |
if(垂直網): | |
我.布.create_line(我.寬/2, 0, 我.寬/2, 我.高, | |
width= 2, | |
fill= 網色, | |
dash= (15, 23)) | |
if(水平網): | |
我.布.create_line(0, 我.高/2, 我.寬, 我.高/2, | |
width= 2, | |
fill= 網色, | |
dash= (15, 23)) | |
字型= ("times", 72) | |
我.記分板= 我.布.create_text(我.寬/2, 65, | |
font= 字型, | |
fill= "magenta") | |
def 畫方(我, 方): | |
x1= 方.位x | |
y1= 方.位y | |
x2= x1 + 方.寬 | |
y2= y1 + 方.高 | |
c= 方.色 | |
return 我.布.create_rectangle(x1, y1, x2, y2, fill= c) | |
def 畫圓(我, 圓): | |
x1= 圓.位x | |
y1= 圓.位y | |
x2= x1 + 圓.寬 | |
y2= y1 + 圓.高 | |
c= 圓.色 | |
return 我.布.create_oval(x1, y1, x2, y2, fill= c) | |
def 移項(我, 項, x1, y1, x2, y2): | |
我.布.coords(項, x1, y1, x2, y2) | |
def 刪項(我, 項): | |
我.布.delete(項) | |
def 改項色(我, 項, 色): | |
我.布.itemconfigure(項, fill= 色) | |
def 記分(我, 左, 右): | |
分= str(右) + " : " + str(左) # 這裡怪怪的! | |
我.布.itemconfigure(我.記分板, text= 分) | |
class 球類: | |
def __init__(我, 桌, | |
寬= 20, | |
高= 20, | |
色= "red", | |
速x= 10, | |
速y= 5, | |
位x= 0, | |
位y= 0): | |
我.寬= 寬 | |
我.高= 高 | |
我.位x= 位x | |
我.位y= 位y | |
我.色= 色 | |
我.位x0= 位x | |
我.位y0= 位y | |
我.速x= 速x | |
我.速y= 速y | |
我.桌= 桌 | |
我.圓= 我.桌.畫圓(我) | |
def 設初始位置(我): | |
我.位x= 我.位x0 | |
我.位y= 我.位y0 | |
def 發球(我, 速x, 速y): | |
我.速x= -速x if random.randint(0,1) else 速x | |
我.速y= -速y if random.randint(0,1) else 速y | |
我.設初始位置() | |
def 移位(我): | |
# | |
# 依速度,改變位置 | |
# | |
我.位x += 我.速x | |
我.位y += 我.速y | |
狀態= '' | |
# | |
# 撞左牆: | |
# | |
if(我.位x <= 0): | |
我.位x = 0 | |
我.速x *= -1 | |
狀態= '撞左牆' | |
# | |
# 撞右牆: | |
# | |
if(我.位x >= 我.桌.寬): | |
我.位x = 我.桌.寬 | |
我.速x *= -1 | |
狀態= '撞右牆' | |
# | |
# 撞上牆: | |
# | |
if(我.位y <= 0): | |
我.位y= 0 | |
我.速y *= -1 | |
狀態= '撞上牆' | |
# | |
# 撞下牆: | |
# | |
if(我.位y >= 我.桌.高): | |
我.位y= 我.桌.高 | |
我.速y *= -1 | |
狀態= '撞下牆' | |
# | |
# 算出該移動的座標值 | |
# | |
x1= 我.位x | |
y1= 我.位y | |
x2= x1 + 我.寬 | |
y2= y1 + 我.高 | |
# | |
# 以上數學都算好了,真正的移動指令在此: | |
# | |
我.桌.移項(我.圓, x1, y1, x2, y2) | |
return 狀態 # 把撞牆狀態傳出去 | |
def 停球(我): | |
我.速x= 0 | |
我.速y= 0 | |
class 拍類: | |
def __init__(我, 桌, | |
寬= 20, | |
高= 100, | |
位x= 50, | |
位y= 50, | |
色= "green", | |
速x= 20, | |
速y= 20): | |
我.寬= 寬 | |
我.高= 高 | |
我.位x= 位x | |
我.位y= 位y | |
我.色= 色 | |
我.位x0= 位x | |
我.位y0= 位y | |
我.速x= 速x | |
我.速y= 速y | |
我.桌= 桌 | |
我.方= 我.桌.畫方(我) | |
def 偵測碰撞(我, 球): | |
''' | |
If the implementation is easy to explain, | |
it may be a good idea. | |
>>>拍.偵測碰撞(球) | |
''' | |
拍上= 我.位y | |
拍下= 我.位y + 我.高 | |
拍左= 我.位x | |
拍右= 我.位x + 我.寬 | |
球上= 球.位y | |
球下= 球.位y + 球.高 | |
球左= 球.位x | |
球右= 球.位x + 球.寬 | |
# | |
# 開始寫碰撞邏輯了 | |
# | |
球左上撞拍= 球左下撞拍= 球右上撞拍= 球右下撞拍= False | |
球左上撞拍= ((拍左<球左<拍右) and (拍上<球上<拍下)) | |
球左下撞拍= ((拍左<球左<拍右) and (拍上<球下<拍下)) | |
球右上撞拍= ((拍左<球右<拍右) and (拍上<球上<拍下)) | |
球右下撞拍= ((拍左<球右<拍右) and (拍上<球下<拍下)) | |
碰撞= any([ 球左上撞拍, 球左下撞拍, 球右上撞拍, 球右下撞拍]) | |
# 碰撞後,速度及方向有所變化,遊戲比較好玩。 | |
if(碰撞): | |
球.速x *= -(1+random.random()) | |
球.速y *= 1+random.random() | |
def 移上(我, 參數): | |
我.位y += -我.速y | |
if(我.位y <= 0): | |
我.位y = 0 | |
x1 = 我.位x | |
x2 = 我.位x+我.寬 | |
y1 = 我.位y | |
y2 = 我.位y+我.高 | |
我.桌.移項(我.方, x1, y1, x2, y2) | |
def 移下(我, 參數): | |
我.位y += +我.速y | |
if(我.位y >= 我.桌.高 - 我.高): | |
我.位y = 我.桌.高 - 我.高 | |
x1 = 我.位x | |
x2 = 我.位x+我.寬 | |
y1 = 我.位y | |
y2 = 我.位y+我.高 | |
我.桌.移項(我.方, x1, y1, x2, y2) | |
def 移左(我, 參數): | |
我.位x += -我.速x | |
if(我.位x <= 0): | |
我.位x = 0 | |
x1 = 我.位x | |
x2 = 我.位x+我.寬 | |
y1 = 我.位y | |
y2 = 我.位y+我.高 | |
我.桌.移項(我.方, x1, y1, x2, y2) | |
def 移右(我, 參數): | |
我.位x += +我.速x | |
if(我.位x >= 我.桌.寬 - 我.寬): | |
我.位x = 我.桌.寬 - 我.寬 | |
x1 = 我.位x | |
x2 = 我.位x+我.寬 | |
y1 = 我.位y | |
y2 = 我.位y+我.高 | |
我.桌.移項(我.方, x1, y1, x2, y2) | |
def 設初始位置(我): | |
我.位x= 我.位x0 | |
我.位y= 我.位y0 | |
# | |
# 設計 遊戲流程 | |
# | |
def 遊戲流程(): | |
global 暫停遊戲等待發球, 左分, 右分, 目標分 | |
global 窗, 桌, 球, 左拍, 右拍 | |
if(暫停遊戲等待發球 == True): | |
球.停球() # 其實是設其 速 = 0 | |
# | |
# 球在動。。。 | |
# | |
狀態= 球.移位() | |
左拍.偵測碰撞(球) | |
右拍.偵測碰撞(球) | |
if(狀態 in ['撞左牆', '撞右牆']): | |
球.停球() | |
球.設初始位置() | |
暫停遊戲等待發球= True | |
if(狀態=='撞左牆'): | |
左分 += 1 | |
if(左分 >= 目標分): 左分, 右分 = "贏", "輸" | |
if(狀態=='撞右牆'): | |
右分 += 1 | |
if(右分 >= 目標分): 右分, 左分= "贏", "輸" | |
桌.記分(左分, 右分) | |
延遲時間= 10 #延遲時間 (ms) 後, | |
#自己呼叫自己,這是無窮迴圈。 | |
窗.after(延遲時間, 遊戲流程) | |
# | |
# 設計 重新遊戲 的機制 | |
# | |
def 重新遊戲(參數): | |
global 暫停遊戲等待發球, 左分, 右分 | |
global 窗, 桌, 球, 左拍, 右拍 | |
球.設初始位置() | |
左拍.設初始位置() | |
右拍.設初始位置() | |
初速x= random.random()*2 | |
初速y= random.random()*2 | |
球.發球(速x= 初速x, 速y= 初速y) | |
if(左分 in ["贏","輸"]): | |
左分= 右分= 0 | |
桌.記分(左分, 右分) | |
暫停遊戲等待發球= False | |
# | |
# 設計 控制介面 | |
# | |
def 綁定控制介面(): | |
global 窗, 桌, 球, 左拍, 右拍 | |
# | |
# 綁定 按鍵 與 球拍動作(上下左右) | |
# | |
窗.bind('<Up>', 右拍.移上) | |
窗.bind('<Down>', 右拍.移下) | |
窗.bind('<Left>', 右拍.移左) | |
窗.bind('<Right>',右拍.移右) | |
窗.bind('s', 左拍.移上) | |
窗.bind('x', 左拍.移下) | |
窗.bind('z', 左拍.移左) | |
窗.bind('c', 左拍.移右) | |
# | |
# 綁定 按鍵 「空白」與 重新遊戲 | |
# | |
窗.bind('<space>', 重新遊戲) | |
def 主程式(): | |
global 暫停遊戲等待發球, 左分, 右分, 目標分 | |
global 窗, 桌, 球, 左拍, 右拍 | |
左分= 右分= 0 # 左右打者分數 | |
目標分= 5 # 到達 目標分 即算 贏 | |
暫停遊戲等待發球= True | |
# | |
# 從 tkinter 進口 Tk 物類,改名為 窗類 | |
# | |
窗類= tkinter.Tk | |
# | |
# 從 窗類 生 1個 窗 | |
# | |
窗= 窗類() | |
窗.title("桌球窗") | |
# | |
# 從 桌類 生 1個 桌,放在 窗 內 | |
# | |
桌= 桌類(窗) | |
# | |
# 從 球類 生 1個 球,放在 桌 上 | |
# | |
球= 球類( | |
桌= 桌, | |
色= "red", | |
寬= 20, | |
高= 20, | |
位x= 桌.寬/2, | |
位y= 桌.高/2 | |
) | |
# | |
# 從 拍類 生 2個 拍,左拍、右拍,放在 桌 上。 | |
# | |
左拍= 拍類( | |
桌= 桌, | |
色= "blue", | |
寬= 20, | |
高= 100, | |
位x= 0, | |
位y= 桌.高/2 | |
) | |
右拍= 拍類( | |
桌= 桌, | |
色= "yellow", | |
寬= 20, | |
高= 100, | |
位x= -20+桌.寬, | |
位y= 桌.高/2 | |
) | |
# | |
# 呼叫遊戲流程,正式開始遊戲。 | |
# | |
綁定控制介面() | |
遊戲流程() | |
# | |
# 進入 窗 的 主迴圈 | |
# | |
窗.mainloop() | |
if __name__=='__main__': | |
主程式() |
沒有留言:
張貼留言