Cross Code

There is only one heroism in the world: to see the world as it is and to love it

0%

项目实战(零一):坦克大战

本篇记录的是坦克大战的项目实战。使用的图片,音乐等资源以及源代码记录在了阿伟同学 Github 仓库中,地址 https://github.com/AltriaChen/TankWar

一. 源代码

(A) main.py

1
2
3
4
5
6
7
8
9
10
11
# Thanks to  Zack
# Time 2021/02/04
# Development tool Pycharm 2020
# Environment Python 3.8.3
# Module pygame

from tank_war import TankWar

if __name__ == '__main__':
tankWar = TankWar()
tankWar.run_game()

(B) settings.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
import os
from pygame import Rect

class Settings:

# 游戏设置
FPS = 60 # 游戏帧率
GAME_NAME = "坦克大战" # 游戏标题
BOX_SIZE = 50 # 单位屏幕大小
BOX_RECT = Rect(0, 0, BOX_SIZE, BOX_SIZE) # 单位屏幕矩形
SCREEN_RECT = Rect(0, 0, BOX_SIZE * 19, BOX_SIZE * 13) # 屏幕矩形
SCREEN_COLOR = (0, 0, 0) # 屏幕颜色

# 通用变量
LEFT = 0
RIGHT = 1
UP = 2
DOWN = 3

# 地图
MAP_ONE = [
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ],
[0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, ],
[0, 1, 0, 0, 1, 3, 3, 1, 1, 2, 1, 1, 3, 3, 1, 0, 0, 1, 0, ],
[0, 1, 0, 0, 1, 3, 3, 1, 1, 2, 1, 1, 3, 3, 1, 0, 0, 1, 0, ],
[0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, ],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ],
[1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, ],
[0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, ],
[0, 1, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 1, 0, ],
[0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, ],
[0, 1, 3, 3, 3, 1, 0, 0, 0, 0, 0, 0, 0, 1, 3, 3, 3, 1, 0, ],
[0, 1, 3, 3, 3, 1, 0, 0, 1, 1, 1, 0, 0, 1, 3, 3, 3, 1, 0, ],
[0, 0, 0, 0, 0, 0, 0, 0, 1, 5, 1, 0, 0, 0, 0, 0, 0, 0, 0, ],
]

# 音频
BOOM_MUSIC = "resources/musics/boom.wav"
FIRE_MUSIC = "resources/musics/fire.wav"
HIT_MUSIC = "resources/musics/hit.wav"

# 坦克类型
HERO = 0
ENEMY = 1

# 我方坦克
HERO_IMAGE_NAME = "./resources/images/hero/hero1U.gif"
HERO_IMAGES = {
LEFT: "./resources/images/hero/hero1L.gif",
RIGHT: "./resources/images/hero/hero1R.gif",
UP: "./resources/images/hero/hero1U.gif",
DOWN: "./resources/images/hero/hero1D.gif"
}
HERO_SPEED = 2
BOSS_IMAGE = "./resources/images/5.png"
# 我方老家

# 敌方坦克
ENEMY_IMAGES = {
LEFT: "./resources/images/enemy/enemy2L.gif",
RIGHT: "./resources/images/enemy/enemy2R.gif",
UP: "./resources/images/enemy/enemy2U.gif",
DOWN: "./resources/images/enemy/enemy2D.gif"
}
ENEMY_COUNT = 5
ENEMY_SPEED = 1

# 子弹
BULLET_IMAGE_NAME = "./resources/images/bullet/bullet.png"
BULLET_RECT = Rect(0, 0, 5, 5)
BULLET_SPEED = 5

# 0表示空白、1表示红墙、2表示铁墙、3表示草、4表示海、5表示鸟
RED_WALL = 1
IRON_WALL = 2
WEED_WALL = 3
BOSS_WALL = 5
WALLS = [
f"resources/images/walls/{file}" \
for file in os.listdir("resources/images/walls/")
]

# 爆炸的图片
BOOMS = [
"resources/images/boom/" + file \
for file in os.listdir("resources/images/boom")
]

(C) sprites.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
import time
import random
import pygame
from threading import Thread
from settings import Settings

