IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Python知识库 -> Python基础:第012课——最小的程序框架(代码解析) -> 正文阅读

[Python知识库]Python基础:第012课——最小的程序框架(代码解析)

Python基础:第012课——最小的程序框架(代码解析)

观看视频

参考:pygame详细教程
参考案例:游戏模块
Pygame 作为一个入门级的游戏开发库,其实并不难学,只要掌握 Python 编程的相关知识就能很轻松地掌握它。

Pygame 语法简单、明了,秉持了 Python 语言一贯的风格。同时,它作为一个游戏开发库来说,具有图形编程的基本特点,如果您对于图形编程从未了解过,即使您有 Python 编程基础,也会略感迷茫。因此,在接下来的学习中会详细介绍 Pygame 的常用模块,以及图形编程中的相关概念,帮助您快速掌握 Pygame 的使用。

屏幕坐标系

在这里插入图片描述

#导入所需的模块
import pygame, sys

# 使用pygame之前必须初始化
pygame.init()

# 设置主屏窗口
screen = pygame.display.set_mode((600,400))

# 设置窗口的标题,即游戏名称
pygame.display.set_caption("小小工坊")

# 加载图像,存储在ball变量中,ball是一个图像对象
ball = pygame.image.load('pygame/images/ball.gif')

#获得显示对象的rect区域坐标
ball_rect = ball.get_rect()
# 设置显示对象居中
ball_rect.center = (300, 200)
# 将准备好的图像绘制到主屏幕 Screen 上。
screen.blit(ball, ball_rect)

# 建立时钟对象
fclock = pygame.time.Clock()

# 固定代码段,实现点击关闭按钮退出游戏的功能,几乎所有的pygame都会使用该段代码
while True :
		# 循环获取事件,监听事件状态
	    for event in pygame.event.get():
		    	# 判断用户是否点了"X"关闭按钮,并执行if代码段
		        if event.type == pygame.QUIT:
			            #卸载所有模块
			            pygame.quit()
			            #终止程序,确保退出程序
			            sys.exit()
	    ball_rect = ball_rect.move(speed,speed)
	    screen.fill((0,0,0))
	    screen.blit(ball,ball_rect)
		
		#更新屏幕内容
	    pygame.display.update()
	    fclock.tick(60)

12. 代码解析

Python:pygame包的详细使用方法

12.1 游戏的初始化和退出

# 使用pygame之前必须初始化
pygame.init()
  • 要使用pygame提供的所有功能之前,需要调用init 方法,它的作用是自动检测 Pygame 软件包是否正常可用,并检查电脑的硬件调用接口、基础功能是否存在问题,比如音频、光驱、声卡驱动等设备。同时,它会完成 Pygame 中所有模块的初始化操作,比如 display(显示模块)、font(字体模块)、mixer(声音控制模块)、cursors(光标控制模块)等。

  • 在游戏结束前需要调用一下quit方法

12.1.1 方法说明

pygame.init() 导入并初始化所有pygame模块,使用其他模块前,必须先调用iinit方法
pygame.quit() 卸载所有pygame模块,在游戏结束之前调用

12.2 Surface对象

12.2.1 坐标系

  • 原点在左上角 (0,0)
  • x轴水平方向向右,逐渐增加
  • y轴垂直方向向下,逐渐增加

如图:
在这里插入图片描述

  • 在游戏中,所有可见的元素都是以矩形区域来描述位置的
  • 要描述一个矩形区域有四个要素: (x, y) (width, height)

(x,y)是物体坐标,(width, height)是物体像素大小

  • pygame 专门提供了一个类pygame.Rect 用于描述矩形区域

x, y
left,top,bottom,right
center,centerx,centery
size,width,height

12.2.2 如何创建Surface对象

那么我们应该如何创建 Surface 对象呢?Pygame 提供了多种创建 Surface 对象的方法,这里先介绍以下几种方法。

上述示例,使用如下方式创建了一个 surface 对象:

#也叫screen对象,本质上是一个Surface,大小400*400
screen = pygame.display.set_mode((400,400))

