飞机大战

liunx操作

安装pygame

1,首先安装pygame

sudo pip3 install pygame

2,验证是否安装pygame

python3 -m pygame.examples.aliens

如果安装上那就完成下列步骤,完成飞机大战项目:

项目准备

一. 使用 pygame 创建图形窗口
二. 理解 图像 并实现图像绘制
三 理解 游戏循环 和 游戏时钟
四. 理解 精灵 和 精灵组

一,创建图形窗口
1.游戏的初始化和退出
切记

    * 要使用 pygame 提供的所有功能之前,需要调用 init 方法
    * 在游戏结束前需要调用一下 quit 方法

import pygame

导入并初始化所有 pygame 模块,使用其他模块之前,必须先调用 init 方法

pygame.init()

游戏代码...

卸载所有 pygame 模块,在游戏结束之前调用!

pygame.quit()
2.游戏中的坐标系

* 坐标系

    * 原点 在 左上角 (0, 0)
    * x 轴 水平方向向 右,逐渐增加
    * y 轴 垂直方向向 下,逐渐增加
 SCREEN_RECT = pygame.Rect(0, 0, 480,600)
依次是英雄的x,y轴,宽度和长度 

3.创建游戏主窗口
pygame 专门提供了一个 模块 pygame.display 用于创建、管理 游戏窗口

)初始化游戏显示窗口

pygame.display.set_mode()

刷新屏幕内容显示,稍后使用

pygame.display.update()

基础类的构建

导弹类

  • 1.导弹是从飞机上发射的(无论是玩家的飞机还是敌机),导弹的位置需要根据飞机的位置确定,还需要根据是玩家飞机还是敌机确定导弹的图片名和发射方向,因此需要传入图片名和位置参数。


    这里写图片描述

    pygame框架加载图片为图像函数为:

    pygame.image.load(image).convert()
    

    传入的参数是图片的相对路径

  • 2.描绘出导弹的位置,导弹并且需要在初始化的self.xself.y基础上移动位置,位置是在屏幕上描绘的,需要传入屏幕参数。

    这里写图片描述

    pygame显示图片函数为:

    screen.blit(self.image,(self.x,self.y))
    pygame.display.update()
    

    第一个参数为加载的图像,第二个参数为左上角坐标。两个函数是配合使用的,需要第二个函数去刷新界面。

飞机类

  • 1.Plane类是接下来要创建的玩家类Hero和敌机类Enemy的基类。基类把两者共同的属性和方法定义出来,方便子类继承。飞机要发射导弹,有一定的发射间隔,因此定义一个对象属性self.bulletSleepTime。还需要一个列表存储导弹,定义一个对象属性为空列表self.bulletList

    这里写图片描述

    time.time()可以用来确定当前时间,按照一定的格式可以转换

  • 2.在初始化的时候我们定义了导弹的发射间隔时间,大于间隔时间的话我们就往定义的列表中添加导弹对象,因为我现在只想让玩家飞机发射子弹,因此初始化导弹对象特意往self.x加了36(是玩家飞机72x72图片宽度的一半),让导弹在玩家飞机的正中间开始显示。

    这里写图片描述

  • 3.描绘出飞机的位置


    这里写图片描述

继承类的构建

玩家飞机类

  • 1.在飞机基类中我们定义了一些共同的对象属性,不同的对象属性有图像和原始位置,而且玩家飞机类对象还想拥有基类对象的属性,所以需要调用Plane.__init__(self)函数,通过这个函数就拥有了Plane基类的对象属性bulletSleepTimelastShootTimebulletList

    这里写图片描述

  • 2.玩家飞机通过键盘的上下左右控制飞机的位置


    这里写图片描述

敌人飞机类

1.jpg
  • 1.敌人飞机类中还多了速度对象属性,考虑到随着游戏难度的增加,敌人飞机速度越来越快,这个参数需要外界传入。而且敌人飞机有小中大三种类型,是随机的,起始的位置x轴也是随机的,y轴固定从最上方开始。

    这里写图片描述

    用到了随机数函数,需要导入random模块

    random.randint(1,3)
    

    其中用到了super(Enemy,self).__init__()与玩家类中的Plane.__init__(self)效果是相同的。direction对象属性可以忽略,现在没有用到。

  • 2.敌人的飞机不断往下掉,改变self.y,其实不用判断,direction没有用到

    这里写图片描述