class BaseSprite(pygame.sprite.Sprite):
"""
BaseSprite类,游戏中所有变化物体的底层父类
"""
def __init__(self, image_name, screen):
super().__init__()
self.screen = screen
self.direction = None
self.speed = None
self.image = pygame.image.load(image_name)
self.rect = self.image.get_rect()

def update(self):
# 根据方向移动
if self.direction == Settings.LEFT:
self.rect.x -= self.speed
elif self.direction == Settings.RIGHT:
self.rect.x += self.speed
elif self.direction == Settings.UP:
self.rect.y -= self.speed
elif self.direction == Settings.DOWN:
self.rect.y += self.speed


class Bullet(BaseSprite):

def __init__(self, image_name, screen):
super().__init__(image_name, screen)
self.speed = Settings.BULLET_SPEED


class TankSprite(BaseSprite):
"""
ImageSprite类,BaseSprite的子类,所有带图片的精灵的父类
"""
def __init__(self, image_name, screen):
super().__init__(image_name, screen)
self.type = None
self.bullets = pygame.sprite.Group()
self.is_alive = True
self.is_moving = False

def shot(self):
"""
射击类,坦克调用该类发射子弹
:return:
"""

# 把消失的子弹移除
self.__remove_sprites()
if not self.is_alive:
return
if len(self.bullets) >= 3:
return
if self.type == Settings.HERO:
pygame.mixer.music.load(Settings.FIRE_MUSIC)
pygame.mixer.music.play()

# 发射子弹
bullet = Bullet(Settings.BULLET_IMAGE_NAME, self.screen)
bullet.direction = self.direction
if self.direction == Settings.LEFT:
bullet.rect.right = self.rect.left
bullet.rect.centery = self.rect.centery
elif self.direction == Settings.RIGHT:
bullet.rect.left = self.rect.right
bullet.rect.centery = self.rect.centery
elif self.direction == Settings.UP:
bullet.rect.bottom = self.rect.top
bullet.rect.centerx = self.rect.centerx
elif self.direction == Settings.DOWN:
bullet.rect.top = self.rect.bottom
bullet.rect.centerx = self.rect.centerx
self.bullets.add(bullet)

def move_out_wall(self, wall):
if self.direction == Settings.LEFT:
self.rect.left = wall.rect.right + 2
elif self.direction == Settings.RIGHT:
self.rect.right = wall.rect.left - 2
elif self.direction == Settings.UP:
self.rect.top = wall.rect.bottom + 2
elif self.direction == Settings.DOWN:
self.rect.bottom = wall.rect.top - 2

def __remove_sprites(self):
"""
移除无用的子弹
:return:
"""
for bullet in self.bullets:
if bullet.rect.bottom <= 0 or \
bullet.rect.top >= Settings.SCREEN_RECT.bottom or \
bullet.rect.right <= 0 or \
bullet.rect.left >= Settings.SCREEN_RECT.right:
self.bullets.remove(bullet)
bullet.kill()

def update(self):
if not self.is_alive:
return
super(TankSprite, self).update()

def boom(self):
pygame.mixer.music.load(Settings.BOOM_MUSIC)
pygame.mixer.music.play()
for boom in Settings.BOOMS:
self.image = pygame.image.load(boom)
time.sleep(0.05)
self.screen.blit(self.image, self.rect)
pygame.mixer.music.stop()
super(TankSprite, self).kill()

def kill(self):
self.is_alive = False
t = Thread(target=self.boom)
t.start()


class Hero(TankSprite):

def __init__(self, image_name, screen):
super(Hero, self).__init__(image_name, screen)
self.type = Settings.HERO
self.speed = Settings.HERO_SPEED
self.direction = Settings.UP
self.is_hit_wall = False

# 初始化英雄的位置
self.rect.centerx = Settings.SCREEN_RECT.centerx - Settings.BOX_RECT.width * 2
self.rect.bottom = Settings.SCREEN_RECT.bottom

def __turn(self):
self.image = pygame.image.load(Settings.HERO_IMAGES.get(self.direction))

