用 Python 實現一個簡易版的 Pong 遊戲 (二)

{"type":"doc","content":[{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"回顧"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在第一部分,對 Pong 遊戲進行了簡單的介紹,以及演示了 Turtle 模塊的使用。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"有了Turtle 的初步體驗後,接下來將開始實現 Pong 遊戲。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"注意:由於篇幅所限,正文的代碼區域不一定顯示完整代碼,\"......\" 代表省略的代碼。"}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"遊戲窗口配置"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在 Visual Studio Code 裏新建一個 名爲 "},{"type":"text","marks":[{"type":"italic"}],"text":"pong.py"},{"type":"text","text":" 的Python 文件,然後對它進行編輯。"}]},{"type":"codeblock","attrs":{"lang":"python"},"content":[{"type":"text","text":"# 引入turtle模塊\nimport turtle\n# 創建一個 Screen 對象,並賦給變量 wn\nwn = turtle.Screen()\n# 設置程序窗口的標題爲 Pong by @MatrixTech\nwn.title(\"Pong by @MatrixTech\")\n# 設置程序窗體的背景顏色爲黑色\nwn.bgcolor(\"black\")\n# 設置繪圖屏幕寬爲 800 像素大小,高爲 600 像素大小\nwn.setup(width=800, height=600)\n# tracer方法調用禁止動畫顯示\nwn.tracer(0)\n\n# 主循環\nwhile True:\n # 執行 TurtleScreen 刷新。在每幀繪製結束後調用update方法進行屏幕刷新,讓繪製的圖形一次性顯示在窗口裏。\n wn.update()"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"這裏特別注意的是,"},{"type":"text","marks":[{"type":"italic"}],"text":"wn.tracer(0)"},{"type":"text","text":" 使用tracer方法禁止動畫顯示,然後通過"},{"type":"text","marks":[{"type":"italic"}],"text":"wn.update()"},{"type":"text","text":" 對屏幕進行刷新,讓繪製的圖形一次性顯示在窗口,無需漫長地等待繪製過程。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"運行 "},{"type":"text","marks":[{"type":"italic"}],"text":"pong.py"},{"type":"text","text":":Visual Studio Code -> 右鍵-> Run Python File Terminal "}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/0f/0f727ae4091efec08f68c1b361a01959.png","alt":null,"title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"運行成功後,會出現遊戲應用的窗體:"}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/4e/4e18adf78e523563866b4485f48b6f5d.png","alt":null,"title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"添加球拍和乒乓球"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"添加球拍 A"}]},{"type":"codeblock","attrs":{"lang":"python"},"content":[{"type":"text","text":"# 引入turtle模塊\nimport turtle\n# 創建一個 Screen 對象,並賦給變量 wn\nwn = turtle.Screen()\n# 設置程序窗口的標題爲 Pong by @MatrixTech\nwn.title(\"Pong by @MatrixTech\")\n# 設置程序窗體的背景顏色爲黑色\nwn.bgcolor(\"black\")\n# 設置遊戲屏幕寬爲 800 像素大小,高爲 600 像素大小\nwn.setup(width=800, height=600)\n# tracer方法調用禁止動畫顯示\nwn.tracer(0)\n\n# 球拍 A (左邊球拍)\n# 通過 turtle 模塊創建一個 Turtle 對象,並賦給變量 paddle_a\npaddle_a = turtle.Turtle()\n# 設置速度爲0\npaddle_a.speed(0)\n# 設置形狀爲矩形\npaddle_a.shape(\"square\")\n# 設置顏色爲白色\npaddle_a.color(\"white\")\n# 畫筆擡起,移動時不畫線\npaddle_a.penup()\n# 前往 x 座標爲 -350, y 座標爲 0 的位置\npaddle_a.goto(-350,0)\n\n# 球拍 B\n\n# 乒乓球\n\n\n# 遊戲主循環\nwhile True:\n # 執行 TurtleScreen 刷新。在每幀繪製結束後調用update方法進行屏幕刷新,讓繪製的圖形一次性顯示在窗口裏。\n wn.update()"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"運行程序,查看效果:"}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/4f/4f3b381f4df2edbd31d5a1b6f7a9ed23.png","alt":null,"title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"程序運行後,球拍A是一個長和高都是20像素的方塊,因此我們需要調整它形狀大小。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"使用 turtle.shapesize 方法可以調整球拍的形狀大小。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"turtle.shapesize(stretch_wid=None, stretch_len=None, outline=None)"}]}]},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"stretch_wid : 接受正數值,垂直方向拉伸;"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"stretch_len : 接受正數值,水平方向拉伸;"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"outline :接受正數值,形狀輪廓描邊的寬度;"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"返回或設置畫筆的屬性 x/y-拉伸因子和/或輪廓。海龜基於拉伸因子調整外觀: "},{"type":"text","marks":[{"type":"italic"}],"text":"stretch_wid"},{"type":"text","text":" 爲垂直於其朝向的寬度拉伸因子,"},{"type":"text","marks":[{"type":"italic"}],"text":"stretch_len"},{"type":"text","text":" 爲水平於其朝向的長度拉伸因子,決定形狀輪廓線的粗細。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"turtle.shapesize 方法的詳細介紹可參閱手冊 : "},{"type":"link","attrs":{"href":"https://docs.python.org/zh-cn/3/library/turtle.html#turtle.shapesize","title":null},"content":[{"type":"text","text":"https://docs.python.org/zh-cn/3/library/turtle.html#turtle.shapesize"}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"球拍A 方塊原來是20*20 像素,現在垂直方向拉伸5,水平拉伸1,最終長水平方向爲20像素,垂直方向爲100像素。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"python"},"content":[{"type":"text","text":"......\n......\n......\n\n# 球拍 A (左邊球拍)\n# 通過 turtle 模塊創建一個 Turtle 對象,並賦給變量 paddle_a\npaddle_a = turtle.Turtle()\n# 設置速度爲0\npaddle_a.speed(0)\n# 設置形狀爲矩形\npaddle_a.shape(\"square\")\n# 設置顏色爲白色\npaddle_a.color(\"white\")\n# 球拍A 在垂直方向拉伸5(100 像素),水平方向拉伸1(20 像素)\npaddle_a.shapesize(stretch_wid=5,stretch_len=1)\n# 畫筆擡起 -- 移動時不畫線\npaddle_a.penup()\n# 前往 x 座標爲 -350, y 座標爲 0 的位置\npaddle_a.goto(-350,0)\n......\n......\n......"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"運行,查看效果:"}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/64/644c7ba17c9f2b1b7b37346fa465b235.png","alt":null,"title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"添加球拍 B"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"球拍B的代碼與球拍A的代碼相似,因此複製球拍A的代碼塊,做些許修改即可。"}]},{"type":"codeblock","attrs":{"lang":"python"},"content":[{"type":"text","text":"# 引入turtle模塊\nimport turtle\n# 創建一個 Screen 對象,並賦給變量 wn\nwn = turtle.Screen()\n# 設置程序窗口的標題爲 Pong by @MatrixTech\nwn.title(\"Pong by @MatrixTech\")\n# 設置程序窗體的背景顏色爲黑色\nwn.bgcolor(\"black\")\n# 設置程序屏幕寬爲 800 像素,高爲 600 像素\nwn.setup(width=800, height=600)\n# tracer方法調用禁止動畫顯示\nwn.tracer(0)\n\n# 球拍 A (左邊球拍)\n# 通過 turtle 模塊創建一個 Turtle 對象,並賦給變量 paddle_a\npaddle_a = turtle.Turtle()\n# 設置速度爲0\npaddle_a.speed(0)\n# 設置形狀爲矩形\npaddle_a.shape(\"square\")\n# 設置顏色爲白色\npaddle_a.color(\"white\")\npaddle_a.shapesize(stretch_wid=5,stretch_len=1)\n# 畫筆擡起 -- 移動時不畫線\npaddle_a.penup()\n# 前往 x 座標爲 -350, y 座標爲 0 的位置\npaddle_a.goto(-350,0)\n\n# 球拍 B (右邊球拍)\n# 通過 turtle 模塊創建一個 Turtle 對象,並賦給變量 paddle_b\npaddle_b = turtle.Turtle()\n# 設置速度爲0\npaddle_b.speed(0)\n# 設置形狀爲矩形\npaddle_b.shape(\"square\")\n# 設置顏色爲白色\npaddle_b.color(\"white\")\npaddle_b.shapesize(stretch_wid=5,stretch_len=1)\n# 畫筆擡起 -- 移動時不畫線\npaddle_b.penup()\n# 前往 x 座標爲 350, y 座標爲 0 的位置\npaddle_b.goto(350,0)\n\n# 乒乓球\n\n\n# 遊戲主循環\nwhile True:\n # 執行 TurtleScreen 刷新。在每幀繪製結束後調用update方法進行屏幕刷新,讓繪製的圖形一次性顯示在窗口裏。\n wn.update()"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"運行程序,查看效果:"}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/53/5302e029c6859d7d7cf6989087226db8.png","alt":null,"title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"添加乒乓球"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在原點添加一個方塊作乒乓求,添加的方法和上面的球拍添加一樣, 代碼如下:"}]},{"type":"codeblock","attrs":{"lang":"python"},"content":[{"type":"text","text":"......\n......\n......\n\n# 球拍 B (右邊球拍)\n# 通過 turtle 模塊創建一個 Turtle 對象,並賦給變量 paddle_b\npaddle_b = turtle.Turtle()\n# 設置速度爲0\npaddle_b.speed(0)\n# 設置形狀爲矩形\npaddle_b.shape(\"square\")\n# 設置顏色爲白色\npaddle_b.color(\"white\")\npaddle_b.shapesize(stretch_wid=5,stretch_len=1)\n# 畫筆擡起 -- 移動時不畫線\npaddle_b.penup()\n# 前往 x 座標爲 350, y 座標爲 0 的位置\npaddle_b.goto(350,0)\n\n# 乒乓球\nball = turtle.Turtle()\nball.speed(0)\nball.shape(\"square\")\nball.color(\"white\")\nball.penup()\nball.goto(0,0)\n\n# 遊戲主循環\nwhile True:\n # 執行 TurtleScreen 刷新。在每幀繪製結束後調用update方法進行屏幕刷新,讓繪製的圖形一次性顯示在窗口裏。\n wn.update()"}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"實現球拍的移動"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"步驟"}]},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"創建控制球拍垂直方向上下移動的函數;"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"把移動函數與鍵盤按鍵事件綁定,程序監聽鍵盤按鍵事件;"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"用戶按下被綁定的按鍵,觸發移動的函數;"}]}]}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"移動球拍 A"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"球拍A 向上移動:"}]},{"type":"codeblock","attrs":{"lang":"python"},"content":[{"type":"text","text":"......\n......\n......\n\n# 乒乓球\nball = turtle.Turtle()\nball.speed(0)\nball.shape(\"square\")\nball.color(\"white\")\nball.penup()\nball.goto(0,0)\n\n# 向上移動球拍 A\ndef paddle_a_up():\n \t# 獲得 paddle_a 的y座標數值,並賦給變量 y\n y = paddle_a.ycor()\n # 在原來的數值基礎上,增加20個像素\n y += 20\n # 重新設置 paddle_a 的y座標,使其向上移動20個像素的距離\n paddle_a.sety(y)\n\n# 鍵盤事件綁定\n# 事件監聽\nwn.listen()\n# 鍵盤 w 鍵的按下事件與方法 paddle_a_up 綁定\nwn.onkeypress(paddle_a_up,'w')"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"運行程序,查看效果:"}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/af/af4028c4da78729a09c7ce7fc9c744c7.gif","alt":null,"title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"球拍A 向下移動:"}]},{"type":"codeblock","attrs":{"lang":"python"},"content":[{"type":"text","text":"......\n......\n......\n\n# 函數\n# 向上移動球拍 A\ndef paddle_a_up():\n \t# 獲得 paddle_a 的 y 座標數值,並賦給變量 y\n y = paddle_a.ycor()\n # 在原來的數值基礎上,增加20個像素\n y += 20\n # 重新設置 paddle_a 的y座標,使其向上移動20個像素的距離\n paddle_a.sety(y)\n\n# 向下移動球拍 A\ndef paddle_a_down():\n # 獲得 paddle_a 的y座標數值,並賦給變量 y\n y = paddle_a.ycor()\n # 在原來的數值基礎上,減少20個像素\n y -= 20\n # 重新設置 paddle_a 的y座標,使其向下移動20個像素的距離\n paddle_a.sety(y)\n\n# 鍵盤事件綁定\n# 事件監聽\nwn.listen()\n# 鍵盤 w 鍵的按下事件與方法 paddle_a_up 綁定\nwn.onkeypress(paddle_a_up,'w')\n# 鍵盤 s 鍵的按下事件與方法 paddle_a_down 綁定\nwn.onkeypress(paddle_a_down,'s')\n\n"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"運行程序,查看效果:"}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/f5/f5b6de46621dad13a708294927800698.gif","alt":null,"title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"移動球拍 B"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"球拍B的移動實現與球拍A的一樣,可以參考球拍A移動的代碼。"}]},{"type":"codeblock","attrs":{"lang":"python"},"content":[{"type":"text","text":"# 函數\n......\n......\n......\n\n# 向上移動球拍 B\ndef paddle_b_up():\n \t# 獲得 paddle_b 的y座標數值,並賦給變量 y\n y = paddle_b.ycor()\n # 在原來的數值基礎上,增加20個像素\n y += 20\n # 重新設置 paddle_b 的y座標,使其向上移動20個像素的距離\n paddle_b.sety(y)\n\n# 向下移動球拍 B\ndef paddle_b_down():\n # 獲得 paddle_b 的y座標數值,並賦給變量 y\n y = paddle_b.ycor()\n # 在原來的數值基礎上,減少20個像素\n y -= 20\n # 重新設置 paddle_b 的y座標,使其向下移動20個像素的距離\n paddle_b.sety(y) \n\n# 鍵盤事件綁定\n# 事件監聽\nwn.listen()\n# 鍵盤 w 鍵的按下事件與方法 paddle_a_up 綁定\nwn.onkeypress(paddle_a_up,'w')\n# 鍵盤 s 鍵的按下事件與方法 paddle_a_down 綁定\nwn.onkeypress(paddle_a_down,'s')\n# 鍵盤 ↑ 鍵的按下事件與方法 paddle_b_up 綁定\nwn.onkeypress(paddle_b_up,'Up')\n# 鍵盤 ↑ 鍵的按下事件與方法 paddle_b_down 綁定\nwn.onkeypress(paddle_b_down,'Down')\n\n......\n......\n......"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"運行程序,查看效果:"}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/67/67226f279ae74b83402916b1ea3e9e50.gif","alt":null,"title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"實現乒乓球的移動"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"程序運行後,在遊戲的主循環裏不斷地按一個座標增量去更新原先的乒乓球座標,從而實現乒乓球的移動。"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"乒乓球的移動"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"爲乒乓球添加座標的增量:"}]},{"type":"codeblock","attrs":{"lang":"python"},"content":[{"type":"text","text":"......\n......\n......\n\n# 乒乓球\nball = turtle.Turtle()\nball.speed(0)\nball.shape(\"square\")\nball.color(\"white\")\nball.penup()\nball.goto(0,0)\n# 乒乓球的 x 座標增量\nball.dx = 2\n# 乒乓球的 y 座標增量\nball.dy = 2\n......\n......\n......"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在遊戲主循環中更新乒乓球座標:"}]},{"type":"codeblock","attrs":{"lang":"python"},"content":[{"type":"text","text":"......\n......\n......\n\n# 遊戲主循環\nwhile True:\n # 執行 TurtleScreen 刷新。在每幀繪製結束後調用update方法進行屏幕刷新,讓繪製的圖形一次性顯示在窗口裏。\n wn.update()\n # 移動乒乓球\n ball.setx(ball.xcor() + ball.dx)\n ball.sety(ball.ycor() + ball.dy)\n \n......\n......\n......"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如果在添加上述代碼後運行程序,就會看到乒乓球向右上角移動然後消失。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我們可以爲乒乓球添加邊界檢測解決其消失的問題,實現當乒乓球碰撞到窗口邊界後反彈。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我們先把乒乓球對象的 ball.penup() 註釋,讓“鋼筆”放下,這樣海龜移動時候就出現軌跡,方便我們看看它碰撞邊界後反彈的軌跡。"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"上邊界檢測"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"註釋 ball.penup() :"}]},{"type":"codeblock","attrs":{"lang":"python"},"content":[{"type":"text","text":"......\n......\n......\n\n# 乒乓球\nball = turtle.Turtle()\nball.speed(0)\nball.shape(\"square\")\nball.color(\"white\")\n# ball.penup()\nball.goto(0,0)\n# 乒乓球的 x 座標增量\nball.dx = 2\n# 乒乓球的 y 座標增量\nball.dy = 2\n\n......\n......\n......"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在遊戲主循環添加上邊界檢測代碼:"}]},{"type":"codeblock","attrs":{"lang":"python"},"content":[{"type":"text","text":"......\n......\n......\n......\n......\n\n# 遊戲主循環\nwhile True:\n print(\"x: \",ball.xcor(),\" y: \",ball.ycor() )\n # 執行 TurtleScreen 刷新。在每幀繪製結束後調用update方法進行屏幕刷新,讓繪製的圖形一次性顯示在窗口裏。\n wn.update()\n # 移動乒乓球\n ball.setx(ball.xcor() + ball.dx)\n ball.sety(ball.ycor() + ball.dy)\n\n # 上邊界檢測\n if ball.ycor() > 290:# 當乒乓球的 y 座標大於 290 像素時候\n # 設置乒乓球的 y 座標設置爲290\n ball.sety(290)\n # 把乒乓球 y 座標的增量變成 -2\n ball.dy *= -1\n "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"運行程序後,看到效果:"}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/4c/4c85853eeceb3b59a3b608706314bfb5.png","alt":null,"title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"程序啓動後,乒乓球從座標原點(0,0)以增量 (dx=2,dy=2) 往右上角移動。當乒乓球的 y 座標大於 290 時,乒乓球被被反彈,以增量(dx=2,dy=-2)移動。"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"下邊界檢測"}]},{"type":"codeblock","attrs":{"lang":"python"},"content":[{"type":"text","text":"......\n......\n......\n......\n......\n\n# 遊戲主循環\nwhile True:\n print(\"x: \",ball.xcor(),\" y: \",ball.ycor() )\n # 執行 TurtleScreen 刷新。在每幀繪製結束後調用update方法進行屏幕刷新,讓繪製的圖形一次性顯示在窗口裏。\n wn.update()\n # 移動乒乓球\n ball.setx(ball.xcor() + ball.dx)\n ball.sety(ball.ycor() + ball.dy)\n\n # 上邊界檢測\n if ball.ycor() > 290:# 當乒乓球的 y 座標大於 290 像素時候\n # 設置乒乓球的 y 座標設置爲290\n ball.sety(290)\n # 把乒乓球 y 座標的增量變成 -2\n ball.dy *= -1\n # 下邊界檢測 \n if ball.ycor() < -290:# 當乒乓球的 y 座標小於 290 像素時候\n # 設置乒乓球的 y 座標設置爲290\n ball.sety(-290)\n # 把乒乓球 y 座標的增量變成 -2\n ball.dy *= -1 "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"爲了查看效果,在運行程序之前,還需要修改乒乓球的座標增量如下:"}]},{"type":"codeblock","attrs":{"lang":"python"},"content":[{"type":"text","text":"# 乒乓球\nball = turtle.Turtle()\nball.speed(0)\nball.shape(\"square\")\nball.color(\"white\")\n# ball.penup()\nball.goto(0,0)\n# 乒乓球的 x 座標增量\nball.dx = 2\n# 乒乓球的 y 座標增量\nball.dy = -2"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"把 "},{"type":"text","marks":[{"type":"italic"}],"text":"ball.dy = 2"},{"type":"text","text":" 改成 "},{"type":"text","marks":[{"type":"italic"}],"text":"ball.dy = -2"},{"type":"text","text":" 後,乒乓球在程序運行後會向右下方移動。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"運行程序,查看結果:"}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/94/9476beefda84edd588410ec10a0d49a0.png","alt":null,"title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"至此,已經完成了上下邊界的檢測,可以把 "},{"type":"text","marks":[{"type":"italic"}],"text":"ball.penup()"},{"type":"text","text":" 的註釋取消:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"python"},"content":[{"type":"text","text":"......\n......\n......\n\n# 乒乓球\nball = turtle.Turtle()\nball.speed(0)\nball.shape(\"square\")\nball.color(\"white\")\nball.penup()\nball.goto(0,0)\n# 乒乓球的 x 座標增量\nball.dx = 2\n# 乒乓球的 y 座標增量\nball.dy = 2\n\n......\n......\n......"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"左右邊界檢測"}]},{"type":"codeblock","attrs":{"lang":"python"},"content":[{"type":"text","text":"......\n......\n......\n\n# 遊戲主循環\nwhile True:\n\t\t......\n\t\t......\n\t\t......\n\n # 下邊界檢測\n if ball.ycor() < -290:# 當乒乓球的 y 座標小於 290 像素時候\n # 設置乒乓球的 y 座標設置爲290\n ball.sety(-290)\n # 把乒乓球 y 座標的增量變成 -2\n ball.dy *= -1\n\n # 右邊界檢測\n if ball.xcor() > 390: #當乒乓球的 y 座標大於 390 像素時候 \n # 乒乓球恢復到原點座標\n ball.goto(0,0)\n # 改變開球方向\n ball.dx *= -1\n\n # 左邊界檢測\n if ball.xcor() < -390: #當乒乓球的 y 座標小於 -390 像素時候 \n # 乒乓球恢復到原點座標\n ball.goto(0,0)\n # 改變開球方向\n ball.dx *= -1"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"球拍 A 的 y 座標爲 -350,球拍 B 的 y 座標爲 350。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"當乒乓球的 y 座標大於350 時候,說明球拍 B 沒有接住乒乓球,球拍 B 失一分,球拍 A 得一分;"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"反之,當乒乓球的 y 座標小於 - 350 時候,說明球拍 A 沒有接住乒乓球,球拍 A 失一分,球拍 B 得一分。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"運行程序,查看結果:"}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/77/77af4fd599437b43e9accd55f1c9aa3f.gif","alt":null,"title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"實現球拍和球的碰撞檢測"}]},{"type":"codeblock","attrs":{"lang":"python"},"content":[{"type":"text","text":"......\n......\n......\n\n# 遊戲主循環\nwhile True:\n\t......\n\t......\n\t......\n\n # 右邊界檢測\n if ball.xcor() < -390: #當乒乓球的 y 座標小於 -390 像素時候 \n # 乒乓球恢復到原點座標\n ball.goto(0,0)\n # 改變開球方向\n ball.dx *= -1\n\n # 乒乓球與球拍 B 的碰撞檢測\n if (ball.xcor() > 340 and ball.xcor() < 350) and (ball.ycor() < paddle_b.ycor() + 50 and ball.ycor() > paddle_b.ycor() - 50 ):\n ball.setx(340)\n ball.dx *= -1\n\n # 乒乓球與球拍 A 的碰撞檢測\n if (ball.xcor() < -340 and ball.xcor() > -350) and (ball.ycor() < paddle_a.ycor() + 50 and ball.ycor() > paddle_a.ycor() - 50 ):\n ball.setx(-340)\n ball.dx *= -1"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"運行程序,查看效果:"}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/2e/2e898d85faa6e28d06aac85fbb25c23a.gif","alt":null,"title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"分數計算"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"創建 Pen 繪製得分"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"python"},"content":[{"type":"text","text":"......\n......\n......\n\n# 乒乓球\nball = turtle.Turtle()\nball.speed(0)\nball.shape(\"square\")\nball.color(\"white\")\nball.penup()\nball.goto(0,0)\n# 乒乓球的 x 座標增量\nball.dx = 2\n# 乒乓球的 y 座標增量\nball.dy = -2\n\n# Pen\npen = turtle.Turtle()\npen.speed(0)\npen.color(\"white\")\npen.penup()\n# 隱藏海龜,加快繪製速度\npen.hideturtle()\npen.goto(0,260)\npen.write(\"玩家 A: 0 玩家 B: 0\", align=\"center\", font=(\"Courier\",24,\"normal\"))\n\n......\n......\n......"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"運行程序,查看效果:"}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/77/77d6537fc4282f7beee566e32806f9ad.png","alt":null,"title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"計算得分"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"分別爲玩家 A 和玩家 B 添加分數變量:"}]},{"type":"codeblock","attrs":{"lang":"python"},"content":[{"type":"text","text":"......\n......\n......\n\n# Pen\npen = turtle.Turtle()\npen.speed(0)\npen.color(\"white\")\npen.penup()\n# 隱藏海龜,加快繪製速度\npen.hideturtle()\npen.goto(0,260)\npen.write(\"玩家 A: 0 玩家 B: 0\", align=\"center\", font=(\"Courier\",24,\"normal\"))\n\n# 得分\nscore_a = 0\nscore_b = 0\n\n......\n......\n......"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"添加計分邏輯代碼:"}]},{"type":"codeblock","attrs":{"lang":"python"},"content":[{"type":"text","text":"......\n......\n......\n\n# 遊戲主循環\nwhile True:\n \t......\n\t\t......\n\t\t......\n\n # 左邊界檢測\n if ball.xcor() > 390: #當乒乓球的 y 座標大於 390 像素時候 \n # 乒乓球恢復到原點座標\n ball.goto(0,0)\n # 改變開球方向\n ball.dx *= -1\n # score_a 得 1 分\n score_a += 1 \n # 清除畫筆 pen 的繪圖\n pen.clear()\n # 重新繪製得分結果\n pen.write(\"玩家 A: {} 玩家 B: {}\".format(score_a,score_b), align=\"center\", font=(\"Courier\",24,\"normal\"))\n\n # 右邊界檢測\n if ball.xcor() < -390: #當乒乓球的 y 座標小於 -390 像素時候 \n # 乒乓球恢復到原點座標\n ball.goto(0,0)\n # 改變開球方向\n ball.dx *= -1\n # 玩家 B 得 1 分\n score_b += 1\n # 清除畫筆 pen 的繪圖\n pen.clear()\n # 重新繪製得分結果\n pen.write(\"玩家 A: {} 玩家 B: {}\".format(score_a,score_b), align=\"center\", font=(\"Courier\",24,\"normal\"))\n\n\t\t......\n\t\t......\n\t\t......"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":"br"},"content":[{"type":"text","text":"運行程序,查看效果:"}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/f5/f55d47fbfa998682666ce934fd42242f.gif","alt":null,"title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"添加音效"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"音效文件可在此下載: "},{"type":"link","attrs":{"href":"https://github.com/matrixtechxyz/Pong/blob/master/bounce.wav","title":""},"content":[{"type":"text","text":"https://github.com/matrixtechxyz/Pong/blob/master/bounce.wav"}]}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"MacOS 系統"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如果在 MacOS 上開發 Pong, 可以通過引入 os 模塊通過sytem 方法調用 afplay 命令播放音效文件。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在頂部引入 os 模塊"}]},{"type":"codeblock","attrs":{"lang":"python"},"content":[{"type":"text","text":"# 引入turtle模塊\nimport turtle\n# 引入 os 模塊\nimport os\n\n\n......\n......\n......"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在碰撞檢測的地方添加音效:"}]},{"type":"codeblock","attrs":{"lang":"python"},"content":[{"type":"text","text":"# 遊戲主循環\nwhile True:\n # print(\"x: \",ball.xcor(),\" y: \",ball.ycor() )\n # 執行 TurtleScreen 刷新。在每幀繪製結束後調用update方法進行屏幕刷新,讓繪製的圖形一次性顯示在窗口裏。\n wn.update()\n # 移動乒乓球\n ball.setx(ball.xcor() + ball.dx)\n ball.sety(ball.ycor() + ball.dy)\n\n # 上邊界檢測\n if ball.ycor() > 290:# 當乒乓球的 y 座標大於 290 像素時候\n # 設置乒乓球的 y 座標設置爲290\n ball.sety(290)\n # 把乒乓球 y 座標的增量變成 -2\n ball.dy *= -1\n os.system(\"afplay bounce.wav&\")\n\n\n # 下邊界檢測\n if ball.ycor() < -290:# 當乒乓球的 y 座標小於 290 像素時候\n # 設置乒乓球的 y 座標設置爲290\n ball.sety(-290)\n # 把乒乓球 y 座標的增量變成 -2\n ball.dy *= -1\n os.system(\"afplay bounce.wav&\")\n\n # 左邊界檢測\n if ball.xcor() > 390: #當乒乓球的 y 座標大於 390 像素時候 \n # 乒乓球恢復到原點座標\n ball.goto(0,0)\n # 改變開球方向\n ball.dx *= -1\n # score_a 得 1 分\n score_a += 1 \n # 清除畫筆的繪圖\n pen.clear()\n # 重新生成新的繪圖\n pen.write(\"玩家 A: {} 玩家 B: {}\".format(score_a,score_b), align=\"center\", font=(\"Courier\",24,\"normal\"))\n\n # 右邊界檢測\n if ball.xcor() < -390: #當乒乓球的 y 座標小於 -390 像素時候 \n # 乒乓球恢復到原點座標\n ball.goto(0,0)\n # 改變開球方向\n ball.dx *= -1\n # 玩家 B 得 1 分\n score_b += 1\n # 清除畫筆的繪圖\n pen.clear()\n # 重新生成新的繪圖\n pen.write(\"玩家 A: {} 玩家 B: {}\".format(score_a,score_b), align=\"center\", font=(\"Courier\",24,\"normal\"))\n\n\n # 乒乓球與球拍 B 的碰撞檢測\n if (ball.xcor() > 340 and ball.xcor() < 350) and (ball.ycor() < paddle_b.ycor() + 50 and ball.ycor() > paddle_b.ycor() - 50 ):\n ball.setx(340)\n ball.dx *= -1\n os.system(\"afplay bounce.wav&\")\n\n # 乒乓球與球拍 A 的碰撞檢測\n if (ball.xcor() < -340 and ball.xcor() > -350) and (ball.ycor() < paddle_a.ycor() + 50 and ball.ycor() > paddle_a.ycor() - 50 ):\n ball.setx(-340)\n ball.dx *= -1\n os.system(\"afplay bounce.wav&\")"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"Windows 系統"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如果在 Windows 系統下開發 Pong ,可以使用 winsound 模塊播放 音效文件。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在源碼文件頂部引入 winsound 模塊:"}]},{"type":"codeblock","attrs":{"lang":"python"},"content":[{"type":"text","text":"# 引入turtle模塊\nimport turtle\n# Windows 系統發聲模塊\n#import winsound\n\n......\n......\n......"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在碰撞檢測的地方添加音效:"}]},{"type":"codeblock","attrs":{"lang":"python"},"content":[{"type":"text","text":"......\n......\n......\n# 遊戲主循環\nwhile True:\n # print(\"x: \",ball.xcor(),\" y: \",ball.ycor() )\n # 執行 TurtleScreen 刷新。在每幀繪製結束後調用update方法進行屏幕刷新,讓繪製的圖形一次性顯示在窗口裏。\n wn.update()\n # 移動乒乓球\n ball.setx(ball.xcor() + ball.dx)\n ball.sety(ball.ycor() + ball.dy)\n\n # 上邊界檢測\n if ball.ycor() > 290:# 當乒乓球的 y 座標大於 290 像素時候\n # 設置乒乓球的 y 座標設置爲290\n ball.sety(290)\n # 把乒乓球 y 座標的增量變成 -2\n ball.dy *= -1\n # Windows 系統下播放 bounce.wav 音頻文件\n #winsound.PlaySound(\"bounce.wav\", winsound.SND_ASYNC)\n\n\n # 下邊界檢測\n if ball.ycor() < -290:# 當乒乓球的 y 座標小於 290 像素時候\n # 設置乒乓球的 y 座標設置爲290\n ball.sety(-290)\n # 把乒乓球 y 座標的增量變成 -2\n ball.dy *= -1\n # Windows 系統下播放 bounce.wav 音頻文件\n #winsound.PlaySound(\"bounce.wav\", winsound.SND_ASYNC)\n\n # 左邊界檢測\n if ball.xcor() > 390: #當乒乓球的 y 座標大於 390 像素時候 \n # 乒乓球恢復到原點座標\n ball.goto(0,0)\n # 改變開球方向\n ball.dx *= -1\n # score_a 得 1 分\n score_a += 1 \n # 清除畫筆的繪圖\n pen.clear()\n # 重新生成新的繪圖\n pen.write(\"玩家 A: {} 玩家 B: {}\".format(score_a,score_b), align=\"center\", font=(\"Courier\",24,\"normal\"))\n\n # 右邊界檢測\n if ball.xcor() < -390: #當乒乓球的 y 座標小於 -390 像素時候 \n # 乒乓球恢復到原點座標\n ball.goto(0,0)\n # 改變開球方向\n ball.dx *= -1\n # 玩家 B 得 1 分\n score_b += 1\n # 清除畫筆的繪圖\n pen.clear()\n # 重新生成新的繪圖\n pen.write(\"玩家 A: {} 玩家 B: {}\".format(score_a,score_b), align=\"center\", font=(\"Courier\",24,\"normal\"))\n\n\n # 乒乓球與球拍 B 的碰撞檢測\n if (ball.xcor() > 340 and ball.xcor() < 350) and (ball.ycor() < paddle_b.ycor() + 50 and ball.ycor() > paddle_b.ycor() - 50 ):\n ball.setx(340)\n ball.dx *= -1\n # Windows 系統下播放 bounce.wav 音頻文件\n #winsound.PlaySound(\"bounce.wav\", winsound.SND_ASYNC)\n\n # 乒乓球與球拍 A 的碰撞檢測\n if (ball.xcor() < -340 and ball.xcor() > -350) and (ball.ycor() < paddle_a.ycor() + 50 and ball.ycor() > paddle_a.ycor() - 50 ):\n ball.setx(-340)\n ball.dx *= -1\n # Windows 系統下播放 bounce.wav 音頻文件\n #winsound.PlaySound(\"bounce.wav\", winsound.SND_ASYNC)"}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"源代碼"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"源代碼地址 : "},{"type":"link","attrs":{"href":"https://github.com/matrixtechxyz/Pong","title":null},"content":[{"type":"text","text":"https://github.com/matrixtechxyz/Pong"}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"參考資源"}]},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"link","attrs":{"href":"https://www.youtube.com/watch?v=C6jJg9Zan7w&t=380s","title":""},"content":[{"type":"text","text":"《Python Game Tutorial: Pong》"}]}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"link","attrs":{"href":"https://docs.python.org/zh-cn/3/library/turtle.html#turtle.hideturtle","title":""},"content":[{"type":"text","text":"《海龜繪圖》"}]}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"link","attrs":{"href":"http://yltang.net/tutorial/python/5/","title":""},"content":[{"type":"text","text":"小烏龜繪圖模組"}]}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"link","attrs":{"href":"https://sites.google.com/site/ezpythoncolorcourse/useturtle","title":""},"content":[{"type":"text","text":"使用Turtle模組繪圖"}]},{"type":"zerowidth"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"link","attrs":{"href":"https://blog.csdn.net/weixin_41137248/article/details/81188801","title":""},"content":[{"type":"text","text":"Python學習(一):turtle庫介紹與簡單案例"}]}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"link","attrs":{"href":"https://docs.python.org/zh-cn/3.7/library/winsound.html?highlight=winsound#module-winsound","title":""},"content":[{"type":"text","text":"windsound -- Suond-playing interface for Windows"}]},{"type":"zerowidth"},{"type":"zerowidth"},{"type":"zerowidth"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"link","attrs":{"href":"https://www.matrixtech.xyz/2020/08/04/cs-python-turtle-pong/[https://zh.wikipedia.org/wiki/%E4%B9%93](https://zh.wikipedia.org/wiki/%E4%B9%93)","title":null},"content":[{"type":"text","text":"維基百科 Pong"}]}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"zerowidth"}]},{"type":"horizontalrule"},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"text","text":"用 Python 實現一個簡易版的 Pong 遊戲 (一)"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"link","attrs":{"href":"https://xie.infoq.cn/article/273f9ff6dc0cc667bf80d5d93","title":""},"content":[{"type":"text","text":"https://xie.infoq.cn/article/273f9ff6dc0cc667bf80d5d93"}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":"br"}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":"br"}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":"br"}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":"br"}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}}]}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章