学习一门语言的初期总是会碰很多壁,还好用时间从错误中换来经验和稳重。当目标明确时,就不容易动摇。所以,记得自己为什么学这门语言、需要在哪里用很重要哦!
很感激最终实现了Pong小游戏。这里吐槽下我走过的弯路:
由于跟着coursera的An Introduction to Interactive Programming in Python 课,他们使用codeskulptor编写,我在大陆无法连上那个在线IDE,一直使用Sublime Text3文本编辑器编写代码。其中的编译、逻辑、显示错误,很难知道,由此走了很多弯路。
1. 先是因为python中没有simpleGUI库,只好下载SimpleGUICS2Pygame库代替,但在install时出现encoding的错误,苦于无法解决考虑使用其它GUI库。
2. 我们一般使用R进行数据分析,久闻python在数据分析中更有优势,于是学习了python的数据表示方法,总结如下符号表示:
^ | 一行以...开头 |
$ | 一行以...结尾 |
. | 对应任何字符 |
\s | 对应空格 |
\S | 对应任何非空格字符 |
* | 可输入0-若干个字符 |
*? | 可输入0-若干个字符(非贪婪策略)(指选择满足条件的最短部分) |
+ | 可输入1-若干个字符 |
+? | 可输入1-若干个字符(非贪婪策略) |
[xxx] | 对应方括号中的任一字符 |
[^xxx] | 对应除方括号中字符以外的任一字符 |
[a-z0-9] | 对应一定范围内字符 |
( | 标示从哪里开始 |
) | 标示到哪里结束 |
在网页爬取时,python3.5版本无法使用import urllib格式调用urllib.urlopen函数。得照此格式输入才可开始打开网页。
from urllib import request
import urllib.request
fhand = request.urlopen('http://www.py4inf.com/code/romeo.txt')
3. 对于python版本和simpleGUI库的问题,我最后买了VPN直接使用codeSkulptor编写程序,省了好多麻烦,也算解决问题了!
Pong的游戏规则很简单,就是用两个板把球弹到对方的边界,没接住者输,对方得分。这里左手边的方块用w,s控制上下,右手边的用↑、↓控制,两个人可以使用同一台电脑玩。
游戏要求见此:https://www.coursera.org/learn/interactive-python-1/supplement/wiv24/mini-project-description
编程思路如下(也许你有更好的方法,欢迎指点~~):
(1) 首先确定引用库,全局变量,主函数:
import simplegui
import math
import random
# initialize globals - pos and vel encode vertical info for paddles
WIDTH = 600
HEIGHT = 400
BALL_RADIUS = 20
PAD_WIDTH = 8
PAD_HEIGHT = 80
HALF_PAD_WIDTH = PAD_WIDTH / 2
HALF_PAD_HEIGHT = PAD_HEIGHT / 2
LEFT = False
RIGHT = True
# initialize ball_pos and ball_vel for new bal in middle of table
ball_pos = [WIDTH/2, HEIGHT/2]
ball_vel = [random.randrange(240, 300)/60, random.randrange(60, 240)/60]
time = 0
<pre name="code" class="python"># create frame
frame = simplegui.create_frame("Pong", WIDTH, HEIGHT)
frame.set_draw_handler(draw)
frame.set_keydown_handler(keydown)
frame.set_keyup_handler(keyup)
timer = simplegui.create_timer(500,tick)
# start frame
new_game()
frame.start()
timer.start()
(2) 其次在draw(canvas)函数中绘制边线,球(ball),控制块(paddle):
def draw(canvas):
global score1, score2, paddle1_pos, paddle2_pos, ball_pos, ball_vel
# draw mid line and gutters
canvas.draw_line([WIDTH / 2, 0],[WIDTH / 2, HEIGHT], 1, "White")
canvas.draw_line([PAD_WIDTH, 0],[PAD_WIDTH, HEIGHT], 1, "White")
canvas.draw_line([WIDTH - PAD_WIDTH, 0],[WIDTH - PAD_WIDTH, HEIGHT], 1, "White")
# draw ball
canvas.draw_circle(ball_pos, BALL_RADIUS, 2, "Red", "White")
# draw paddles
canvas.draw_polygon([(0,paddle1_pos-HALF_PAD_HEIGHT),(PAD_WIDTH,paddle1_pos-HALF_PAD_HEIGHT),\
(PAD_WIDTH,paddle1_pos+HALF_PAD_HEIGHT),(0,paddle1_pos+HALF_PAD_HEIGHT)],2,'White','Gray')
canvas.draw_polygon([(WIDTH-PAD_WIDTH,paddle2_pos-HALF_PAD_HEIGHT),(WIDTH,paddle2_pos-HALF_PAD_HEIGHT),\
(WIDTH,paddle2_pos+HALF_PAD_HEIGHT),(WIDTH-PAD_WIDTH,paddle2_pos+HALF_PAD_HEIGHT)],2,'White','Gray')
(3) 确定游戏刚开始和进行新一轮的状态
def spawn_ball(direction):
global ball_pos, ball_vel # these are vectors stored as lists
global time
if direction == RIGHT:
ball_pos = [WIDTH/2+time*ball_vel[0], HEIGHT/2+time*ball_vel[1]]
if direction == LEFT:
ball_pos = [WIDTH/2-time*ball_vel[0], HEIGHT/2+time*ball_vel[1]]
def new_game():
global paddle1_pos, paddle2_pos, paddle1_vel, paddle2_vel # these are numbers
global score1, score2 # these are ints
score1, score2 = 0, 0
paddle1_pos = HEIGHT/2
paddle2_pos = HEIGHT/2
paddle1_vel, paddle2_vel = 0, 0
(4) 通过键盘'W''S'键和上下键分别控制左手边、右手边paddle
def keydown(key):
global paddle1_vel, paddle2_vel,t
acc = 7
if key == simplegui.KEY_MAP["up"]:
paddle2_vel -= acc
elif key == simplegui.KEY_MAP["down"]:
paddle2_vel += acc
elif key == simplegui.KEY_MAP["w"]:
paddle1_vel -= acc
elif key == simplegui.KEY_MAP["s"]:
paddle1_vel += acc
print paddle1_pos, paddle2_pos
def keyup(key):
global paddle1_vel, paddle2_vel,t
acc = 7
if key == simplegui.KEY_MAP["up"]:
paddle2_vel += acc
elif key == simplegui.KEY_MAP["down"]:
paddle2_vel -= acc
elif key == simplegui.KEY_MAP["w"]:
paddle1_vel += acc
elif key == simplegui.KEY_MAP["s"]:
paddle1_vel -= acc
print paddle1_pos, paddle2_pos
(5) 更新ball和paddle位置,写在绘制上方,这样可以更新后再绘制
</pre><pre name="code" class="python"> # update ball
if (ball_pos[1] <= BALL_RADIUS) or (ball_pos[1] >=HEIGHT-BALL_RADIUS):
ball_vel[1] = -ball_vel[1]
ball_pos[0] = ball_pos[0]+ball_vel[0]
ball_pos[1] = ball_pos[1]+ball_vel[1]
# update paddle's vertical position, keep paddle on the screen
if paddle1_pos+paddle1_vel>=HALF_PAD_HEIGHT and paddle1_pos+paddle1_vel<=HEIGHT-HALF_PAD_HEIGHT:
paddle1_pos += paddle1_vel
if paddle2_pos+paddle2_vel>=HALF_PAD_HEIGHT and paddle2_pos+paddle2_vel<=HEIGHT-HALF_PAD_HEIGHT:
paddle2_pos += paddle2_vel
(6) 确定球与控制块是否碰撞来确定转向还是开启下一轮
# determine whether paddle and ball collide
crit_x_d = PAD_WIDTH+BALL_RADIUS
crit_y_d = HALF_PAD_HEIGHT
pos_x1_d = math.fabs(0-ball_pos[0])
pos_x2_d = math.fabs(WIDTH-ball_pos[0])
pos_y1_d = math.fabs(paddle1_pos-ball_pos[1])
pos_y2_d = math.fabs(paddle2_pos-ball_pos[1])
if pos_x1_d<=BALL_RADIUS:
score2 +=1
spawn_ball(RIGHT)
if pos_x2_d<=BALL_RADIUS:
score1 = score1+1
spawn_ball(LEFT)
elif (pos_x1_d<=crit_x_d and pos_y1_d<=crit_y_d) or (pos_x2_d<=crit_x_d and pos_y2_d<=crit_y_d):
ball_vel[0]=-ball_vel[0]
(7) 最后编写绘制分数代码
# draw scores
canvas.draw_text('score1',(250,20),15,'Red')
canvas.draw_text('score2',(350,20),15,'Red')
canvas.draw_text(str(score1),(270,30),12,'Red')
canvas.draw_text(str(score2),(370,30),12,'Red')
这是一次值得经历的过程,虽然创作过程坎坷,最后的显示简单,但其背后的思路分析、编写顺序是切身捋一次才能深刻学习到。下图便为游戏的界面显示。我要坚持下去,相信熟练后,可以添加更多丰富的细节!