def hit_wall(self):
if self.direction == Settings.LEFT and self.rect.left <= 0 or \
self.direction == Settings.RIGHT and self.rect.right >= Settings.SCREEN_RECT.right or \
self.direction == Settings.UP and self.rect.top <= 0 or \
self.direction == Settings.DOWN and self.rect.bottom >= Settings.SCREEN_RECT.bottom:
self.is_hit_wall = True

def update(self):
if not self.is_hit_wall:
super().update()
self.__turn()

def kill(self):
self.is_alive = False
self.boom()


class Enemy(TankSprite):

def __init__(self, image_name, screen):
super().__init__(image_name, screen)
self.is_hit_wall = False
self.type = Settings.ENEMY
self.speed = Settings.ENEMY_SPEED
self.direction = random.randint(0, 3)
self.terminal = float(random.randint(40*2, 40*8))

def random_turn(self):
# 随机转向
self.is_hit_wall = False
directions = [i for i in range(4)]
directions.remove(self.direction)
self.direction = directions[random.randint(0, 2)]
self.terminal = float(random.randint(40*2, 40*8))
self.image = pygame.image.load(Settings.ENEMY_IMAGES.get(self.direction))

def random_shot(self):
shot_flag = random.choice([True] + [False]*59)
if shot_flag:
super().shot()

def hit_wall_turn(self):
turn = False
if self.direction == Settings.LEFT and self.rect.left <= 0:
turn = True
self.rect.left = 2
elif self.direction == Settings.RIGHT and self.rect.right >= Settings.SCREEN_RECT.right-1:
turn = True
self.rect.right = Settings.SCREEN_RECT.right-2
elif self.direction == Settings.UP and self.rect.top <= 0:
turn = True
self.rect.top = 2
elif self.direction == Settings.DOWN and self.rect.bottom >= Settings.SCREEN_RECT.bottom-1:
turn = True
self.rect.bottom = Settings.SCREEN_RECT.bottom-2
if turn:
self.random_turn()

def update(self):
self.random_shot()
if self.terminal <= 0:
self.random_turn()
else:
super().update()
# 碰墙掉头
self.terminal -= self.speed


class Wall(BaseSprite):

def __init__(self, image_name, screen):
super().__init__(image_name, screen)
self.type = None
self.life = 2

def update(self):
pass

def boom(self):
pygame.mixer.music.load(Settings.BOOM_MUSIC)
pygame.mixer.music.play()
for boom in Settings.BOOMS:
self.image = pygame.image.load(boom)
time.sleep(0.07)
self.screen.blit(self.image, self.rect)
pygame.mixer.music.stop()
super().kill()

def kill(self):
self.life -= 1
if not self.life:
t = Thread(target=self.boom)
t.start()

(D) tank_war.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
import pygame
from sprites import *

class TankWar:

def __init__(self):
self.screen = pygame.display.set_mode(Settings.SCREEN_RECT.size)
self.clock = pygame.time.Clock()
self.game_still = True
self.hero = None
self.enemies = None
self.enemy_bullets = None
self.walls = None

@staticmethod
def __init_game():
"""
初始化游戏的一些设置
:return:
"""
pygame.init() # 初始化pygame模块
pygame.display.set_caption(Settings.GAME_NAME) # 设置窗口标题
pygame.mixer.init() # 初始化音频模块

def __create_sprite(self):
self.hero = Hero(Settings.HERO_IMAGE_NAME, self.screen)
self.enemies = pygame.sprite.Group()
self.enemy_bullets = pygame.sprite.Group()
self.walls = pygame.sprite.Group()
for i in range(Settings.ENEMY_COUNT):
direction = random.randint(0, 3)
enemy = Enemy(Settings.ENEMY_IMAGES[direction], self.screen)
enemy.direction = direction
self.enemies.add(enemy)
self.__draw_map()