游戏初始化类(封装功能)

  • 1.GameInit类创建了几个类属性,g_enemyList=[]列表用于存储敌人飞机对象,初始化玩家对象hero=objectobject是元类,和用于统计玩家分数的属性score

    这里写图片描述
  • 2.接下来定义了几个类方法和静态方法,用于封装功能,在主函数里调用的都是这些类方法和静态方法

    • 往敌机列表中添加敌机对象,忽略下我的代码英语好像打错了


      这里写图片描述
    • 创建玩家飞机对象


      这里写图片描述
    • 游戏初始化


      这里写图片描述
    • 玩家飞机对象处理键盘操作,在玩家飞机类中已经定义了键盘处理函数,这里再封装一层


      这里写图片描述
    • 更新敌人飞机位置,敌人飞机对象都在g_enemyList列表中

      这里写图片描述

    • 有3种类型的对象需要描绘,玩家飞机对象,敌人飞机对象和导弹,这个函数就是用来描绘这些对象,其中导弹和敌机需要判断哪些对象超出屏幕从列表中删除,这里用了del函数,记录下索引值并从列表中删除,同样也可以用pop函数,这里的j为索引值

      这里写图片描述

    • 玩家飞机对象发射子弹,同时也要判断打中了敌机就让敌机对象和和子弹对象同时从列表中删除。通过pygame.Rect(self.image.get_rect())获得矩形的值,但是只获得了图像的widthheight两个属性,前两个属性lefttop都为0,因此还需要设置这两个属性,然后通过collidetect判断两个矩形是否有相交处,其中索引值enemyIndexbulletIndex需要仔细分析下

      这里写图片描述

    • 判断玩家飞机是否与敌机相撞判断游戏是否结束


      这里写图片描述
  • 3.几个静态方法,静态方法不需要cls这个参数,通过类和实例都可以调用

    • 退出整个程序


      这里写图片描述
    • 进入游戏后可以按space键停止游戏,其实就是就是个死循坏,按键按下后跳出函数

      这里写图片描述

    • 游戏开始后和结束后把分数显示出来,第一个参数是分数,第二个参数是通过pygame的字体库创建出来的,例如font = pygame.font.SysFont(None,64),参数分别为字体样式和大小,可以选择字体样式例如arialsimsun(宋体),第三个参数是屏幕,第四和第五个参数是字体显示的lefttop值。

      这里写图片描述

1,首先安装pygame
sudo pip3 install pygame
2,验证是否安装pygame
python3 -m pygame.examples.aliens
如果安装上那就完成下列步骤,完成飞机大战项目:
项目准备
一. 使用 pygame 创建图形窗口
二. 理解 图像 并实现图像绘制
三 理解 游戏循环 和 游戏时钟
四. 理解 精灵 和 精灵组
一,创建图形窗口
1.游戏的初始化和退出
切记
* 要使用 pygame 提供的所有功能之前,需要调用 init 方法
* 在游戏结束前需要调用一下 quit 方法

import pygame

导入并初始化所有 pygame 模块,使用其他模块之前,必须先调用 init 方法

pygame.init()

游戏代码...

卸载所有 pygame 模块,在游戏结束之前调用!

pygame.quit()
2.游戏中的坐标系

  • 坐标系

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

SCREEN_RECT = pygame.Rect(0, 0, 480,600)
依次是英雄的x,y轴,宽度和长度
3.创建游戏主窗口
pygame 专门提供了一个 模块 pygame.display 用于创建、管理 游戏窗口

)初始化游戏显示窗口

pygame.display.set_mode()

刷新屏幕内容显示,稍后使用

pygame.display.update()

主函数

  • 1.运行一个模块,有if __name__ == 'main':标识,会直接运行里面的代码。第一步初始化pygame库,调用pygame.init(),第二步创建一个窗口与背景图片一样大:screen = pygame.display.set_mode((ScreenWidth,ScreenHeight),0,32),然后可以设置窗口标题:pygame.display.set_caption('飞机大战'),第三步做一些初始化常量设置。其中纪录了游戏开始的时间,因为按照我的思想游戏开始后难度会逐渐增加,我是通过时间来增加难度的

    这里写图片描述

    启动时显示start图片,直到Enter键按下才进入游戏

  • 2.进入while 循坏后,调用游戏初始化类封装好的函数,通过时间间隔interval选定游戏困难模式,通过改变敌机刷新的时间和敌机的速度增加难度,游戏结束后,再次按下Enter 按键退出程序。这里存在一个bug,一旦游戏进行过程中按下Space暂停游戏,interval时间间隔仍然再计算(按道理应该让时间暂停),再次按下Space恢复游戏后,当前模式设定时间减少了或者进入更困难模式了。

    这里写图片描述

