• 【Python项目】过马路游戏


    零、序章

    这是一个使用Python写的过马路游戏。

    可以练习一些面向对象的知识。

    由于全写注释CSND说我字太少,就统一写代码外面来


    实现的功能有:

    • 汽车的随机刷新、汽车的整体移动、碰撞检测
    • 玩家的移动(只能向上移动。。。没有更多操作了)
    • 关卡显示以及根据关卡自动调整汽车移动速度

    可以改进的地方有:

    • 暂停功能
    • 碰撞检测可以优化得更精准
    • 感觉有卡顿,不知道是单次循环的停顿时间根据level变化造成的错觉,还是运行到后面车太多了造成了实际的卡顿

    一、游戏主程序

    • cal_limits函数:根据screen计算边界
    • quit_game函数:控制退出游戏
    • 实例化屏幕对象、玩家对象、汽车管理员对象、计分板对象
    • 每次循环停顿时间根据level决定,level越高,停顿时间越短,达到汽车运动越快的效果(也可以通过更改汽车单次移动常量来加速)
    • 每次循环汽车要刷新、移动、进行碰撞检测
    import time
    from turtle import Screen
    from player import Player
    from car_manager import CarManager
    from scoreboard import ScoreBoard
    
    screen = Screen()
    screen.setup(width=600, height=600)
    screen.tracer(0)
    
    
    def cal_limits(screen):
        u_limit = screen.window_height() / 2
        d_limit = -screen.window_height() / 2
        l_limit = -screen.window_width() / 2
        r_limit = screen.window_width() / 2
        return u_limit, d_limit, l_limit, r_limit
    
    
    def quit_game():
        global game_is_on
        game_is_on = False
    
    
    limits = cal_limits(screen)
    
    player = Player()
    car_manager = CarManager(limits=limits)
    
    screen.listen()
    screen.onkey(key='Up', fun=player.move)
    screen.onkey(key='q', fun=quit_game)
    
    scoreboard = ScoreBoard(limits)
    
    game_is_on = True
    while game_is_on:
    
        time.sleep(0.11 - scoreboard.level * 0.015)
        screen.update()
    
        car_manager.add_car((limits[0] - 50, limits[1] + 100, limits[3], limits[3] + 300))
    
        car_manager.move(limits)
    
        if car_manager.collision_check(player):
            scoreboard.game_clear('Game Over!!!')
            player.respawn()
            scoreboard.refresh_level()
    
        if player.check_finish():
            scoreboard.refresh_level()
    
    • 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

    二、玩家类

    • 具有初始位置、单次移动距离、终点线等常量
    • 继承自Turtle类
    • 每次抵达终点线使用respawn函数回到起点
    • 使用check_finish函数检测是否抵达终点线
    STARTING_POSITION = (0, -280)
    MOVE_DISTANCE = 10
    FINISH_LINE_Y = 280
    
    from turtle import Turtle
    
    
    class Player(Turtle):
        def __init__(self):
            super().__init__()
            self.penup()
            self.shape('turtle')
            self.goto(STARTING_POSITION)
            self.setheading(90)
    
        def move(self):
            self.forward(MOVE_DISTANCE)
    
        def respawn(self):
            self.goto(STARTING_POSITION)
    
        def check_finish(self):
            if self.pos()[1] >= FINISH_LINE_Y:
                self.respawn()
                return True
    
    • 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

    三、汽车管理员类

    • 具有颜色、刷新距离、单次移动距离、刷新率等常量
    • 本身是个列表,列表内放Turtle类
    • 一开始在给定范围(基本是整个屏幕内)刷新,之后就都在屏幕右边的范围刷新
    • add_car函数:根据刷新率在屏幕右侧随机刷新汽车,,每次都要遍历汽车检测刷新距离是否满足STARTING_MOVE_DISTANCE常量,满足就加入列表
    • move函数:遍历列表,每个车都向左移动
    • collision_check碰撞检测函数:有点难做,因为我不想简单地使用distance,感觉这个是不是不能用在方形物体的碰撞检测上?我的总体思路是将整个屏幕看作一个网格,每个格子边长为10,计算出汽车上下左右边界和玩家的上下边界(左右边界感觉不用算也能判断得很精准)在哪个格子后再进行碰撞检测。
    COLORS = ["red", "orange", "yellow", "green", "blue", "purple"]
    STARTING_MOVE_DISTANCE = 10
    MOVE_INCREMENT = 10
    REFRESH_RATE = 0.3
    
    import random
    from turtle import Turtle
    
    
    class CarManager:
        def __init__(self, limits):
            self.cars = []
            spawn_range = (limits[0] - 20, limits[1] + 100, limits[2], limits[3] + 300)
            for i in range(25):
                self.add_car(spawn_range)
    
        def add_car(self, spawn_range):
            if random.random() < REFRESH_RATE:
                new_pos = (random.randint(spawn_range[2], spawn_range[3]) // 20) * 20, \
                          (random.randint(spawn_range[1], spawn_range[0]) // 20) * 20
    
                while self.cars:
                    for old_car in self.cars:
                        if old_car.distance(new_pos) <= STARTING_MOVE_DISTANCE:
                            new_pos = (random.randint(spawn_range[2], spawn_range[3]) // 20) * 20, \
                                      (random.randint(spawn_range[1], spawn_range[0]) // 20) * 20
                            break
                    else:
                        break
    
                new_car = Turtle(shape='square')
                new_car.shapesize(stretch_wid=1, stretch_len=2)
                new_car.penup()
                new_car.color(random.choice(COLORS))
                new_car.setheading(180)
                new_car.goto(new_pos)
                self.cars.append(new_car)
    
        def move(self, limits):
            for car in self.cars:
                car.forward(MOVE_INCREMENT)
                if car.pos()[0] < limits[2] - 20:
                    car.ht()
                    self.cars.remove(car)
    
        def collision_check(self, player):
            player_up_y_block = (player.pos()[1] + 10) // 10
            player_down_y_block = (player.pos()[1] - 10) // 10
    
            for car in self.cars:
                car_left_x_block = (car.pos()[0] - 20) // 10
                car_right_x_block = (car.pos()[0] + 20) // 10
                car_up_y_block = (car.pos()[1] + 10) // 10
                car_down_y_block = (car.pos()[1] - 10) // 10
                if car_left_x_block <= 0 <= car_right_x_block and \
                        (car_down_y_block < player_up_y_block < car_up_y_block or
                         car_down_y_block < player_down_y_block < car_up_y_block):
                    return True
    
    • 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

    四、计分板类

    • 具有字体、最大关数等常量
    • 计分板类继承自Turtle类,具有额外的level属性
    • 其他功能和之前发的贪吃蛇、乒乓类似,就不赘述了,只多了个检测通关的功能
    FONT = ("Courier", 24, "normal")
    MAX_LEVEL = 7
    
    import time
    from turtle import Turtle
    
    
    class ScoreBoard(Turtle):
        def __init__(self, limits):
            super().__init__()
            self.level = 1
            self.penup()
            self.ht()
            self.goto(limits[2] + 20, limits[0] - 50)
            self.write(f"Level:{self.level}", font=FONT)
    
        def refresh_level(self):
            if self.level >= MAX_LEVEL:
                self.game_clear('Game Clear!!!')
            self.clear()
            self.level += 1
            self.write(f"Level:{self.level}", font=FONT)
    
        def game_clear(self, info):
            self.level = 0
            pos = self.pos()
            self.goto(-100, 0)
            self.write(info, font=FONT)
            self.goto(pos)
            time.sleep(5)
    
    • 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

    五、效果展示

    在这里插入图片描述

  • 相关阅读:
    一文搞懂this指向
    2018HBCPC个人题解
    中职网络空间安全技能大赛
    第4章 R语言编程基础——数据整理与预处理
    Ansible学习笔记15
    案例丨妍丽联合神策上线 CDP,实现五大指标全面提升
    算法刷题:动态规划-背包问题学习整理
    项目管理工具的功能与帮助一览
    【深度学习】 Python 和 NumPy 系列教程(七):Python函数
    图像处理方面的笔试面试题目及回答总结整理21~40
  • 原文地址:https://blog.csdn.net/SpriteNym/article/details/126697331