def __draw_map(self):
"""
绘制地图
:return:
"""
for y in range(len(Settings.MAP_ONE)):
for x in range(len(Settings.MAP_ONE[y])):
if Settings.MAP_ONE[y][x] == 0:
continue
wall = Wall(Settings.WALLS[Settings.MAP_ONE[y][x]], self.screen)
wall.rect.x = x*Settings.BOX_SIZE
wall.rect.y = y*Settings.BOX_SIZE
if Settings.MAP_ONE[y][x] == Settings.RED_WALL:
wall.type = Settings.RED_WALL
elif Settings.MAP_ONE[y][x] == Settings.IRON_WALL:
wall.type = Settings.IRON_WALL
elif Settings.MAP_ONE[y][x] == Settings.WEED_WALL:
wall.type = Settings.WEED_WALL
elif Settings.MAP_ONE[y][x] == Settings.BOSS_WALL:
wall.type = Settings.BOSS_WALL
wall.life = 1
self.walls.add(wall)

def __check_keydown(self, event):
"""检查按下按钮的事件"""
if event.key == pygame.K_LEFT:
# 按下左键
self.hero.direction = Settings.LEFT
self.hero.is_moving = True
self.hero.is_hit_wall = False
elif event.key == pygame.K_RIGHT:
# 按下右键
self.hero.direction = Settings.RIGHT
self.hero.is_moving = True
self.hero.is_hit_wall = False
elif event.key == pygame.K_UP:
# 按下上键
self.hero.direction = Settings.UP
self.hero.is_moving = True
self.hero.is_hit_wall = False
elif event.key == pygame.K_DOWN:
# 按下下键
self.hero.direction = Settings.DOWN
self.hero.is_moving = True
self.hero.is_hit_wall = False
elif event.key == pygame.K_SPACE:
# 坦克发子弹
self.hero.shot()

def __check_keyup(self, event):
"""检查松开按钮的事件"""
if event.key == pygame.K_LEFT:
# 松开左键
self.hero.direction = Settings.LEFT
self.hero.is_moving = False
elif event.key == pygame.K_RIGHT:
# 松开右键
self.hero.direction = Settings.RIGHT
self.hero.is_moving = False
elif event.key == pygame.K_UP:
# 松开上键
self.hero.direction = Settings.UP
self.hero.is_moving = False
elif event.key == pygame.K_DOWN:
# 松开下键
self.hero.direction = Settings.DOWN
self.hero.is_moving = False

def __event_handler(self):
for event in pygame.event.get():
# 判断是否是退出游戏
if event.type == pygame.QUIT:
TankWar.__game_over()
elif event.type == pygame.KEYDOWN:
TankWar.__check_keydown(self, event)
elif event.type == pygame.KEYUP:
TankWar.__check_keyup(self, event)

def __check_collide(self):
# 保证坦克不移出屏幕
self.hero.hit_wall()
for enemy in self.enemies:
enemy.hit_wall_turn()

# 子弹击中墙
for wall in self.walls:
# 我方英雄子弹击中墙
for bullet in self.hero.bullets:
if pygame.sprite.collide_rect(wall, bullet):
if wall.type == Settings.RED_WALL:
wall.kill()
bullet.kill()
elif wall.type == Settings.BOSS_WALL:
self.game_still = False
elif wall.type == Settings.IRON_WALL:
bullet.kill()
# 敌方英雄子弹击中墙
for enemy in self.enemies:
for bullet in enemy.bullets:
if pygame.sprite.collide_rect(wall, bullet):
if wall.type == Settings.RED_WALL:
wall.kill()
bullet.kill()
elif wall.type == Settings.BOSS_WALL:
self.game_still = False
elif wall.type == Settings.IRON_WALL:
bullet.kill()

# 我方坦克撞墙
if pygame.sprite.collide_rect(self.hero, wall):
# 不可穿越墙
if wall.type == Settings.RED_WALL or wall.type == Settings.IRON_WALL or wall.type == Settings.BOSS_WALL:
self.hero.is_hit_wall = True
# 移出墙内
self.hero.move_out_wall(wall)

# 敌方坦克撞墙
for enemy in self.enemies:
if pygame.sprite.collide_rect(wall, enemy):
if wall.type == Settings.RED_WALL or wall.type == Settings.IRON_WALL or wall.type == Settings.BOSS_WALL:
enemy.move_out_wall(wall)
enemy.random_turn()