1.jpg

game.py


import pygame
import random
SCREEN_RECT = pygame.Rect(0, 0, 480,600)


# 接下来我们就开始写我们敌机方面的内容 (产生敌机)
# 我先定义一个事件常量
CREATE_ENEMY_EVENT = pygame.USEREVENT

# 我们还可以定义一个事件常量 (发射子弹)
HERO_FIRE_EVENT = pygame.USEREVENT + 1

bg1 = pygame.image.load('./images/enemy0_down1.png')
bg2 = pygame.image.load('./images/enemy0_down2.png')
bg3 = pygame.image.load('./images/enemy0_down3.png')
bg4= pygame.image.load('./images/enemy0_down4.png')

#爆炸的精灵组
enemy1_down_group = pygame.sprite.Group()

#把爆炸图片放到列表中
enemy1_down_surface = []
enemy1_down_surface.append(bg1)
enemy1_down_surface.append(bg2)
enemy1_down_surface.append(bg3)
enemy1_down_surface.append(bg4)


class GameSprite(pygame.sprite.Sprite):
    """游戏精灵的基础类"""
    # 我们其实可以给我们的基础类的速度 设置一个默认值
    def __init__(self,new_image,new_speed=1):
        super().__init__()
        # 我们需要以下3个属性
        # 考虑到通用性  我们需要改造一下代码
        # pygame.image.load pygame提供的方法 主要是加载图片
        self.image = pygame.image.load(new_image)
        # self.image.get_rect() 获取图片的宽高 get_rect() 是pygame提供
        self.rect = self.image.get_rect()
        # 这是将来精灵的移动速度 精灵有:英雄精灵 背景精灵 敌机精灵 子弹精灵
        self.speed = new_speed

    def update(self):
        # 默认垂直方向移动 (这个时候我就要有一个概念 坐标系的y轴控制垂直
        self.rect.y += self.speed


# 那么以上就是我们游戏的基础类 接下来我们需要设置我们的 背景类
# 首先我们需要先明确我们的背景类  继承自我们的游戏精灵类
class Background(GameSprite):
    """背景精灵类"""
    def __init__(self,is_alt=False):
        """is_alt 判断是否为另外一张图像
        False表示第一张图像 
        True表示另外一张图像     我们最开始说了  我们是2张图像交替
        在这里我先设置一下 vim快捷键
        """
        # 因为背景图片是固定的  所以我们可以在背景精灵类直接传图片
        super().__init__('./images/background.png')
        if is_alt:
            # 如果是地二张图片 我们让他的初始位置为 -self.rect.height
            self.rect.y = -self.rect.height

    def update(self):
        # 1 调用父类的方法实现 这是实现父类方法
        super().update()
        # 2 判断是否移除屏幕 如果移出屏幕 我们就要将图像设置到屏幕到上方
        # SCREEN_RECT.height 这是我们自己设置的常量  我们可以往上看
        # 其实到这一步 我们就已经把我们的背景类设计完了 接下来我们就去我们的主程序模块调用就行了
        if self.rect.y >= SCREEN_RECT.height:
            self.rect.y = -self.rect.height

# 接下来我们就要设置我们的敌机类
# 我们的敌机类 同样也是继承自我们的精灵基类
class Enemy(GameSprite):
    """敌机精灵类"""
    def __init__(self):
        # 1 调用父类方法 创建敌机精灵类 并且指定敌机图像
        super().__init__('./images/enemy1.png')
        # 2 设置敌机初始速度 稍后设置 (随机数)
        self.speed = random.randint(1, 3)
        # 3 设置敌机的随机初始位置 稍后设置
        # self.rect.y  = self.rect.bottom - self.rect.height
        self.rect.bottom = 0
        # 敌机x轴最大值 需要用屏幕的宽度-敌机自身的宽度
        max_x = SCREEN_RECT.width - self.rect.width
        # 随机一个位置
        self.rect.x = random.randint(0, max_x)


        # 我们发现。。。。。敌机出来的位置在 一条线上
        # 说明  x轴的位置一直没有变 

        def update(self):
            # 1 调用父类方法
            super().update()

            # 2 判断是否飞出屏幕 如果是 需要敌机从精灵组删除
            if self.rect.y >= SCREEN_RECT.height:
                print("敌机飞出屏幕")
                # 移出屏幕  就销毁
                self.kill()
