Python萤火虫找女朋友__arcade迷宫解密型游戏

萤火虫找女朋友_by李兴球_arcade迷宫解密型游戏

"""
萤火虫找女朋友.py
请按上下左右方向箭头操作萤火虫去找另一只萤火虫。按W或S键
能改变它的发光强度,不过如果发光强了,可能会被癞蛤蟆发现,
所以要注意有时候光度不能太强!在迷宫还有陷阱,有钻石可拾取,可是它的女朋友在哪里呢?


本游戏主要用arcade模块实现,用turtle模块实现开始界面。


"""

import random
import arcade


SPRITE_SCALING = 1
SCREEN_WIDTH = 800
SCREEN_HEIGHT = 600
SPRITE_PIXEL_SIZE = 64
GAME_NAME = "萤火虫找女朋友_by李兴球_arcade迷宫解密型游戏"
# 距离屏幕边距的最小距离 

VIEWPORT_MARGIN = 40
MOVEMENT_SPEED = 5

class MyGame(arcade.Window):
    """主应用程序类. """

    def __init__(self, width, height,title):
        """
        初始化器
        """
        super().__init__(width, height,title)

        self.game_over = False

        # 角色列表
        
        self.toad_list = None
        self.diamond_list = None
        self.trap_list = None       

        # 设置游戏及玩家相关变量
        self.score = 0
        self.player_sprite = None     # 雄性萤火虫 (玩家)
        self.femail_firefly = None    # 雌性萤火虫
        self.wall_list = None
        self.physics_engine = None
        self.view_bottom = 0
        self.view_left = 0

    def setup(self):
        """ 实例化变量 """
        
        self.found_girl_friend = False

        # 地图块角色列表
        self.wall_list = arcade.SpriteList()

        # 设置蒙板       
        self.mask = arcade.Sprite("images/mask.png")
        self.mask.scale = 0.6


        # 实例化雌性萤火虫
        self.femail_firefly = arcade.Sprite("images/femail_firefly.png")
        self.femail_firefly.center_x = SCREEN_WIDTH + SPRITE_PIXEL_SIZE*5
        self.femail_firefly.center_y = SCREEN_HEIGHT - SPRITE_PIXEL_SIZE*5
        self.femail_firefly.visible = False       # 自定义属性,可见性
        
        # 实例化玩家操作的角色
        self.score = 0
        self.player_sprite = arcade.Sprite("images/firefly_right.png")
        self.player_sprite.textures.append(arcade.load_texture("images/firefly_left.png"))
        self.player_sprite.center_x = 128
        self.player_sprite.center_y = 270
        self.player_sprite.status = "alive"
        

        # 下面是加载地图        
        my_map = arcade.read_tiled_map(f"bigroom_1.tmx", SPRITE_SCALING)
        
        # 读取不可移动的平台数据阵列'ground'是一图层的名称
        map_array = my_map.layers_int_data['ground']        
          
        # 从墙生成地图列表
        self.wall_list = arcade.generate_sprites(my_map, 'ground', SPRITE_SCALING)
        self.wall_list.move(SPRITE_PIXEL_SIZE ,0)   # 水平方向和垂直方向移动
        
        # 加载简单型的物理引擎,简单的理解为让玩家和墙发生碰撞的封装好了的对象
        self.physics_engine = arcade.PhysicsEngineSimple(self.player_sprite,self.wall_list)
 
        
        # 生成地图中可拾取的diamond角色列表
        self.diamond_list = arcade.generate_sprites(my_map, 'picked', SPRITE_SCALING)
        self.diamond_list.move(SPRITE_PIXEL_SIZE ,0)
        
        # trap角色列表,陷阱
        self.trap_list = arcade.generate_sprites(my_map, 'trap', SPRITE_SCALING)
        self.trap_list.move(SPRITE_PIXEL_SIZE ,0)
        
        # toad角色列表,籁蛤蟆
        self.toad_list = arcade.generate_sprites(my_map, 'toad', SPRITE_SCALING)
        
        self.toad_list.move(SPRITE_PIXEL_SIZE ,0)       

        self.physics_engine = arcade.PhysicsEngineSimple(self.player_sprite, self.wall_list)

        # 设置背景颜色
        arcade.set_background_color(arcade.color.AMAZON)

        # 设置视口边界
        self.view_left = 0
        self.view_bottom = 0

    def detect_collision_radius_with_toads(self):
        """检测和每个癞蛤蟆的距离,蒙板越大,萤火虫越容易死"""
 
        for toad in self.toad_list:
            d = arcade.get_distance_between_sprites(self.player_sprite,toad)
            if d <  SPRITE_PIXEL_SIZE * self.mask.scale * 2 :
                self.player_sprite.status = "dead"
                print("游戏失败结束,画一个Game Over。")
                self.game_over = True  

    def on_draw(self):
        """
        渲染屏幕
        """

        # 开始渲染
        arcade.start_render()

        # 画各个角色
        self.wall_list.draw()
        self.diamond_list.draw()
        self.trap_list.draw()
        self.toad_list.draw()
        if  self.femail_firefly.visible: self.femail_firefly.draw()
        self.mask.draw()
        
        if self.player_sprite.status == "alive":
            self.player_sprite.draw()
            
        if self.game_over :
            x = self.view_left + SCREEN_WIDTH//2 -200
            y = self.view_bottom + SCREEN_HEIGHT//2
            if self.found_girl_friend:
                string = "恭喜,游戏成功结束!"
            else:
                string = "被蛤蟆看见,它伸出舌头把萤火虫吃了 !"
            arcade.draw_text(string,x,y, arcade.color.GREEN,24,font_name="simhei")                

    def on_key_press(self, key, modifiers):
        """当按键时调用此方法 """
        if  self.game_over :return
        if key == arcade.key.UP:
            self.player_sprite.change_y = MOVEMENT_SPEED
        elif key == arcade.key.DOWN:
            self.player_sprite.change_y = -MOVEMENT_SPEED
        elif key == arcade.key.LEFT:
            self.player_sprite.set_texture(1)
            self.player_sprite.change_x = -MOVEMENT_SPEED
        elif key == arcade.key.RIGHT:
            self.player_sprite.set_texture(0)
            self.player_sprite.change_x = MOVEMENT_SPEED
        elif key == arcade.key.W:
            if self.mask.scale < 1.2:
                self.mask.scale += 0.1
                 
        elif key == arcade.key.S:
            if self.mask.scale > 0.4:
                self.mask.scale -= 0.1
                

    def on_key_release(self, key, modifiers):
        """当松开按键时调用此方法 """
        
        if  self.game_over :return
        if key == arcade.key.UP or key == arcade.key.DOWN:
            self.player_sprite.change_y = 0
        elif key == arcade.key.LEFT or key == arcade.key.RIGHT:
            self.player_sprite.change_x = 0

    def update(self, delta_time):
        """ 游戏逻辑设定,结果都是更新坐标/角度,删除/添加角色等。"""

        if self.game_over == True :return
        # 调用物理引擎
        self.physics_engine.update()

        # 蒙板跟随玩家角色
        self.mask.center_x = self.player_sprite.center_x
        self.mask.center_y = self.player_sprite.center_y

        # 玩家与diamond的碰撞检测,返回列表
        if len(self.diamond_list) > 0:
            hits = arcade.check_for_collision_with_list(self.player_sprite, self.diamond_list)
            for dx in hits: dx.kill()
            if len(self.diamond_list) == 0 : self.femail_firefly.visible = True            
        
        # 玩家与陷坑的碰撞检测,返回列表  
        hits = arcade.check_for_collision_with_list(self.player_sprite, self.trap_list)
        if hits:
            self.player_sprite.status = "dead"                           
            print("游戏失败结束,画一个Game Over。")
            self.game_over = True       
            
        
        # 玩家与toad癞蛤蟆的碰撞检测,根据蒙板大小设定
        self.detect_collision_radius_with_toads()
        
        # 如果雌性萤火虫可见了,则与它进行碰撞检测
        if  self.femail_firefly.visible:
           hits = arcade.check_for_collision(self.player_sprite, self.femail_firefly)
           if hits:
               self.found_girl_friend = True               
               print("游戏成功结束。")
               self.game_over = True      
             


        # --- 管理滚动
        changed = False

        # 左滚动
        left_bndry = self.view_left + VIEWPORT_MARGIN
        if self.player_sprite.left < left_bndry:
            self.view_left -= left_bndry - self.player_sprite.left
            changed = True

        # 右滚动
        right_bndry = self.view_left + SCREEN_WIDTH - VIEWPORT_MARGIN
        if self.player_sprite.right > right_bndry:
            self.view_left += self.player_sprite.right - right_bndry
            changed = True

        # 上滚动
        top_bndry = self.view_bottom + SCREEN_HEIGHT - VIEWPORT_MARGIN
        if self.player_sprite.top > top_bndry:
            self.view_bottom += self.player_sprite.top - top_bndry
            changed = True

        # 下滚动
        bottom_bndry = self.view_bottom + VIEWPORT_MARGIN
        if self.player_sprite.bottom < bottom_bndry:
            self.view_bottom -= bottom_bndry - self.player_sprite.bottom
            changed = True

        if changed:
            arcade.set_viewport(self.view_left,
                                SCREEN_WIDTH + self.view_left,
                                self.view_bottom,
                                SCREEN_HEIGHT + self.view_bottom)

def show_game_UI():
    
    import turtle
    screen = turtle.getscreen()
    screen.title(GAME_NAME)
    screen.setup(610,610)
    screen.bgpic("images/bg.png")
    screen.onkeypress(lambda:screen.bye(),"space")
    screen.onclick(lambda x,y:screen.bye())
    screen.listen()
    screen.mainloop()


    
    
def main():
    """ 主要方法"""

    show_game_UI()
    
    window = MyGame(SCREEN_WIDTH, SCREEN_HEIGHT,GAME_NAME)
    window.setup()
    arcade.run()

if __name__ == "__main__":
    main()