screen 的本质上就是一个 Surface 对象,它是游戏的主窗口,也就是整个游戏中尺寸最大的“纸”,任何其他的 Surface 对象都需要附着在这张最大的“纸”上,比如创建一个图像的 Surface 对象,通过以下方法将它绘制在主屏幕上:

# 加载图像,存储在ball变量中,ball是一个图像对象
ball = pygame.image.load('pygame/images/ball.gif')

#获得显示对象的rect区域坐标
ball_rect = ball.get_rect()
# 设置显示对象居中
ball_rect.center = (300, 200)
# 将准备好的图像绘制到主屏幕 Screen 上。
screen.blit(ball, ball_rect)

比如创建一个包含文本的 Surface 对象,通过以下方法将它绘制在主屏幕上:

# 引入字体类型
f = pygame.font.Font('C:/Windows/Fonts/simhei.ttf',50)

#创建一个包含文字的Surface对象
# 生成文本信息,第一个参数文本内容;第二个参数,字体是否平滑;
# 第三个参数,RGB模式的字体颜色;第四个参数,RGB模式字体背景颜色;
text = f.render("小小工坊",True,(255,0,0),(0,0,0))

textRect =text.get_rect()

#通过blit方法将其绘制在主屏幕上,这里的textRect表示位置坐标
screen.blit(text,textRect)
set_mode()方法

set_ mode( resolution=(0,0),flags=0, depth=0) -> Surface(名字随意)

  • 作用:创建游戏显示窗口
  • 参数
    • resolution 指定屏幕的宽和高,默认创建的窗口大小和屏幕大小一致
    • flags参数指定屏幕的附加选项,例如是否全屏等等,默认不需要传递
    • depth参数表示颜色的位数,默认自动匹配
  • 返回值:Surface对象
    Surface对象是内存中的屏幕数据对象,可以理解为游戏的屏幕,游戏的元素都需要被绘制到游戏的屏幕上
    1. 在开发时,可能会需要使用固定的数值,例如屏幕的高度是700
    2. 这个时候,建议不要直接使用固定数值,而应该使用常量
    3. 当实验需求发生变化时,只需要修改常量的值就可,不需要在一个一个去找数值更改

常量的命名方式:

所有字母都使用大写,单词与单词之间使用下划线连接

12.2.3 *Rect对象

pygame.Rect是一个比较特殊的类,内部只是封装了一些数字计算

实例:

import pygame
hero = pygame.Rect(100,200,50,120)
print("英雄的x,y坐标分别是 %d, %d" % (hero.x, hero.y))
print("英雄的宽高分别是:%d,%d" % (hero.width, hero.height))
# Rect中的size属性是一个元组(宽,高)
print("英雄的宽高分别是:%d,%d" % hero.size))
# Rect中的bottom属性表示底部的纵坐标 y+height,top属性表示元素顶部纵坐标y
print("英雄的底部y坐标为:%d,顶部y坐标为:%d" % (hero.bottom, hero.top))
# Rect的right属性表示元素右边横坐标 x+width, left表示元素横坐标x
print("英雄的最右边x坐标为%d,最左边x坐标为:%d" % (hero.right, hero.left))
# Rect的center属性是一个元组(centerx,centery)
print("英雄的中心点坐标为:%d,%d" % hero.center)

12.3 图像绘制

那么要在创建的窗口中按照指定要求显示图片,则需要三个步骤:

1. 使用`pygame.image.load()`加载图像的数据
2. 使用游戏屏幕对象,调用`blit`方法将图像绘制到指定位置
3. 调用`pygame.display.update()`方法更新整个屏幕的显示
*
*
*
*
load
-File 图像文件
blit
-image 图像对象
+tuple 位置
update
-screen update

注:如果不调用pygame.display.update()方法,则运行程序后图片并不会显示出来,在所有图像绘制完成后可放在最后统一更新

12.4 事件监听

游戏,在我们日常生活中经常接触到,无论是手游、还是电脑端游戏,已经成了信息社会中,不可或缺的一部分。