# 接下来我们就设计英雄类和子弹类

# 英雄精灵类
class Hero(GameSprite):
    """英雄精灵类"""
    def __init__(self,a):
        # 英雄的初始速度我设置为0
        super().__init__('./images/plane.png',0)

        # 设置初始位置 这是是让我英雄X轴的中心点等于屏幕X轴中心点
        self.rect.centerx = SCREEN_RECT.centerx + a
        # 这里是设置我飞机的y轴
        self.rect.bottom = SCREEN_RECT.bottom 

        # 子弹组
        self.bullets = pygame.sprite.Group()
        # 这样 我们的子弹精灵组 就创建完毕了 我们就要去fire里面修改我们的
        # 方法
        self.speed1 = 0

    def update(self):
        # 飞机水平移动
        self.rect.x += self.speed
        self.rect.y += self.speed1
        # 控制英雄边界 屏幕边界
        if self.rect.left < 0:
            self.rect.left = 0
        if self.rect.right >SCREEN_RECT.right:
            self.rect.right = SCREEN_RECT.right
        if self.rect.bottom > SCREEN_RECT.height:
            self.rect.bottom = SCREEN_RECT.height
        if self.rect.top < 0:
            self.rect.top = 0
    def fire(self):
        # 英雄的方法。。。发射子弹  是一个动作  是一个行为 。。。
        print("发射子弹....")

        for i in (1,2,3):
            # 子弹精灵 我们在 英雄的这个fire()方法里面去创建
            #1 创建 子弹精灵
            bullet = Bullet()
            gws = Bullet()
            sst = Bullet()
            #2 设置精灵位置
            bullet.rect.bottom = self.rect.y -20
            bullet.rect.centerx = self.rect.centerx
            gws.rect.bottom = self.rect.y -20
            gws.rect.centerx = self.rect.centerx +15
            sst.rect.bottom = self.rect.y -20
            sst.rect.centerx = self.rect.centerx -15
            #3 将精灵添加到精灵组
            
            self.bullets.add(bullet,gws,sst)


class Bullet(GameSprite):
    """子弹精灵"""
    def __init__(self):
        super().__init__('./images/bullet1.png',-20)
    def update(self):
        super().update()
        # 判断是否超出屏幕
        if self.rect.bottom < 0:
            self.kill()

飞机大战.py

