Pygame-Python游戏编程⼊门(1)
前⾔
在上⼀篇中,我们初步熟悉了pygame的控制流程,但这对于⼀个游戏⽽⾔是远远不够的。所以在这⼀篇中,我们的任务是添加⼀架飞机(玩家),并且能够控制它进⾏移动,这样我们就⼜离⽬标进了⼀步了~ε=ε=(ノ≧∇≦)ノ
正⽚开始!
1. 把我们的战⽃机搬上屏幕
在正式上代码以前,有⼀点需要说明的,我们可以看到,所有屏幕上出现的元素都在资源⽂件(resources/image/shoot.png)中,那我们要怎么做才能把⼀只飞机给裁剪出来呢?在pygame中,所有在屏幕上显⽰的元素都可以视为⼀个surface,利⽤这个特点,我们可以把资源⽂件导⼊(load()函数),然后⽤surface.subsurface()函数把shoot.png中我们想要的元素裁剪出来,这样问题就解决了~(tips:怎样才知道shoot.png中飞机的准确坐标呢?在resources/image/shoot.pack⽂件中已经详细记录了每个屏幕元素的左上⾓坐标以及它的宽和⾼了)
先上代码:(在注释# == new add ==之间的代码为新加⼊代码)
1import pygame # 导⼊pygame库
2from pygame.locals import * # 导⼊pygame库中的⼀些常量
3from sys import exit # 导⼊sys库中的exit函数
4
5# 定义窗⼝的分辨率
6 SCREEN_WIDTH = 480
7 SCREEN_HEIGHT = 640
8
9# 计数ticks == new add ==
10 ticks = 0
11# 计数ticks == new add ==
12
13# 初始化游戏
14 pygame.init() # 初始化pygame
15 screen = pygame.display.set_mode([SCREEN_WIDTH, SCREEN_HEIGHT]) # 初始化窗⼝
16 pygame.display.set_caption('This is my first pygame-program') # 设置窗⼝标题
17
18# 载⼊背景图
19 background = pygame.image.load('resources/image/background.png')
20
21# 载⼊资源图⽚ == new add ==
22 shoot_img = pygame.image.load('resources/image/shoot.png')
23# ⽤subsurface剪切读⼊的图⽚
24 hero1_rect = pygame.Rect(0, 99, 102, 126)
25 hero2_rect = pygame.Rect(165, 360, 102, 126)
26 hero1 = shoot_img.subsurface(hero1_rect)
27 hero2 = shoot_img.subsurface(hero2_rect)
28 hero_pos = [200, 500]
python可以做什么游戏29# 载⼊资源图⽚ == new add ==
30
31# 事件循环(main loop)
32while True:
33
34# 绘制背景
35 screen.blit(background, (0, 0))
36
37# 绘制飞机 == new add ==
38if ticks % 50 < 25:
39 screen.blit(hero1, hero_pos)
40else:
41 screen.blit(hero2, hero_pos)
42 ticks += 1
43# 绘制飞机 == new add ==
44
45# 更新屏幕
46 pygame.display.update()
47
48# 处理游戏退出
49# 从消息队列中循环取
50for event in ():
pe == pygame.QUIT:
52 pygame.quit()
53 exit()
不妨运⾏⼀下:
可以看到,我们的飞机动了,究竟是怎样实现动画效果的呢?在代码中,新加⼊的代码⼀共有三处,显⽰玩家飞机的那⼀段已经解释过了,现在我们
来解释其余的两段新加⼊的代码。⾸先增加了⼀个计数变量ticks,在消息循环中,每循环⼀次就累加⼀次,可以理解为每⼀个周期就是1 tick,我们可以利⽤周期数来分隔不同的显⽰效果;我们读⼊了两张不同的玩家飞机图⽚,利⽤周期数实现每50个周期,前25个周期显⽰hero1,后25个周期显⽰hero2,这样就有了缓慢变化的动态效果。不过值得注意的是,这样每⼀次循环就计算并判断⼀次ticks的做法明显不是好⽅法。还有!(╯°⼝°)╯(┴—┴,Python是⽊有⾃增表达式的,我试图++ticks结果报错了。
战⽃机已经准备就绪,该教会飞⾏员怎样操作了~(`·ω·´)
2. ⽤键盘控制飞机移动
我们知道,每敲⼀下键盘都会产⽣⼀个事件,⽽这个事件能被Python检测到,既然知道了这个⼤前提,那控制飞机就很容易了。
come on code~ ( °∀°)
1import pygame # 导⼊pygame库
2from pygame.locals import * # 导⼊pygame库中的⼀些常量
3from sys import exit # 导⼊sys库中的exit函数
4
5# 定义窗⼝的分辨率
6 SCREEN_WIDTH = 480
7 SCREEN_HEIGHT = 640
8
9 ticks = 0
10# dict == new add ==
11 offset = {pygame.K_LEFT:0, pygame.K_RIGHT:0, pygame.K_UP:0, pygame.K_DOWN:0}
12# dict == new add ==
13
14# 初始化游戏
15 pygame.init() # 初始化pygame
16 screen = pygame.display.set_mode([SCREEN_WIDTH, SCREEN_HEIGHT]) # 初始化窗⼝
17 pygame.display.set_caption('This is my first pygame-program') # 设置窗⼝标题
18
19# 载⼊背景图
20 background = pygame.image.load('resources/image/background.png')
21
22# 载⼊飞机图⽚
23 shoot_img = pygame.image.load('resources/image/shoot.png')
24# ⽤subsurface剪切读⼊的图⽚
25 hero1_rect = pygame.Rect(0, 99, 102, 126)
26 hero2_rect = pygame.Rect(165, 360, 102, 126)
27 hero1 = shoot_img.subsurface(hero1_rect)
28 hero2 = shoot_img.subsurface(hero2_rect)
29 hero_pos = [200, 500]
30
31# 事件循环(main loop)
32while True:
33
34# 绘制背景
35 screen.blit(background, (0, 0))
36
37# 绘制飞机
38if ticks % 50 < 25:
39 screen.blit(hero1, hero_pos)
40else:
41 screen.blit(hero2, hero_pos)
42 ticks += 1 # python已略去⾃增运算符
43
44# 更新屏幕
45 pygame.display.update()
46
47# 处理游戏退出
48# 从消息队列中循环取
49for event in ():
pe == pygame.QUIT:
51 pygame.quit()
52 exit()
53
54# Python中没有switch-case 多⽤字典类型替代
55# 控制⽅向 == new add ==
pe == pygame.KEYDOWN:
57if event.key in offset:
58 offset[event.key] = 3
pe == pygame.KEYUP:
60if event.key in offset:
61 offset[event.key] = 0
62
63# part 1
64#offset_x = offset[pygame.K_RIGHT] - offset[pygame.K_LEFT]
65#offset_y = offset[pygame.K_DOWN] - offset[pygame.K_UP]
66#hero_pos = [hero_pos[0] + offset_x, hero_pos[1] + offset_y]
67# part 2
68 offset_x = offset[pygame.K_RIGHT] - offset[pygame.K_LEFT]
69 offset_y = offset[pygame.K_DOWN] - offset[pygame.K_UP]
70 hero_pos = [hero_pos[0] + offset_x, hero_pos[1] + offset_y]
71# 控制⽅向 == new add ==
新加⼊了两处,⼀个是字典类型的变量,⼀个是控制⽅向的代码。跟之前控制程序退出的代码⼀样,依然是从事件队列中取事件;当pe为按键事件时,再判断event.key是否属于上下左右四个键位中的其中⼀个;最后在其相应⽅向上给⼀个偏移量,即完成判断的过程;松键的话该⽅向上的偏移量赋值为0,这样该键⽅向上就没有位移了;最后将偏移量加到飞机的pos上,下⼀轮刷新时⾃然就到移动到新地⽅了。(这⾥插播⼀个事,我以前写过c++和java,所以写到判断键盘键位时,很⾃然就想⽤switch-case语句,没想到竟然出错了(╯°⼝°)╯(┴—┴,后来才发现原来Python是没有switch-case语句的,switch-case语句多⽤字典数据结构代替,感觉这样的写法就更灵活了)
上⾯讲得都⽐较简单,现在我们要思考⼀个问题,上⾯的代码中,line 63-66和line 67-70的代码是⼀样的,但两部分代码的效果却是很不⼀样。part1代码使得我们要按⼀次键飞机才会动⼀次,⽽在part2代码中我们可以长按⽅向键来控制飞机,不禁感慨⼀下Python的缩进。part1是在for循环的影响下的,也就是说,事件队列中有事件才会执⾏part1的代码,假设我们长按⽅向左键(注意,击键⼀次只会产⽣⼀个pygame.KEYDOWN事件,所以长按也只触发⼀次),飞机也只会往左移3个像素点;⽽part2代码由于不在for循环内,所以每⼀tick就向左移3个像素点直到松开⽅向左键。
演⽰⼀下效果:
好的,控制飞机已经不成问题了,不过⼤家发现飞机有⼀个⼩问题了吗?它会穿到窗⼝的“外⾯”去!不过我们只要添加⼀个⼩⼩的限制就可以解决问题了,只要把line68-70换成以下边界判断代码就可以了。
1 hero_x = hero_pos[0] + offset[pygame.K_RIGHT] - offset[pygame.K_LEFT]
2 hero_y = hero_pos[1] + offset[pygame.K_DOWN] - offset[pygame.K_UP]
3if hero_x < 0:
4 hero_pos[0] = 0
5elif hero_x > SCREEN_WIDTH - hero1_rect.width:
6 hero_pos[0] = SCREEN_WIDTH - hero1_rect.width
7else:
8 hero_pos[0] = hero_x
9
10if hero_y < 0:
11 hero_pos[1] = 0
12elif hero_y > SCREEN_HEIGHT - hero1_rect.height:
13 hero_pos[1] = SCREEN_HEIGHT - hero1_rect.height
14else:
15 hero_pos[1] = hero_y
今天功能就完成到这⾥吧~(`·ω·´)
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论