书籍:《PYTHON游戏编程入门》(More Python Programming for the Absolute Beginner)
本文为第九章知识点总结以及核心代码,欢迎交流
第九章
列表
这一章介绍了列表的概念,并且给出了一些针对列表的操作,这里对这些操作做一个总结:
可以参照python编程 从入门到实践 第四章总结
- 列表的创建:列表是由中括号
[]
括起来的一些元素的集合。 - 修改一个元素:可以通过索引编号来获取列表中的任何元素的数据,可以通过引用索引编号来修改该元素。
- 添加一个元素:使用
lst.append(elenemt)
的方法把新的项添加到列表当中。 - 插入一个元素:使用
lst.insert(loc, element)
的方法将一个元素插入到列表的中间,第一个参数是插入的位置索引,第二个参数是要插入的元素。 - 计数元素:如果列表中存在重复的元素,可以通过
lst.count(element)
的方法对其进行计数。 - 搜素元素:可以使用
lst.index(element)
的方法来搜索一个具体的元素在列表中第一次出现的位置。 - 删除元素:使用·lst.remove(element)`方法来删除列表中的一个元素,删除的是传递的值的第一次出现,并且只会删除一次。
- 将列表反向:使用
lst.reverse()
方法可以将整个列表反向,但是并不会实际修改列表中的每一个元素。 - 排序列表:使用
lst.sort()
方法将列表中的元素排序(升序) - 对于多维度列表,可以直接写成多维的形式:
grid = [[1,2,3],[4,5,6],[7,8,9]]
(使用方括号中带有索引的语法访问单个元素)也可以使用但唯独列表来模拟二维(多维)列表,对于二维列表,索引转换公式为:row*10+col
元组
元组与列表类似,但是元组是只读的,意味着代码中一旦进行了初始化,这些项就不可以再更改了。元组中的元素放在圆括号()
中,以便与列表区分开。元组的主要优点在于他的速度很快。
- 打包:指创建一个元组的过程。
- 解包:指从元组中读取数据的过程。
- 搜索元素:可以用
'element' in tpl
来在一定的范围内搜索我们想要的元素。 - 计数元素:使用
tpl.count(element)
方法返回一个元组中具有指定的值的元素的数目。 - 求元组长度:使用
len(tpl)
方法得到远足中所有元素的数目。
Block Breaker 游戏
主干思路
这个游戏的思路如下:
- set level tuple
- init params
- handle player input
- choose level
- init the game
- load level information
- wait for mouse press to release the ball
- move ball accroding to the vel now and the direction
- move paddle according to player’s operation
- handle collision between ball and paddle
- handle collision between ball and block
- update drawing
下面给出主函数部分的代码:
# main program
# init some params
pygame.init()
SCREEN_X = 800
SCREEN_Y = 600
KEYS_PADDLE_MOVE = 10.0
PADDLE_X = 90
PADDLE_Y = 60
BALL_SIZE = 20
choose_level = True
stage_clear = False
score = 0
waiting = True
game_over = False
lives = 3
level = 0
game_init()
movex = 0.0
movey = 0.0
mousex = 0.0
mousey = 0.0
while True:
timer.tick(30)
ticks = pygame.time.get_ticks()
# handle events
for event in pygame.event.get():
if event.type == QUIT:
sys.exit()
elif choose_level:
if event.type == KEYUP:
if event.key == K_1:
level = 0
choose_level = False
load_level()
elif event.key == K_2:
level = 1
load_level()
choose_level = False
elif event.key == K_3:
level = 2
load_level()
choose_level = False
elif event.key == K_4:
level = 3
choose_level = False
elif event.key == K_5:
level = 4
choose_level = False
elif event.key == K_6:
level = 5
choose_level = False
'''
if event.key == K_RETURN:
goto_next_level()#利用回车选关
'''
elif event.type == MOUSEMOTION:
movex, movey = event.rel
mousex, mousey = event.pos
elif event.type == MOUSEBUTTONUP:
if waiting and not choose_level:
waiting = False
reset_ball()
# handle key presses
keys = pygame.key.get_pressed()
if keys[K_ESCAPE]:
sys.exit()
screen.fill((50, 50, 50))
if choose_level:
printText(font_big, 150, 200, "BLOCK BREAKER")
printText(font_t, 200, 400, 'Press 1 - 6 to choose level')
elif stage_clear:
stage_clear = False
printText(font_big, 60, 260, "S T A G E C L E A R !")
pygame.display.update()
time.sleep(3)
else:
print(choose_level)
# updates
if not game_over:
move_paddle()
move_ball()
collision_ball_paddle()
collision_ball_blocks()
update_blocks()
# draw
block_group.draw(screen)
paddle_group.draw(screen)
ball_group.draw(screen)
printText(font_t, 0, 0, "SCORE")
printText(font_num, 150, 6, str(score))
printText(font_t, 250, 0, "LEVEL")
printText(font_num, 350, 6, str(level+1))
printText(font_t, 450, 0, "BLOCKS")
printText(font_num, 600, 6, str(len(block_group)))
printText(font_t, 690, 0, "BALLS")
printText(font_num, 780, 6, str(lives))
if game_over:
printText(font_big, 100, 260, "G A M E O V E R !")
pygame.display.update()
set level tuple
关卡的设置通过一个二维元组来存储。
其中的数字表示砖块的硬度,即打几下可以消失。
levels = (
(0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,
1,0,0,0,0,0,0,0,0,0,0,1),
(1,0,1,0,1,1,1,1,0,1,0,1,
1,0,1,0,1,1,1,1,0,1,0,1,
1,0,1,0,1,1,1,1,0,1,0,1,
1,0,1,0,1,1,1,1,0,1,0,1,
1,0,1,0,1,0,0,1,0,1,0,1,
1,0,1,0,1,0,0,1,0,1,0,1,
1,0,1,0,1,1,1,1,0,1,0,1,
1,0,1,0,1,1,1,1,0,1,0,1,
1,0,1,0,1,1,1,1,0,1,0,1,
1,0,1,0,1,1,1,1,0,1,0,1),
(1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,0,0,1,1,1,1,1,
1,1,1,1,1,0,0,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1),
(2,2,2,2,2,2,2,2,2,2,2,2,
2,1,1,2,2,2,2,2,2,1,1,2,
2,1,1,2,2,2,2,2,2,1,1,2,
2,2,2,2,2,2,2,2,2,2,2,2,
2,2,2,2,2,1,1,2,2,2,2,2,
2,2,2,2,2,1,1,2,2,2,2,2,
2,2,2,2,2,2,2,2,2,2,2,2,
2,1,1,2,2,2,2,2,2,1,1,2,
2,1,1,2,2,2,2,2,2,1,1,2,
2,2,2,2,2,2,2,2,2,2,2,2),
(3,3,3,3,3,3,3,3,3,3,3,3,
3,3,0,0,0,3,3,0,0,0,3,3,
3,3,0,0,0,3,3,0,0,0,3,3,
3,3,0,0,0,3,3,0,0,0,3,3,
3,3,3,3,3,3,3,3,3,3,3,3,
3,3,3,3,3,3,3,3,3,3,3,3,
3,3,0,0,0,3,3,0,0,0,3,3,
3,3,0,0,0,3,3,0,0,0,3,3,
3,3,0,0,0,3,3,0,0,0,3,3,
3,3,3,3,3,3,3,3,3,3,3,3),
(3,4,4,4,4,4,4,4,4,4,4,3,
4,3,2,2,2,3,3,2,2,2,3,4,
4,3,2,1,2,3,3,2,1,2,3,4,
4,3,2,2,2,3,3,2,2,2,3,4,
4,3,3,3,3,3,3,3,3,3,3,4,
4,3,3,3,3,3,3,3,3,3,3,4,
4,3,2,2,2,3,3,2,2,2,3,4,
4,3,2,1,2,3,3,2,1,2,3,4,
4,3,2,2,2,3,3,2,2,2,3,4,
3,4,4,4,4,4,4,4,4,4,4,3),
)
init the game
def game_init():
global screen, font_t, font_num, font_big, timer
global paddle_group, block_group, ball_group
global paddle, block_image, block, ball
global level, game_over, waiting, lives, score
global SCREEN_X, SCREEN_Y, KEYS_PADDLE_MOVE
global PADDLE_X, PADDLE_Y, BALL_SIZE
screen = pygame.display.set_mode((SCREEN_X,SCREEN_Y))
pygame.display.set_caption('Block Breaker')
font_num = pygame.font.Font('DengXian.ttf', 30)
font_t = pygame.font.Font('BAUHS93.TTF',36)
font_big = pygame.font.Font('SNAP____.TTF',50)
pygame.mouse.set_visible(True)# the players want to see the mouse
timer = pygame.time.Clock()
# create the sprite group
block_group = pygame.sprite.Group()
paddle_group = pygame.sprite.Group()
ball_group = pygame.sprite.Group()
# create the ball
ball = MySprite()
ball.load('ball.png')
ball.pos = SCREEN_X // 2, SCREEN_Y // 2
ball_group.add(ball)
# create the paddle
paddle = MySprite()
paddle.load('paddle.png')
paddle.pos = SCREEN_X // 2, SCREEN_Y - PADDLE_Y
paddle_group.add(paddle)
load_level()
load level information
# update the blocks.
# if there is no blocks left, go to the next level.
# if there is still blocks left, update them.
def update_blocks():
global block_group, waiting, ticks, stage_clear
if len(block_group) == 0:
goto_next_level()
waiting = True
stage_clear = True
block_group.update(ticks,50)
# set the num of 'level'.
# if arrive at the last level, rotate it from the begining.
def goto_next_level():
global level, levels
level += 1
if level > len(levels) - 1:
level = 0
load_level()
# load blocks corresponding level number
def load_level():
global levels, level, block, block_image, block_group, levels
block_image = pygame.image.load('blocks.png').convert_alpha()
block_group.empty()# clear block group
for bx in range(0,12):
for by in range(0,10):
# generate a new block
block = MySprite()
block.set_image(block_image,58,28,4)
x = 40 + bx * (block.frame_width + 1)
y = 60 + by * (block.frame_height + 1)
block.pos = x,y
# read block texture
num = levels[level][by*12+bx]
if num > 0:
block.first_frame = num - 1
block.last_frame = num - 1
block_group.add(block)
move ball accroding to the vel now and the direction
# reset the vel of the ball
def reset_ball():
global ball, level
ball.velocity = Point(4.5 + level, -7.0 - level*2)
# move the ball according to its velocity now
# judge if the player has missed the ball
# and judge if no balls left at the same time
def move_ball():
global ball, game_over, lives, waiting
#move the ball
ball_group.update(ticks,50)
if waiting:
ball.x = paddle.x + 40
ball.y = paddle.y - 10
else:
ball.x += ball.velocity.x
ball.y += ball.velocity.y
# handle collision with edge of the game
if ball.x < 0:
ball.x = 0
ball.velocity.x *= -1
elif ball.x > SCREEN_X - BALL_SIZE:
ball.x = SCREEN_X - BALL_SIZE
ball.velocity.x *= -1
if ball.y < 0:
ball.y = 0
ball.velocity.y *= -1
elif ball.y > SCREEN_Y - BALL_SIZE:# miss the ball
waiting = True
lives -= 1
if lives < 1:
game_over = True
move paddle according to player’s operation
# move the paddle according to move of mouse or keys of keyboard,
# which are transformed by the params extracted from main function
def move_paddle():
global keys, waiting, mosuex, mousey #movex, movey
paddle_group.update(ticks, 50) # about ticks?
if keys[K_SPACE]:
if waiting:
waiting = False
reset_ball()
elif keys[K_LEFT]:
paddle.velocity.x = -KEYS_PADDLE_MOVE
elif keys[K_RIGHT]:
paddle.velocity.x = KEYS_PADDLE_MOVE
else:
paddle.velocity.x = 0.0
paddle.x = mousex
'''
else:
if movex < -2 or movex > 2:
paddle.velocity.x = movex
else:
paddle.velocity.x = 0.0
'''
paddle.x += paddle.velocity.x
if paddle.x < 0:
paddle.x = 0
elif paddle.x > 710:
paddle.x = 710
handle collision between ball and paddle
# handle the collision between ball and paddle
def collision_ball_paddle():
if pygame.sprite.collide_rect(ball,paddle):
ball.velocity.y = -abs(ball.velocity.y)
handle collision between ball and block
# handle the collision between ball and blocks
def collision_ball_blocks():
global score
hit_block = pygame.sprite.spritecollideany(ball, block_group)
if hit_block != None:
score += 10
# change the vel when get scores
if ball.velocity.x > 0:
ball.velocity.x += score / 12000
else:
ball.velocity.x -= score / 12000
if ball.velocity.y > 0:
ball.velocity.y += score / 6000
else:
ball.velocity.y -=score / 6000
# change block when get hit
if hit_block.first_frame > 0:
hit_block.first_frame -= 1
hit_block.last_frame -= 1
else:
block_group.remove(hit_block)
bx = ball.x + BALL_SIZE / 2
by = ball.y + BALL_SIZE / 2
if bx >= hit_block.x and bx <= hit_block.x + hit_block.frame_width:
ball.velocity.y *= -1
elif by >= hit_block.y and by <= hit_block.y + hit_block.frame_height:
ball.velocity.x *= -1
else:
ball.velocity.y *= -1