Python实现四个经典小游戏合集

这篇文章主要介绍了利用Python编写一个经典小游戏的合集,包括:贪吃蛇,扫雷,俄罗斯方块,五子棋。感兴趣的小伙伴可以跟随小编一起学习一下

目录

 一、效果展示

1、俄罗斯方块

这个应该是玩起来最最简单的了…

2、扫雷

运气好,点了四下都没踩雷哈哈…

3、五子棋

我是菜鸡,玩不赢电脑人…

4、

4、贪吃蛇

害,这个是最惊心动魄的,为了我的小心脏,不玩了不玩了…

女朋友:你就是借机在玩游戏,逮到了

啊这…

那我不吹牛逼了,我们来敲代码吧~

二、代码展示

1、俄罗斯方块

方块部分

这部分代码单独保存py文件,这里我命名为 blocks.py

方块形状的设计,一开始我是做成 4 × 4,长宽最长都是4的话旋转的时候就不考虑怎么转了,就是从一个图形替换成另一个。

要实现这个功能,只要固定左上角的坐标就可以了。

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

import random

from collections import namedtuple

Point = namedtuple('Point', 'X Y')

Shape = namedtuple('Shape', 'X Y Width Height')

Block = namedtuple('Block', 'template start_pos end_pos name next')

# S形方块

S_BLOCK = [Block(['.OO',

                  'OO.',

                  '...'], Point(0, 0), Point(2, 1), 'S', 1),

           Block(['O..',

                  'OO.',

                  '.O.'], Point(0, 0), Point(1, 2), 'S', 0)]

# Z形方块

Z_BLOCK = [Block(['OO.',

                  '.OO',

                  '...'], Point(0, 0), Point(2, 1), 'Z', 1),

           Block(['.O.',

                  'OO.',

                  'O..'], Point(0, 0), Point(1, 2), 'Z', 0)]

# I型方块

I_BLOCK = [Block(['.O..',

                  '.O..',

                  '.O..',

                  '.O..'], Point(1, 0), Point(1, 3), 'I', 1),

           Block(['....',

                  '....',

                  'OOOO',

                  '....'], Point(0, 2), Point(3, 2), 'I', 0)]

# O型方块

O_BLOCK = [Block(['OO',

                  'OO'], Point(0, 0), Point(1, 1), 'O', 0)]

# J型方块

J_BLOCK = [Block(['O..',

                  'OOO',

                  '...'], Point(0, 0), Point(2, 1), 'J', 1),

           Block(['.OO',

                  '.O.',

                  '.O.'], Point(1, 0), Point(2, 2), 'J', 2),

           Block(['...',

                  'OOO',

                  '..O'], Point(0, 1), Point(2, 2), 'J', 3),

           Block(['.O.',

                  '.O.',

                  'OO.'], Point(0, 0), Point(1, 2), 'J', 0)]

# L型方块

L_BLOCK = [Block(['..O',

                  'OOO',

                  '...'], Point(0, 0), Point(2, 1), 'L', 1),

           Block(['.O.',

                  '.O.',

                  '.OO'], Point(1, 0), Point(2, 2), 'L', 2),

           Block(['...',

                  'OOO',

                  'O..'], Point(0, 1), Point(2, 2), 'L', 3),

           Block(['OO.',

                  '.O.',

                  '.O.'], Point(0, 0), Point(1, 2), 'L', 0)]

# T型方块

T_BLOCK = [Block(['.O.',

                  'OOO',

                  '...'], Point(0, 0), Point(2, 1), 'T', 1),

           Block(['.O.',

                  '.OO',

                  '.O.'], Point(1, 0), Point(2, 2), 'T', 2),

           Block(['...',

                  'OOO',

                  '.O.'], Point(0, 1), Point(2, 2), 'T', 3),

           Block(['.O.',

                  'OO.',

                  '.O.'], Point(0, 0), Point(1, 2), 'T', 0)]

BLOCKS = { 'O': O_BLOCK,

          'I': I_BLOCK,

          'Z': Z_BLOCK,

          'T': T_BLOCK,

          'L': L_BLOCK,

          'S': S_BLOCK,

          'J': J_BLOCK}

def get_block():

    block_name = random.choice('OIZTLSJ')

    b = BLOCKS[block_name]

    idx = random.randint(0, len(b) - 1)

    return b[idx]

def get_next_block(block):

    b = BLOCKS[block.name]

    return b[block.next]

素材 

游戏主代码

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 sys

import time

import pygame

from pygame.locals import *

import blocks

SIZE = 30  # 每个小方格大小

BLOCK_HEIGHT = 25  # 游戏区高度

BLOCK_WIDTH = 10   # 游戏区宽度

BORDER_WIDTH = 4   # 游戏区边框宽度