# 子弹击中、敌方坦克碰撞、敌我坦克碰撞
pygame.sprite.groupcollide(self.hero.bullets, self.enemies, True, True)
# 敌方子弹击中我方
for enemy in self.enemies:
for bullet in enemy.bullets:
if pygame.sprite.collide_rect(bullet, self.hero):
bullet.kill()
self.hero.kill()

def __update_sprites(self):
if self.hero.is_moving:
self.hero.update()
self.walls.update()
self.hero.bullets.update()
self.enemies.update()
for enemy in self.enemies:
enemy.bullets.update()
enemy.bullets.draw(self.screen)
self.enemies.draw(self.screen)
self.hero.bullets.draw(self.screen)
self.screen.blit(self.hero.image, self.hero.rect)
self.walls.draw(self.screen)

def run_game(self):
self.__init_game()
self.__create_sprite()
while True and self.hero.is_alive and self.game_still:
self.screen.fill(Settings.SCREEN_COLOR)
# 1、设置刷新帧率
self.clock.tick(Settings.FPS)
# 2、事件监听
self.__event_handler()
# 3、碰撞监测
self.__check_collide()
# 4、更新/绘制精灵/经理组
self.__update_sprites()
# 5、更新显示
pygame.display.update()
self.__game_over()

@staticmethod
def __game_over():
pygame.quit()
exit()

二. 项目介绍

(A) 运行截图

我们主程序入口在 main.py 文件,在安装好 pygame 模块后就能直接运行。下面是运行截图:

(B) 项目文件

下面是项目目录:

  • resources
    其中 resources 是资源文件。音频,图片等都在 resources 目录。

  • main.py
    main.py 是项目的主入口,代码很短:

    1
    2
    3
    4
    5
    from tank_war import TankWar

    if __name__ == '__main__':
    tankWar = TankWar()
    tankWar.run_game()

    我们直接创建了 TankWar 的实例,然后调用 run_game( ) 方法运行游戏。

  • settings.py
    settings.py 中定义了一些设置信息,包括子弹的数量,子弹的速度,坦克的速度,地图信息,图片信息等。我们可以通过修改 settings.py 来调整游戏的相关设置。

  • sprites.py
    在 pygame 中提供了一个 sprite 类用于创建有图像的物体。而 sprites 中定义的都是 sprite 的子类,因此也都是有图片的类。其中包括坦克基类,英雄类(我方坦克),敌人类(敌人坦克),子弹类,墙类等。
    而各个类中定义了各自的行为,例如:坦克类有发射子弹的行为,移动的行为,爆炸的行为等。

  • tank_war.py
    tank_war.py 中写了我们坦克大战游戏主体的模块,里面的 TankWar 类定义了游戏主体的一切行为。包括初始化屏幕,初始化 pygame 模块,创建敌方坦克,绘制地图,检测碰撞,监听事件等。

三. Tips

(A) pygame.sprite.Sprite

  • pygame.sprite.Sprite 是可见游戏对象的简单基类。有以下这些常用方法:
pygame.sprite.Sprite.update 控制精灵行为的方法
pygame.sprite.Sprite.add 将精灵添加到组中
pygame.sprite.Sprite.remove 从组中删除精灵
pygame.sprite.Sprite.kill 从所有组中删除 Sprite
pygame.sprite.Sprite.alive 精灵属于任何组的检测
pygame.sprite.Sprite.groups 包含此 Sprite 的组列表
  • 可见游戏对象的基类。派生类将覆盖 Sprite.update( ) 并分配 Sprite.image 和 Sprite.rect 属性。初始值设定项可以接受要添加的任意数量的 Group 实例。
    在对 Sprite 进行子类化时,请务必在 Sprite 添加到 Groups 之前调用基本初始值设定项。例如:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Block(pygame.sprite.Sprite):

#构建函数 传入颜色和它的 x,y 坐标
def __init__(self, color, width, height):

#调用父类(Sprite)的构建函数
pygame.sprite.Sprite.__init__(self)