import pygame
from game import *
pygame.mixer.init()
#pygame.mixer.music.load('/home/share/MC天佑 - 又.mp3')
#pygame.mixer.music.play()
class PlaneGame(object):
    """飞机大战主游戏类"""
    # 初始化方法

    def __init__(self):
        print("游戏初始化")
        """在开始游戏我们做这么几件事
        1 创建游戏窗口
        2 创建游戏时钟
        3 调用创建精灵和精灵组的方法 (私有方法)
        """
        self.screen = pygame.display.set_mode(SCREEN_RECT.size)
        self.clock = pygame.time.Clock()
        
        self.__create_sprites()
        pygame.time.set_timer(CREATE_ENEMY_EVENT, 1000)

    def start_game(self):
        """在开始游戏这里我们需要做下面几件事"""
        while True:
            # 1 设置帧率
            self.clock.tick(10)
            # 2 事件监听 主要是要监听我们鼠标 键盘的一些事件
            self.__event_handler()
            # 3 碰撞检测 碰撞检测的内容比较  在这里我还没有定义 现在需要补上
            self.__check_collide()
            # 4 更新精灵和精灵组
            self.__update_sprites()
            # 5  更新显示
            pygame.display.update()
            # 在上面  我们调用类方法 并且关于帧率的设置
            # 更新精灵组 碰撞检测 刷新屏幕这些事情 是要实时检测的
            # 所以我写在游戏循环里面
            # 没1/60秒 就会调用一次

    # 创建精灵和精灵组
    def __create_sprites(self):
        bg1 = Background()
        # True 就表示是第二张图片
        bg2 = Background(True)
        # 英雄
        self.hero = Hero(10)
        self.hero1 = Hero(10)
        self.back_group = pygame.sprite.Group(bg1, bg2)
        # 敌机组
        self.enemy_group = pygame.sprite.Group()
        # 英雄组
        self.hero_group = pygame.sprite.Group(self.hero,self.hero1)

    # 事件监听
    def __event_handler(self):

        # 在这里我先写 事件监听  为啥呢?在调试过程中我好关闭窗口呀
        for event in pygame.event.get():
            # 另外一个方案 返回按键元组  这个我们观察一下就知道了
            # 如果 某个按键按下 对应的值应该会是
            key_pressed = pygame.key.get_pressed()
            key_pressed1 = pygame.key.get_pressed()
            if key_pressed[pygame.K_KP1]:
                self.hero.fire()
            if key_pressed[pygame.K_RIGHT]:
                print("向右边移动")
                # 给英雄一个移动速度
                self.hero.speed = 15
            elif key_pressed[pygame.K_LEFT]:
                self.hero.speed = -15
                print("向左边移动")

            elif key_pressed[pygame.K_UP]:
                print("向上边移动")
                self.hero.speed1 = -15
            elif key_pressed[pygame.K_DOWN]:
                print("想下边移动")
                self.hero.speed1 = 15
            else:
                self.hero.speed = 0
                self.hero.speed1 = 0
            # pygame.event.get():这是 获取到我们所有的事件
            if event.type == pygame.QUIT:

                # 在开发的过程中需要  有这种思想 专门的事情由专门的方法去做
                self.__game_over()
                # 去创建敌机  因为我的目的 就是每秒创建一家敌机
            elif event.type == CREATE_ENEMY_EVENT:
                # 因为我的敌机精灵类还没有写
                # 看看有没有出错  看看是不是每秒调用一次
                print("新的敌机产生")
                # 我们添加了敌机  但是但是但是
                # 没有刷新呀!
                self.enemy_group.add(Enemy())
            if key_pressed1[pygame.K_SPACE]:
                self.hero1.fire()
            if key_pressed1[pygame.K_d]:
                print("向右边移动")
                # 给英雄一个移动速度
                self.hero1.speed = 8
            elif key_pressed1[pygame.K_a]:
                self.hero1.speed = -8
                print("向左边移动")

            elif key_pressed1[pygame.K_w]:
                print("向上边移动")
                self.hero1.speed1 = -8

            elif key_pressed1[pygame.K_s]:
                print("想下边移动")
                self.hero1.speed1 = 8
            else:
                self.hero1.speed = 0
                self.hero1.speed1 = 0

    # 更新精灵和精灵组
    def __update_sprites(self):
        """更新精灵组"""

        #  到这里我们就可以简写代码了 改造 看了比较清爽
        for xxx in [self.back_group, self.enemy_group, self.hero_group, self.hero.bullets, self.hero1.bullets]:
            xxx.update()
            xxx.draw(self.screen)

    def __check_collide(self):
        # 地三个参数为 Ture的时候 就是当碰撞的时候 被碰撞的精灵从精灵组移出
        pygame.sprite.groupcollide(
            self.enemy_group, self.hero.bullets,True, True)
        # 2 敌机撞毁飞机
        enemies = pygame.sprite.spritecollide(
            self.hero, self.enemy_group, True)
        pygame.sprite.groupcollide(
            self.enemy_group, self.hero1.bullets, True, True)
        enemies1 = pygame.sprite.spritecollide(
            self.hero1, self.enemy_group, True)
        # 判断列表时候有内容
        if len(enemies) == 1:
            # 让英雄牺牲
            self.hero.rect.x = -SCREEN_RECT.width
        if len(enemies1) == 1:
            
            self.hero1.kill()
            self.hero1.rect.x = -SCREEN_RECT.width
        if self.hero.rect.x == -SCREEN_RECT.width and self.hero1.rect.x == -SCREEN_RECT.width:
            # 结束游戏
            self.__game_over()

    def __game_over(self):
        """游戏结束"""
        print("游戏结束")
        # 这是pygame提供的卸载模块的功能
        pygame.quit()
        # 这是python本身提供的退出脚本的功能
        exit()
        # 总结 :我们需要先卸载我们的pygame模块  然后退出我们的脚本



# 这个方法就是在我当前方法内生效 在其他模块调不到
if __name__ == "__main__":
    # 创建游戏对象
    game = PlaneGame()
    # 开始游戏
    game.start_game()

最后,我想说 :显然,程序员的生活是很枯燥的

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,362评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,330评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,247评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,560评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,580评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,569评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,929评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,587评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,840评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,596评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,678评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,366评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,945评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,929评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,165评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,271评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,403评论 2 342

推荐阅读更多精彩内容