BORDER_COLOR = (40, 40, 200# 游戏区边框颜色

SCREEN_WIDTH = SIZE * (BLOCK_WIDTH + 5# 游戏屏幕的宽

SCREEN_HEIGHT = SIZE * BLOCK_HEIGHT      # 游戏屏幕的高

BG_COLOR = (40, 40, 60# 背景色

BLOCK_COLOR = (20, 128, 200#

BLACK = (0, 0, 0)

RED = (200, 30, 30)      # GAME OVER 的字体颜色

def print_text(screen, font, x, y, text, fcolor=(255, 255, 255)):

    imgText = font.render(text, True, fcolor)

    screen.blit(imgText, (x, y))

def main():

    pygame.init()

    screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))

    pygame.display.set_caption('俄罗斯方块')

    font1 = pygame.font.SysFont('SimHei', 24# 黑体24

    font2 = pygame.font.Font(None, 72# GAME OVER 的字体

    font_pos_x = BLOCK_WIDTH * SIZE + BORDER_WIDTH + 10  # 右侧信息显示区域字体位置的X坐标

    gameover_size = font2.size('GAME OVER')

    font1_height = int(font1.size('得分')[1])

    cur_block = None   # 当前下落方块

    next_block = None  # 下一个方块

    cur_pos_x, cur_pos_y = 0, 0

    game_area = None    # 整个游戏区域

    game_over = True

    start = False       # 是否开始,当start = True,game_over = True 时,才显示 GAME OVER

    score = 0           # 得分

    orispeed = 0.5      # 原始速度

    speed = orispeed    # 当前速度

    pause = False       # 暂停

    last_drop_time = None   # 上次下落时间

    last_press_time = None  # 上次按键时间

    def _dock():

        nonlocal cur_block, next_block, game_area, cur_pos_x, cur_pos_y, game_over, score, speed

        for _i in range(cur_block.start_pos.Y, cur_block.end_pos.Y + 1):

            for _j in range(cur_block.start_pos.X, cur_block.end_pos.X + 1):

                if cur_block.template[_i][_j] != '.':

                    game_area[cur_pos_y + _i][cur_pos_x + _j] = '0'

        if cur_pos_y + cur_block.start_pos.Y <= 0:

            game_over = True

        else:

            # 计算消除

            remove_idxs = []

            for _i in range(cur_block.start_pos.Y, cur_block.end_pos.Y + 1):

                if all(_x == '0' for _x in game_area[cur_pos_y + _i]):

                    remove_idxs.append(cur_pos_y + _i)

            if remove_idxs:

                # 计算得分

                remove_count = len(remove_idxs)

                if remove_count == 1:

                    score += 100

                elif remove_count == 2:

                    score += 300

                elif remove_count == 3:

                    score += 700

                elif remove_count == 4:

                    score += 1500

                speed = orispeed - 0.03 * (score // 10000)

                # 消除

                _i = _j = remove_idxs[-1]

                while _i >= 0:

                    while _j in remove_idxs:

                        _j -= 1

                    if _j < 0:

                        game_area[_i] = ['.'] * BLOCK_WIDTH

                    else:

                        game_area[_i] = game_area[_j]

                    _i -= 1

                    _j -= 1

            cur_block = next_block

            next_block = blocks.get_block()

            cur_pos_x, cur_pos_y = (BLOCK_WIDTH - cur_block.end_pos.X - 1) // 2, -1 - cur_block.end_pos.Y

    def _judge(pos_x, pos_y, block):

        nonlocal game_area

        for _i in range(block.start_pos.Y, block.end_pos.Y + 1):

            if pos_y + block.end_pos.Y >= BLOCK_HEIGHT:

                return False

            for _j in range(block.start_pos.X, block.end_pos.X + 1):

                if pos_y + _i >= 0 and block.template[_i][_j] != '.' and game_area[pos_y + _i][pos_x + _j] != '.':

                    return False

        return True

    while True:

        for event in pygame.event.get():

            if event.type == QUIT:

                sys.exit()

            elif event.type == KEYDOWN:

                if event.key == K_RETURN:

                    if game_over:

                        start = True

                        game_over = False

                        score = 0

                        last_drop_time = time.time()

                        last_press_time = time.time()

                        game_area = [['.'] * BLOCK_WIDTH for _ in range(BLOCK_HEIGHT)]

                        cur_block = blocks.get_block()

                        next_block = blocks.get_block()

                        cur_pos_x, cur_pos_y = (BLOCK_WIDTH - cur_block.end_pos.X - 1) // 2, -1 - cur_block.end_pos.Y

                elif event.key == K_SPACE:

                    if not game_over:

                        pause = not pause

                elif event.key in (K_w, K_UP):

                    if 0 <= cur_pos_x <= BLOCK_WIDTH - len(cur_block.template[0]):

                        _next_block = blocks.get_next_block(cur_block)

                        if _judge(cur_pos_x, cur_pos_y, _next_block):

                            cur_block = _next_block

        if event.type == pygame.KEYDOWN:

            if event.key == pygame.K_LEFT:

                if not game_over and not pause:

                    if time.time() - last_press_time > 0.1:

                        last_press_time = time.time()

                        if cur_pos_x > - cur_block.start_pos.X:

                            if _judge(cur_pos_x - 1, cur_pos_y, cur_block):

                                cur_pos_x -= 1

            if event.key == pygame.K_RIGHT:

                if not game_over and not pause:

                    if time.time() - last_press_time > 0.1:

                        last_press_time = time.time()

                        # 不能移除右边框

                        if cur_pos_x + cur_block.end_pos.X + 1 < BLOCK_WIDTH:

                            if _judge(cur_pos_x + 1, cur_pos_y, cur_block):

                                cur_pos_x += 1

            if event.key == pygame.K_DOWN:

                if not game_over and not pause:

                    if time.time() - last_press_time > 0.1:

                        last_press_time = time.time()

                        if not _judge(cur_pos_x, cur_pos_y + 1, cur_block):

                            _dock()

                        else:

                            last_drop_time = time.time()

                            cur_pos_y += 1

        _draw_background(screen)

        _draw_game_area(screen, game_area)

        _draw_gridlines(screen)

        _draw_info(screen, font1, font_pos_x, font1_height, score)

        # 画显示信息中的下一个方块

        _draw_block(screen, next_block, font_pos_x, 30 + (font1_height + 6) * 5, 0, 0)

        if not game_over:

            cur_drop_time = time.time()

            if cur_drop_time - last_drop_time > speed:

                if not pause:

                    if not _judge(cur_pos_x, cur_pos_y + 1, cur_block):

                        _dock()

                    else:

                        last_drop_time = cur_drop_time

                        cur_pos_y += 1

        else:

            if start:

                print_text(screen, font2,

                           (SCREEN_WIDTH - gameover_size[0]) // 2, (SCREEN_HEIGHT - gameover_size[1]) // 2,

                           'GAME OVER', RED)

        # 画当前下落方块

        _draw_block(screen, cur_block, 0, 0, cur_pos_x, cur_pos_y)

        pygame.display.flip()

# 画背景

def _draw_background(screen):

    # 填充背景色

    screen.fill(BG_COLOR)

    # 画游戏区域分隔线

    pygame.draw.line(screen, BORDER_COLOR,

                     (SIZE * BLOCK_WIDTH + BORDER_WIDTH // 2, 0),

                     (SIZE * BLOCK_WIDTH + BORDER_WIDTH // 2, SCREEN_HEIGHT), BORDER_WIDTH)

# 画网格线

def _draw_gridlines(screen):

    # 画网格线 竖线

    for x in range(BLOCK_WIDTH):

        pygame.draw.line(screen, BLACK, (x * SIZE, 0), (x * SIZE, SCREEN_HEIGHT), 1)

    # 画网格线 横线

    for y in range(BLOCK_HEIGHT):

        pygame.draw.line(screen, BLACK, (0, y * SIZE), (BLOCK_WIDTH * SIZE, y * SIZE), 1)

# 画已经落下的方块

def _draw_game_area(screen, game_area):

    if game_area:

        for i, row in enumerate(game_area):

            for j, cell in enumerate(row):

                if cell != '.':

                    pygame.draw.rect(screen, BLOCK_COLOR, (j * SIZE, i * SIZE, SIZE, SIZE), 0)

# 画单个方块

def _draw_block(screen, block, offset_x, offset_y, pos_x, pos_y):

    if block:

        for i in range(block.start_pos.Y, block.end_pos.Y + 1):

            for j in range(block.start_pos.X, block.end_pos.X + 1):

                if block.template[i][j] != '.':

                    pygame.draw.rect(screen, BLOCK_COLOR,

                                     (offset_x + (pos_x + j) * SIZE, offset_y + (pos_y + i) * SIZE, SIZE, SIZE), 0)

# 画得分等信息

def _draw_info(screen, font, pos_x, font_height, score):

    print_text(screen, font, pos_x, 10, f'得分: ')

    print_text(screen, font, pos_x, 10 + font_height + 6, f'{score}')

    print_text(screen, font, pos_x, 20 + (font_height + 6) * 2, f'速度: ')

    print_text(screen, font, pos_x, 20 + (font_height + 6) * 3, f'{score // 10000}')

    print_text(screen, font, pos_x, 30 + (font_height + 6) * 4, f'下一个:')

if __name__ == '__main__':

    main()

2、扫雷

地雷部分

一样的,单独保存py文件,mineblock.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

import random

from enum import Enum

BLOCK_WIDTH = 30

BLOCK_HEIGHT = 16

SIZE = 20           # 块大小

MINE_COUNT = 99     # 地雷数

class BlockStatus(Enum):

    normal = 1  # 未点击

    opened = 2  # 已点击

    mine = 3    # 地雷

    flag = 4    # 标记为地雷

    ask = 5     # 标记为问号

    bomb = 6    # 踩中地雷

    hint = 7    # 被双击的周围

    double = 8  # 正被鼠标左右键双击

class Mine:

    def __init__(self, x, y, value=0):

        self._x = x

        self._y = y

        self._value = 0

        self._around_mine_count = -1

        self._status = BlockStatus.normal

        self.set_value(value)

    def __repr__(self):

        return str(self._value)

        # return f'({self._x},{self._y})={self._value}, status={self.status}'

    def get_x(self):

        return self._x

    def set_x(self, x):

        self._x = x

    x = property(fget=get_x, fset=set_x)

    def get_y(self):

        return self._y

    def set_y(self, y):

        self._y = y

    y = property(fget=get_y, fset=set_y)

    def get_value(self):

        return self._value

    def set_value(self, value):

        if value:

            self._value = 1

        else:

            self._value = 0

    value = property(fget=get_value, fset=set_value, doc='0:非地雷 1:雷')

    def get_around_mine_count(self):

        return self._around_mine_count

    def set_around_mine_count(self, around_mine_count):

        self._around_mine_count = around_mine_count

    around_mine_count = property(fget=get_around_mine_count, fset=set_around_mine_count, doc='四周地雷数量')

    def get_status(self):

        return self._status

    def set_status(self, value):

        self._status = value

    status = property(fget=get_status, fset=set_status, doc='BlockStatus')

class MineBlock:

    def __init__(self):

        self._block = [[Mine(i, j) for i in range(BLOCK_WIDTH)] for j in range(BLOCK_HEIGHT)]

        # 埋雷

        for i in random.sample(range(BLOCK_WIDTH * BLOCK_HEIGHT), MINE_COUNT):

            self._block[i // BLOCK_WIDTH][i % BLOCK_WIDTH].value = 1

    def get_block(self):

        return self._block

    block = property(fget=get_block)

    def getmine(self, x, y):

        return self._block[y][x]

    def open_mine(self, x, y):

        # 踩到雷了

        if self._block[y][x].value:

            self._block[y][x].status = BlockStatus.bomb

            return False

        # 先把状态改为 opened

        self._block[y][x].status = BlockStatus.opened

        around = _get_around(x, y)

        _sum = 0

        for i, j in around:

            if self._block[j][i].value:

                _sum += 1

        self._block[y][x].around_mine_count = _sum

        # 如果周围没有雷,那么将周围8个未中未点开的递归算一遍

        # 这就能实现一点出现一大片打开的效果了

        if _sum == 0:

            for i, j in around:

                if self._block[j][i].around_mine_count == -1:

                    self.open_mine(i, j)

        return True

    def double_mouse_button_down(self, x, y):

        if self._block[y][x].around_mine_count == 0:

            return True

        self._block[y][x].status = BlockStatus.double

        around = _get_around(x, y)

        sumflag = 0     # 周围被标记的雷数量

        for i, j in _get_around(x, y):

            if self._block[j][i].status == BlockStatus.flag:

                sumflag += 1

        # 周边的雷已经全部被标记

        result = True

        if sumflag == self._block[y][x].around_mine_count:

            for i, j in around:

                if self._block[j][i].status == BlockStatus.normal:

                    if not self.open_mine(i, j):

                        result = False

        else:

            for i, j in around:

                if self._block[j][i].status == BlockStatus.normal:

                    self._block[j][i].status = BlockStatus.hint

        return result

    def double_mouse_button_up(self, x, y):

        self._block[y][x].status = BlockStatus.opened

        for i, j in _get_around(x, y):

            if self._block[j][i].status == BlockStatus.hint:

                self._block[j][i].status = BlockStatus.normal

def _get_around(x, y):

    """返回(x, y)周围的点的坐标"""

    # 这里注意,range 末尾是开区间,所以要加 1

    return [(i, j) for i in range(max(0, x - 1), min(BLOCK_WIDTH - 1, x + 1) + 1)

            for j in range(max(0, y - 1), min(BLOCK_HEIGHT - 1, y + 1) + 1) if i != x or j != y]

以上就是Python实现四个经典小游戏合集的详细内容

在这里还是要推荐下我自己建的Python学习Q群:831804576,群里都是学Python的,如果你想学或者正在学习Python ,欢迎你加入,大家都是软件开发党,不定期分享干货(只有Python软件开发相关的),
包括我自己整理的一份2021最新的Python进阶资料和零基础教学,欢迎进阶中和对Python感兴趣的小伙伴加入!

猜你喜欢

转载自blog.csdn.net/BYGFJ/article/details/124162979