游戏大致来讲是由动画和人机交互的体验两部分构成,其中动画则是由一系列连续静止的图片,经过一定频率的刷新构成的,这个频率被称为 FPS,如果频率值越大则画面越流畅;如果频率值越小则画面会出现卡顿的感,在游戏过程中一般人能接受的最低 FPS 约为 30Hz,如果想要画面流畅则 FPS 要大于 60 Hz。

FPS 越高,细节越好,体验也越好,但是文件容量也越高

动画保证了玩家的视觉体验,而人机交互则是操作上的体验。通过移动和点击鼠标、按下键盘上的技能键,或是滑动手机屏幕等操作来实现人机交互,这些与游戏程序交互的操作被称为事件(Event)。

Pygame 作为一个游戏开发库,同样具有设置和监听事件的功能。它提供了一个 event 事件模块,这个模块中包含了所有常用到游戏事件。下面是退出游戏的代码示例(其他事件类型,后续会做介绍):

# 循环获取事件,监听事件状态,使用get()获取事件
for event in pygame.event.get():
	# 判断事件类型,用户是否点了"X"关闭按钮    
	# pygame.QUIT 指点击右上角窗口的"X"号
    if event.type == pygame.QUIT:
    	#点击后,卸载所有pygame模块
        pygame.quit()

12.5 游戏循环

当打我们游戏时可能会触发游戏中的各种事件,比如鼠标事件、键盘按键事件、摄像拍照事件等等,因此游戏程序需要一直循环监听玩家的操作,只有当用户点击了游戏“关闭”按钮时,监听才会结束。如果想要达到“循环监听”目的,此时就需要设置一个游戏循环(Game Loop)也称为游戏的主循环,这样才能保证人机交互的体验感。代码示例如下:

#游戏主循环(游戏循环)
while True:
		# 循环获取事件,监听事件
    	for event in pygame.event.get():
    		# 判断用户是否点了关闭按钮
	        if event.type == pygame.QUIT:
	        	# 当用户关闭游戏窗口时执行以下操作
	            # 这里必须调用quit()方法,退出游戏
	            pygame.quit()
	            #终止系统
	            sys.exit()
		#更新并绘制屏幕内容
		pygame.display.flip() 

游戏主循环是每个 Pygame 游戏程序中必不可少的一部分,它主要承担着以下三个重要任务:

  • 处理游戏事件
  • 更新游戏状态
  • 把更新后的游戏状态绘制到屏幕上

pygame程序
图2:主循环示意图

游戏画面和游戏操作状态会因为动画效果和玩家的操作而改变,因此需要以循环的方式实时地更新主屏幕(screen)的显示内容。把下列代码放入游戏主循环中即可实现实时更新和绘制屏幕内容,如下所示:

#刷新界面显示
pygame.display.flip() 

除了上述方法外,Pygame 还提供了另一个方法。如下所示:

pygame.display.update() 

这两个方法的主要区别是:后者可以根据选定的区域来更新部分内容,而前者则是更新整个待显示的内容。如果后者没有提供区域位置参数时,其作用和 display.flip() 相同。

12.6 关于动画实现的原理

跟电影的原理类似,游戏中的动画效果,本质上是快速的在屏幕上绘制图像,电影是将多张静止的电影胶片连续、快速的播放,产生连贯的视觉效果!

一般在电脑上每秒绘制60次,就能够达到非常连续高品质的动画效果,每次绘制的结果被称为帧Frame

在每次调用pygame.display.update()方法产生的结果为一帧,也就是说需要每秒钟调用60次pygame.display.update()方法,就可以达到高品质动画效果

如何实现每秒60帧?
pygame专门提供了一个类pygame.time.Clock 可以非常方便的设置屏幕绘制速度- -刷新帧率

要使用时钟对象需要两步:

  1. 在游戏初始化创建一个时钟对象
  2. 在游戏循环中让时钟对象调用tick(帧率) 方法,tick 方法会根据.上次被调用的时间, 自动设置游戏循环中的延时

