arcade结合物理引擎pymunk金币弹弹弹_作者:李兴球

"""
arcade结合物理引擎pymunk金币弹弹弹_作者:李兴球
本程序用arcade模块结合pymunk模块制作很多金币下落效果,它们之间互相有碰撞。
pymunk手册:http://www.pymunk.org/en/latest/pymunk.html

"""
import random
import arcade
import pymunk
import timeit
import math
import os

SCREEN_WIDTH = 1200
SCREEN_HEIGHT = 800

class PhysicsSprite(arcade.Sprite):
    """物理角色继承自arcade.Sprite,它给角色增加pymunk_shape属性,这个属性描述物理性质"""
    def __init__(self, pymunk_shape, filename):
        super().__init__(filename, center_x=pymunk_shape.body.position.x, center_y=pymunk_shape.body.position.y)
        self.pymunk_shape = pymunk_shape


class CircleSprite(PhysicsSprite):
    def __init__(self, pymunk_shape, filename):
        super().__init__(pymunk_shape, filename)
        self.width = pymunk_shape.radius * 2
        self.height = pymunk_shape.radius * 2


class BoxSprite(PhysicsSprite):
    def __init__(self, pymunk_shape, filename, width, height):
        super().__init__(pymunk_shape, filename)
        self.width = width
        self.height = height


class MyGame(arcade.Window):
    """继承自窗口的游戏类 """

    def __init__(self, width, height):
        super().__init__(width, height,'arcade结合物理引擎pymunk金币弹弹弹_作者:李兴球') 

        arcade.set_background_color(arcade.color.DARK_SLATE_GRAY)

        self.frames_counter = 0             # 帧计数器

        #  Pymunk 重力空间
        self.space = pymunk.Space()         # 游戏的重力空间
        self.space.gravity = (0.0, -180.0)  # 设置游戏重力空间的重力参数

        # 角色列表与静态线们
        self.sprite_list = arcade.SpriteList()
        self.static_lines = []                # 做地面的 

        self.draw_time = 0                   # 每帧渲染的时间
        self.processing_time = 0             # 每帧计算处理时间 

        # 创建地面
        floor_height = 80
        body = pymunk.Body(body_type=pymunk.Body.STATIC)       # 静态刚体
        shape = pymunk.Segment(body, [0, floor_height], [SCREEN_WIDTH, floor_height], 0.0) # 这个是描述刚体属性的
        shape.friction = 0.9                                   # 摩擦系数
        shape.elasticity =   0.95                              # 弹性系数
        self.space.add(shape)                                  # 加入到重力空间
        self.static_lines.append(shape)                              
   

    def spawn(self):
        
        """产生一枚金币金币"""
        size = 45
        mass = 1
        radius = 10
        inertia = pymunk.moment_for_circle(mass, 0, radius, (0, 0))       # 惯性
        body = pymunk.Body(mass, inertia)
        body.position = pymunk.Vec2d(SCREEN_WIDTH//2,SCREEN_HEIGHT//2)
        
        direction =  random.randint(-3000,3000),random.randint(13000,15000) # 力的方向    
        body.force = direction                                            # 给力    
        
        shape = pymunk.Circle(body, radius, pymunk.Vec2d(0, 0))           # 描述刚体属性的,也是个抽像的概念 
        shape.friction = 0.3                                              # 摩擦系数        
        shape.elasticity =   0.95                                         # 弹性系数
        self.space.add(body, shape) 

        sprite = CircleSprite(shape, "coin_01.png")  # 包装成用arcade角色渲染
        self.sprite_list.append(sprite)


    def on_draw(self):
        """        渲染屏幕.        """        
        arcade.start_render()

        # 记录此帧开始渲染时间
        draw_start_time = timeit.default_timer()

        # 画所有的角色
        self.sprite_list.draw()

        # 画地板
        for line in self.static_lines:
            body = line.body
            pv1 = body.position + line.a.rotated(body.angle)
            pv2 = body.position + line.b.rotated(body.angle)
            arcade.draw_line(pv1.x, pv1.y, pv2.x, pv2.y, arcade.color.WHITE, 2)

        # 显示时间
        output = f"处理时间: {self.processing_time:.3f}"
        arcade.draw_text(output, 20, SCREEN_HEIGHT - 20, arcade.color.WHITE, 12,font_name='simkai')

        output = f"渲染时间: {self.draw_time:.3f}"
        arcade.draw_text(output, 20, SCREEN_HEIGHT - 40, arcade.color.WHITE, 12,font_name='simkai')

        self.draw_time = timeit.default_timer() - draw_start_time # 渲染此帧所用时间
 

    def update(self, delta_time):
        start_time = timeit.default_timer()
        self.frames_counter +=1
        if self.frames_counter % 20 == 0 :        self.spawn()
        # 检测每个于是否掉出屏幕
        for sprite in self.sprite_list:
            if sprite.pymunk_shape.body.position.y < 0:
                # y坐标小于0,则删除它
                self.space.remove(sprite.pymunk_shape, sprite.pymunk_shape.body)
                # 从列表中杀掉它
                sprite.kill()

        # 更新物理空间,详情见网址
        # http://www.pymunk.org/en/latest/overview.html#game-loop-moving-time-forward
        self.space.step(1 / 60.0)

        # 把每个角色的坐标和角度移到重力空间相对应的数值,而这个数值也是保存在角色的属性里。
        for sprite in self.sprite_list:
            sprite.center_x = sprite.pymunk_shape.body.position.x
            sprite.center_y = sprite.pymunk_shape.body.position.y
            sprite.angle = math.degrees(sprite.pymunk_shape.body.angle)
        
        self.processing_time = timeit.default_timer() - start_time # 每帧更新角色所花时间


def main():
    MyGame(SCREEN_WIDTH, SCREEN_HEIGHT)

    arcade.run()


if __name__ == "__main__":
    main()