#创建一个图像,用某个颜色填充
#这也可以是从磁盘加载的图像
self.image = pygame.Surface([width, height])
self.image.fill(color)

#获取具有图像尺寸的矩形对象
#通过设置rect.x和rect.y的值来更新该对象的位置
self.rect = self.image.get_rect()

(B) pygame.sprite.Group

  • pygame.sprite.Group 是用于保存和管理多个 Sprite 对象的容器类。有以下这些常用方法:
pygame.sprite.Group.sprites 此组包含的 Sprite 列表
pygame.sprite.Group.copy 复制组
pygame.sprite.Group.add 将 Sprite 添加到此组
pygame.sprite.Group.remove 从组中删除 Sprite
pygame.sprite.Group.has 测试一个 Group 是否包含 Sprite
pygame.sprite.Group.update 在包含的 Sprite 上调用 update 方法
pygame.sprite.Group.draw blit Sprite 的图像
pygame.sprite.Group.clear 在 Sprites 上绘制背景
pygame.sprite.Group.empty 删除所有 Sprite
  • Sprite 对象的简单容器。可以继承此类以创建具有更多特定行为的容器。构造函数将任意数量的 Sprite 参数添加到 Group 中。该组支持以下标准 Python 操作:
1
2
3
4
5
6
7
8
in      test if a Sprite is contained 
len the number of Sprites contained
bool test if any Sprites are contained
iter iterate through all the Sprites
in 测试是否包含Sprite
len 包含的精灵数量
bool 测试是否包含任何精灵
iter 遍历所有精灵

组中的 Sprite 不是有序的,因此绘制和迭代 Sprites 没有特别的顺序。

(C) super( ) 函数

(a) 概述

super( ) 函数用于调用父类(超类)的一个方法。
super( ) 是用来解决多重继承问题的,直接用类名调用父类方法在使用单继承的时候没问题,但是如果使用多继承,会涉及到查找顺序 (MRO),重复调用(钻石继承)等种种问题。MRO 就是类的方法解析顺序表,其实也就是继承父类方法时的顺序表。

(b) 语法

以下是 super( ) 方法的语法:

1
super(type[, object-or-type])

其中

1
2
type -- 类
object-or-type -- 类,一般是self

注,Python3.x 和 Python2.x 的一个区别是,Python3 可以使用 super().xxx 代替 super(Class,self).xxx

Python3.x 实例:

1
2
3
4
5
6
7
8
9
class A:
def add(self, x):
y = x+1
print(y)
class B(A):
def add(self, x):
super().add(x)
b = B()
b.add(2) # 3

Python2.x 实例:

1
2
3
4
5
6
7
8
9
class A(object):   # Python2.x 记得继承object
def add(self, x):
y = x+1
print(y)
class B(A):
def add(self, x):
super(B, self).add(x)
b = B()
b.add(2) # 3

(c) 实例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class FooParent(object):
def __init__(self):
self.parent = 'I\'m the parent.'
print('Parent')

def bar(self, message):
print("%s from Parent" % message)


class FooChild(FooParent):
def __init__(self):
# super(FooChild,self) 首先找到 FooChild 的父类(就是类 FooParent),
#然后把类 FooChild 的对象转换为类 FooParent 的对象
super(FooChild, self).__init__()
print('Child')

def bar(self, message):
super(FooChild, self).bar(message)
print('Child bar fuction')
print(self.parent)


if __name__ == '__main__':
fooChild = FooChild()
fooChild.bar('HelloWorld')

结果为

1
2
3
4
5
Parent
Child
HelloWorld from Parent
Child bar fuction
I'm the parent.

(D) staticmethod( ) 函数

(a) 概述

python staticmethod 返回函数的静态方法。
该方法不强制要求传递参数,如下声明一个静态方法:

1
2
3
4
class C(object):
@staticmethod
def f(arg1, arg2, ...):
...

以上实例声明了静态方法 f,从而可以不实例化调用该方法 C.f()

(b) 实例

1
2
3
4
5
6
7
8
class C(object):
@staticmethod
def f():
print('runoob');

C.f(); # 静态方法无需实例化
cobj = C()
cobj.f() # 也可以实例化后调用