• 小学生python游戏编程arcade----可旋转炮台的坦克


    前言

    接上篇文章继续解绍arcade游戏编程的基本知识。

    带炮台的坦克

    1、可旋转炮台的坦克实现

    1.1坦克由两部分组成

    在这里插入图片描述

    1.2 组装坦克
        # 组装坦克
        self.tank = arcade.Sprite(TANK_BODY,image_x=0,image_y=0,image_width=132,image_height=243,scale=1)
        self.tank.position = SCREEN_MIDDLE
    
        self.barrel = RotatingSprite(TANK_BARREL, image_x=150,image_y=43,image_width=86,image_height=200,scale=1)
        self.barrel.position =\
            SCREEN_MIDDLE[0], SCREEN_MIDDLE[1] - TANK_panli
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    1.3 效果图

    在这里插入图片描述
    炮台随鼠标可以转动
    在这里插入图片描述
    围绕点的精灵旋转,带炮台的坦克,游戏通常包括朝向目标旋转的元素。常见的例如,车辆和塔楼上的炮塔。在2D游戏中,这些旋转部件通常被实现为移动的精灵相对于他们所依附的任何东西。
    这有一个问题:你必须围绕它们的附着点而不是精灵的中心。否则旋转看起来不对!为了说明区别,本例使用了一个可控制的播放器有一个跟在鼠标后面的坦克。
    1.正确,枪管后部紧靠坦克中心
    2.错误的是,围绕枪管中心,将其固定在坦克上

    1.4 代码实现
    import arcade
    import math
    
    
    TANK_SPEED_PIXELS = 64  # 坦克每秒移动多少像素
    TANK_TURN_SPEED_DEGREES = 70  # 坦克车身转动的速度
    
    
    # 这是炮台精灵旋转中心位置与坦克中心的偏离差。
    # 我们使用它来确保炮台的后部位于坦克的中间
    TANK_panli = 40
    
    
    SCREEN_WIDTH = 800
    SCREEN_HEIGHT = 600
    SCREEN_MIDDLE = (SCREEN_WIDTH // 2, SCREEN_HEIGHT // 2)
    
    
    SCREEN_TITLE = "上下旋转的坦克"
    
    
    # These paths are built-in resources included with arcade
    TANK_BODY = "images/坦克1.png"
    TANK_BARREL = "images/坦克1.png"
    
    
    class RotatingSprite(arcade.Sprite):
        """
        可以围绕一个点旋转的精灵子类。这个版本的类总是改变精灵的角度。
        其他游戏可能不会旋转精灵。例如,移动平台成型机中的平台不会旋转。
        """
        def rotate_around_point(self, point: arcade.Point, degrees: float):
    
            # 使精灵在其位置移动时旋转
            self.angle += degrees
    
            # 沿着以传递点为中心的圆移动精灵
            self.position = arcade.rotate_point(
                self.center_x, self.center_y,
                point[0], point[1], degrees)
    
    
    class ExampleWindow(arcade.Window):
    
        def __init__(self):
            super().__init__(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_TITLE)
    
            # 设置背景色
            self.background_color = arcade.csscolor.SEA_GREEN
    
            # 组装坦克
            self.tank = arcade.Sprite(TANK_BODY,image_x=0,image_y=0,image_width=132,image_height=243,scale=1)
            self.tank.position = SCREEN_MIDDLE
    
            self.barrel = RotatingSprite(TANK_BARREL, image_x=150,image_y=43,image_width=86,image_height=200,scale=1)
            self.barrel.position =\
                SCREEN_MIDDLE[0], SCREEN_MIDDLE[1] - TANK_panli
    
            self.tank_direction = 0.0  # # 前进和后退油门
            self.tank_turning = 0.0  # 向左或向右转的力度
    
            self.mouse_pos = 0, 0
    
            self.tank_sprite_list = arcade.SpriteList()
            self.tank_sprite_list.extend([self.tank, self.barrel])
    
            self.control_text = arcade.Text(
                "WASD 键移动坦克, 鼠标移动炮台指向",
                SCREEN_MIDDLE[0], 15,
                anchor_x='center')
    
        def on_draw(self):
            self.clear()
            self.tank_sprite_list.draw()
    
            self.control_text.draw()
    
    
        def on_update(self, delta_time: float):
            self.move_tank(delta_time)
    
        def move_tank(self, delta_time):
    
            # 在不改变位置的情况下将罐体旋转到位,我们将在更新整个坦克的x轴和y轴后旋转枪管
            self.tank.angle += TANK_TURN_SPEED_DEGREES\
                * self.tank_turning * delta_time
    
            #计算应向前或向后移动多少
            move_magnitude = self.tank_direction * TANK_SPEED_PIXELS * delta_time
            x_dir = math.cos(self.tank.radians - math.pi / 2) * move_magnitude
            y_dir = math.sin(self.tank.radians - math.pi / 2) * move_magnitude
    
            # 移动坦克底盘
            self.tank.position =\
                self.tank.center_x + x_dir,\
                self.tank.center_y + y_dir
    
            #移动炮台
            self.barrel.position =\
                self.barrel.center_x + x_dir,\
                self.barrel.center_y + y_dir
    
            # 计算坦克与鼠标的角度
            mouse_angle = arcade.get_angle_degrees(
                self.tank.center_y, self.tank.center_x,
                self.mouse_pos[1], self.mouse_pos[0])
    
            # 补偿原始图片的垂直方向,如果图片朝右,则可以跳过此操作
            mouse_angle += 90
    
            angle_change = mouse_angle - self.barrel.angle
    
            self.barrel.rotate_around_point(self.tank.position, angle_change)
    
        def on_key_press(self, symbol: int, modifiers: int):
            if symbol == arcade.key.W:
                self.tank_direction += 1
            elif symbol == arcade.key.S:
                self.tank_direction -= 1
            elif symbol == arcade.key.A:
                self.tank_turning += 1
            elif symbol == arcade.key.D:
                self.tank_turning -= 1
            elif symbol == arcade.key.P:
                pass
    
        def on_key_release(self, symbol: int, modifiers: int):
            if symbol == arcade.key.W:
                self.tank_direction -= 1
            elif symbol == arcade.key.S:
                self.tank_direction += 1
            elif symbol == arcade.key.A:
                self.tank_turning -= 1
            elif symbol == arcade.key.D:
                self.tank_turning += 1
    
        def on_mouse_motion(self, x: int, y: int, dx: int, dy: int):
            self.mouse_pos = x, y
    
    def main():
        window = ExampleWindow()
        window.run()
    
    
    if __name__ == '__main__':
        main()
    
    
    • 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

    2、以上示例改为类,便于集成游戏中

    2.1 常量 存于seting文件中

    坦克属性
    TANK_body = “images/坦克1.png”
    TANK_barrel = “images/坦克1.png”
    TANK_pos = (SCREEN_width// 2, SCREEN_height // 2)
    TANK_pianli = 15
    TANK_speed_pixels = 64 #坦克每秒移动多少像素
    TANK_turn_speed_degrees = 70 #坦克车身转动的速度

    2.2 坦克类

    from arcadegame.seting import *
    import arcade
    import math

    class RotatingSprite(arcade.Sprite):
    “”" 可以围绕一个点旋转的精灵子类。 “”"
    def rotate_around_point(self, point: arcade.Point, degrees: float):
    # 使精灵在其位置移动时旋转
    self.angle += degrees

        # 沿着以传递点为中心的圆移动精灵
        self.position = arcade.rotate_point(
            self.center_x, self.center_y,
            point[0], point[1], degrees)
    
    • 1
    • 2
    • 3
    • 4

    class Tanke(RotatingSprite):
    def init(self):
    super().init()
    # The tank and barrel sprite
    self.tank = arcade.Sprite(TANK_body,image_x=0,image_y=0,image_width=132,image_height=243,scale=0.5)
    self.tank.position = TANK_pos

        self.barrel = RotatingSprite(TANK_barrel, image_x=150,image_y=0,image_width=89,image_height=243,scale=0.5)
        self.barrel.position =\
            TANK_pos[0], TANK_pos[1] - TANK_pianli
    
    def move_tank(self, delta_time,tank_turning,tank_direction,mouse_pos):
        # 在不改变位置的情况下将罐体旋转到位,我们将在更新整个坦克的x轴和y轴后旋转枪管
        self.tank.angle += TANK_turn_speed_degrees\
            * tank_turning * delta_time
    
        #计算应向前或向后移动多少
        move_magnitude = tank_direction * TANK_speed_pixels * delta_time
        x_dir = math.cos(self.tank.radians - math.pi / 2) * move_magnitude
        y_dir = math.sin(self.tank.radians - math.pi / 2) * move_magnitude
    
        # 移动坦克底盘
        self.tank.position =\
            self.tank.center_x + x_dir,\
            self.tank.center_y + y_dir
    
        #移动炮台
        self.barrel.position =self.barrel.center_x + x_dir, self.barrel.center_y + y_dir
    
        # 计算坦克与鼠标的角度
        mouse_angle = arcade.get_angle_degrees(
            self.tank.center_y, self.tank.center_x,
            mouse_pos[1], mouse_pos[0])
    
        # 补偿炮台的垂直方向如果朝右,则可以跳过此操作
        mouse_angle += 90
    
        angle_change = mouse_angle - self.barrel.angle
    
        self.barrel.rotate_around_point(self.tank.position, angle_change)
    
    • 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
    2.3 Tank类的使用效果图

    在这里插入图片描述

    2.4 代码实现
    """
    围绕点的精灵旋转,带坦克
    游戏通常包括朝向目标旋转的元素。常见的例如,车辆和塔楼上的炮塔。在2D游戏中,
    这些旋转部件通常被实现为移动的精灵相对于他们所依附的任何东西。
    这有一个问题:你必须围绕它们的附着点而不是精灵的中心。否则旋转看起来不对!
    为了说明区别,本例使用了一个可控制的播放器
    有一个跟在鼠标后面的坦克。您可以按P切换
    在两种旋转的方式之间:
    1.正确,枪管后部紧靠坦克中心
    2.错误的是,围绕枪管中心,将其固定在坦克上
    """
    
    from arcadegame.tank import *
    
    SCREEN_WIDTH = 800
    SCREEN_HEIGHT = 600
    SCREEN_MIDDLE = (SCREEN_WIDTH // 2, SCREEN_HEIGHT // 2)
    
    SCREEN_TITLE = "上下旋转的坦克"
    
    
    class ExampleWindow(arcade.Window):
    
        def __init__(self):
            super().__init__(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_TITLE)
    
            # Set Background to be green
            self.background_color = arcade.csscolor.SEA_GREEN
    
            self.tk = None
            self.tank_direction = 0.0  # # 前进和后退油门
            self.tank_turning = 0.0  # 向左或向右转的力度
            self.mouse_pos=0,0
            self.scene = None
            self.control_text = arcade.Text(
                "WASD 键移动坦克, 鼠标移动炮台指向",
                SCREEN_MIDDLE[0], 15,
                anchor_x='center')
    
        def setup(self):
            # 坦克
            self.tk = Tanke()
            # self.tank_sprite_list = arcade.SpriteList()
            # self.tank_sprite_list.extend([self.tk.tank, self.tk.barrel])
            # 初始化场景
            map_name = f"地图\家2.json"  # jia{self.level}.json"
            # 层属性
            layer_options = {
                LAYER_platforms: {
                    "use_spatial_hash": True,
                },
                LAYER_tree: {
                    "use_spatial_hash": False,
                },
                'fz': {
                    "use_spatial_hash": True,
                },
                # 'tizi': {
                #     "use_spatial_hash": True,
                # },
                'Enemies': {
                    "use_spatial_hash": True,
                },
            }
    
            # 读地图文件
            self.tile_map = arcade.load_tilemap(map_name, TILE_Scaling, layer_options)
             # 使用我们的TileMap初始化场景,这将自动添加所有层,以正确的顺序在场景中显示为SpriteList。
            self.scene = arcade.Scene.from_tilemap(self.tile_map)
    
            self.scene.add_sprite("tanke", self.tk.tank)
            self.scene.add_sprite("tanke", self.tk.barrel)
    
    
        def on_draw(self):
            self.clear()
            # self.tank_sprite_list.draw()
            self.scene.draw()
            self.control_text.draw()
    
        def on_update(self, delta_time: float):
            self.tk.move_tank(delta_time,self.tank_turning,self.tank_direction,self.mouse_pos)
    
        def on_key_press(self, symbol: int, modifiers: int):
            if symbol == arcade.key.W:
                self.tank_direction += 1
            elif symbol == arcade.key.S:
                self.tank_direction -= 1
            elif symbol == arcade.key.A:
                self.tank_turning += 1
            elif symbol == arcade.key.D:
                self.tank_turning -= 1
            elif symbol == arcade.key.P:
                pass
    
        def on_key_release(self, symbol: int, modifiers: int):
            if symbol == arcade.key.W:
                self.tank_direction -= 1
            elif symbol == arcade.key.S:
                self.tank_direction += 1
            elif symbol == arcade.key.A:
                self.tank_turning -= 1
            elif symbol == arcade.key.D:
                self.tank_turning += 1
    
        def on_mouse_motion(self, x: int, y: int, dx: int, dy: int):
            self.mouse_pos = x, y
    
    def main():
        window = ExampleWindow()
        window.setup()
        window.run()
    
    
    if __name__ == '__main__':
        main()
    
    
    • 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

    源码获取

    关注博主后,私聊博主免费获取
    需要技术指导,育娃新思考,企业软件合作等更多服务请联系博主

    今天是以此模板持续更新此育儿专栏的第 17/50次。
    可以关注我,点赞我、评论我、收藏我啦。

  • 相关阅读:
    windows编程之处理矩形
    Sky Computing
    无代码开发数据导入入门教程
    spring 获取ioc容器,从容器中获取bean
    档案信息化咨询方法论实践要点有哪些?
    【MySQL】表的内连和外连
    ASP.NET Core 6框架揭秘实例演示[21]:如何承载你的后台服务
    linux下自动构建工具make:makefile
    计算机毕业设计 基于SpringBoot产业园区智慧公寓管理系统的设计与实现 Javaweb项目 Java实战项目 前后端分离 文档报告 代码讲解 安装调试
    【前端优化 & Vue项目优化】 如何避免浏览器卡顿,实现性能优化cdn?
  • 原文地址:https://blog.csdn.net/fqfq123456/article/details/127836832