实现方法:

# 创建时钟对象

clock = pygame.time.Clock()

while True:
	# 在游戏循环内部调用tick方法,里面传入想要的帧数
?	clock.tick(60)

动画实现案例:飞机向上飞行
例 :

    import pygame
    
    pygame.init()
    
    # 创建游戏窗口
    
    screen = pygame.display.set_mode((480,700))
    
    # 加载游戏中需要的图像
    
    background = pygame.image.load("./pygame/images/xx.jpg")
    plane = pygame.image.load("./pygame/images/xxx.jpg)
    
    # 将图像显示到游戏初始化的位置
    
    screen.blit(background, (0, 0))
    screen.blit(plane, (120, 500))
    
    # 定义飞机显示的矩形区域
    
    plane_Rect = pygame.Rect(120, 500, 120, 90)
    
    # 创建时钟对象
    
    clock = pygame.time.Clock()
    while True:
        # 定义每秒60帧
        clock.tick(60)
        # 移动飞机显示矩形区域的位置
        plane_Rect.y = plane_Rect.y -5
    
        # 重绘背景图像,避免出现残影
        screen.blit(background, (0, 0))
    
        # 重新绘制图像
        screen.blit(plane, place_Rect)
    
        # 更新屏幕
        pygame.display.update()
    pygame.quit()

12.7 针对键盘按键捕获的两种方式

●第一种方式判断event.type == pygame.KEYDOWN

实现代码:

if event.type == pygame. KEYDOWN and event.key == pygame.K RIGHT:
	print("向右移动...")

●第二种方式(按住方向键不放可持续移动)

  1. 首先使用pygame. key.get_ pressed()返回所有按键元组
  2. 通过键盘常量,判断元组中某一个键是否被按下——如果被按下,对应数值为1

实现代码:

变量 = pygame.key.get_pressed()
if 变量[pygame.K_RIGHT]:
	print("向右移动")

● 两种方式的区别

第一种方式 event.type 用户必须抬起按键才算一次按键事件(利用列表也可实现持续向某一方向移动,具体见)
第二种方式 用户可按键不放,能够实现持续向某一个方向移动

*12.8 pygame中提供的高级类精灵和精灵组

图像加载、位置变化、绘制图像都需要程序员编写代码分别处理,为了简化代码,避免过多类似重复的代码,pygame提供了精灵和精灵组类

心得: 其根本就是,将需要创建的多个执行相同动作的元素通过精灵类统一规划到一起,再通过精灵组统一执行每个元素的动作并绘制到屏幕上,将多次重复的代码缩减成一次代码。

  • pygame.sprite.Sprite —— 存储图像数据image和位置rect 的对象
  • pygame.sprite.Group

注:在开发时,如果子类的父类不是Object类,则需要通过super(),__init__()来调用父类的初始化方法,因为父类中的初始化方法中封装了许多属性,在继承父类后只有通过手动调用父类的初始化方法,才能在子类的初始化方法中使用父类初始化方法封装的属性

●精灵
。封装图像image、位置rect
。提供update() 方法,根据游戏需求,更新位置rect

    # 定义对象的属性
    self.image = pygame.image.load(image)
    # 得到图片的坐标和宽高像素
    self.rect = self.image.get_rect()

●精灵组
。包含多个精灵对象
。update 方法,让精灵组中的所有精灵调用update 方法更新位置
。draw(游戏窗口对象) 方法,在游戏窗口上绘制精灵组中的所有精灵

实例:

#精灵类planeSprites:

import pygame

class planeSprites(pygame.sprite.Sprite):
    def __init__(self, image, speed=1):

        # 调用父类的初始化方法
        super().__init__()
    
        # 定义对象的属性
        self.image = pygame.image.load(image)
        # 得到图片的坐标和宽高像素
        self.rect = self.image.get_rect()
        # 定义图片的运行速度
        self.speed = speed
    
    def update(self, *args):
        # 使飞机斜着飞行
        self.rect.x += self.speed
        self.rect.y += self.speed
        # 杀死精灵,节约内存
        self.kill()

主程序中:

import pygame
from plane_sprites import planeSprites
pygame.init()

# 创建敌机1,敌机2
enemy1 = planeSprites("./飞机大战素材/敌机.png")
enemy2 = planeSprites("./飞机大战素材/敌机.png")
# 在精灵组中加入敌机1
enemy_group = pygame.sprite.Group(enemy1, enemy2)
while True:
	# 调用精灵组的update方法
    enemy_group.update()
    # 将精灵组中的敌机绘制到屏幕上
    enemy_group.draw(screen)
    # ***一定记得更新视图,否则不会显示出任何图像
    pygame.display.update()
    
pygame.quit()

12.9 pygame中提供的两种精灵碰撞检测方法


pygame.sprite.groupcolide()
groupcollide(group1, group2, dokill1, dokill2, collided = None) -> Sprite_ dict

group1和group2都是一个精灵组
dokill1和dokill2都是布尔类型

当把dokill1设置为True后,精灵组1和精灵组2碰撞时精灵组1会自动销毁
当把dokill2设置为True后,精灵组1和精灵组2碰撞时精灵组2会自动销毁

pygame.sprite.spritecollide()
●判断某个精灵和指定精灵组中的精灵的碰撞

spritecollide(sprite, group, dokill, collided = None) -> Sprite_ list

●如果将dokill 设置为True,则指定精灵组中发生碰撞的精灵将被自动移除

● collided参数是用于计算碰捶的回调函数
。如果没有指定,则每个精灵必须有一一个rect 属性

●返回精灵组中跟精灵发生碰撞的精灵列表

注:这里是返回一个列表

代码实现:

        enemies = pygame.sprite.spritecollide(self.hero, self.enemyGroup, True)
        if len(enemies) > 0:
            print("游戏结束,飞机受到损坏")
            pygame.quit()
            exit()

12.10 背景交替滚动

俗称跑步机模式

在飞机大战中游戏背景不断变化产生向上飞行的视觉效果

实现原理:

实际上是两张尺寸与屏幕一样大小的背景图片向下移动,等第一张图片刚移除出屏幕后立马改变坐标移动到第二张图片之后

代码实现:
精灵类

import pygame

from plane_main import SCREEN_RECT
class planeSprites(pygame.sprite.Sprite):
    def __init__(self, image, speed=1):
        # 调用父类的初始化方法
        super().__init__()

        # 定义对象的属性
        self.image = pygame.image.load(image)
        # 得到图片的坐标和宽高像素
        self.rect = self.image.get_rect()
        # 定义图片的运行速度
        self.speed = speed
    
    def update(self, *args):
        # 使精灵向下移动
        self.rect.y += self.speed


# 当父类update更新方法已经无法满足某一精灵类的条件则可以创建心得精灵子类
class background(planeSprites):

    def __init__(self, is_single=False):
        super().__init__("./飞机大战素材/游戏背景.jpg")
        if is_single:
        	#将第二张图片放在第一张图片的上面
            self.rect.y = - self.rect.height
    
    def update(self, *args):
        # 调用父类更新方法
        super().update()
        if self.rect.y == SCREEN_RECT.height:
            self.rect.y = - self.rect.height

主方法:

import pygame
from plane_sprites import *

pygame.init()

SCREEN_RECT = pygame.Rect(0, 0, 480, 700)
class main(object):
    def __init__(self):
        # 创建游戏屏幕
        self.screen = pygame.display.set_mode(SCREEN_RECT.size)
        # 创建游戏时钟
        self.clock = pygame.time.Clock()
        # 创建游戏精灵组
        self.__create_spirits()

    # 精灵创建
    def __create_spirits(self):
        bg1 = background()
        bg2 = background(True)
        self.backGroup = pygame.sprite.Group(bg1, bg2)  
         
    # 精灵更新处理
    def __update_spirits(self):
        self.backGroup.update()
        self.backGroup.draw(self.screen)

12.11 定时器

●在 pygame中可以使用pygame.time.set.timer()来添加定时器

●所谓定时器,就是每隔一段时间,去执行些动作

set_timer(eventid, milliseconds) -> None

●set_timer 可以创建一个事件
●可以在游戏循环的事件监听方法中捕获到该事件

● 第1个参数事件代号需要基于常量pygame. USEREVENT 来指定

USEREVENT 是一个整数,再增加的事件可以使用USEREVENT + 1指定,依次类推…

●第2个参数是事件触发间隔的毫秒值

定时器事件的监听
●通过pygame.event.get() 可以获取当前时刻所有的事件列表
●遍历列表并且判断event.type 是否等于eventid, 如果相等,表示定时器事件发生

实现方法:

# 创建敌机的定时器,每隔1000ms发出一个事件
pygame.time.set_timer(pygameUSEREVENT, 3000)
# 事件监听
for event in pygame.event.get():
	if event.type == pygameUSEREVENT:
		pass

实例(敌机随机飞进屏幕中):

精灵类

import random
import pygame
# 指定屏幕格式大小
SCREEN_RECT = pygame.Rect(0, 0, 480, 700)
CREATE_EVVENTID = pygame.USEREVENT

class planeSprites(pygame.sprite.Sprite):
    def __init__(self, image, speed=1):
        # 调用父类的初始化方法
        super().__init__()

        # 定义对象的属性
        self.image = pygame.image.load(image)
        # 得到图片的坐标和宽高像素
        self.rect = self.image.get_rect()
        # 定义图片的运行速度
        self.speed = speed
        # 创建敌机的定时器,每隔1000ms发出一个事件
        pygame.time.set_timer(CREATE_EVVENTID, 3000)

class enemy(planeSprites):
    """敌机精灵"""

    def __init__(self):
        super().__init__("./飞机大战素材/敌机.png")
        self.rect.bottom = 0
        # 飞机速度从1—3中任取
        self.speed = random.randint(1, 3)
        max_x = SCREEN_RECT.width - self.rect.width
        # 飞机的位置从0-屏幕右边任取
        self.rect.x = random.randint(0, max_x)
    
    def update(self, *args):
        super().update()
        # 判断精灵飞出屏幕后杀死精灵
        if self.rect.y >= SCREEN_RECT.height:
            self.kill()

主方法:

import pygame
from plane_sprites import *
pygame.init()
    # 精灵创建
    def __create_spirits(self):
        self.enemyGroup = pygame.sprite.Group()
    # 事件监听处理
    def __event_handler(self):
        for event in pygame.event.get():
            # 判断事件类型是否是定时器给出的
            if event.type == CREATE_EVVENTID:
                # 新增精灵
                oneEnemy = enemy()
                # 向精灵组中添加精灵
                self.enemyGroup.add(oneEnemy)
                
    # 精灵更新处理
    def __update_spirits(self):
        self.enemyGroup.update()
        self.enemyGroup.draw(self.screen)

12.12 音乐导入

#导入音乐
	pygame.mixer.init()
	def background_music_load():
	        global hero_fire_music # 导入函数外部变量
	        pygame.mixer.music.load("./music/PlaneWarsBackgroundMusic.mp3")#游戏背景音乐
	        pygame.mixer.music.set_volume(0.3)#设置音量(0-1)
	        pygame.mixer.music.play(-1)#循环播放
	        hero_fire_music = pygame.mixer.Sound("./music/hero_fire.wav")#飞机开火音乐
	        hero_fire_music.set_volume(0.2)#设置音量(0-1)

  Python知识库 最新文章
Python中String模块
【Python】 14-CVS文件操作
python的panda库读写文件
使用Nordic的nrf52840实现蓝牙DFU过程
【Python学习记录】numpy数组用法整理
Python学习笔记
python字符串和列表
python如何从txt文件中解析出有效的数据
Python编程从入门到实践自学/3.1-3.2
python变量
上一篇文章      下一篇文章      查看所有文章
加:2022-07-04 22:49:56  更:2022-07-04 22:53:00 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/18 15:56:31-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码