基于wxWidgets的俄罗斯方块

功能:
1.游戏中会随机产生7种不同的图形;
2.每种图形都是由四个方形的色块组成的;
3.玩家可以控制每种图形旋转、左右移动;
4.图形自动下落,当下落到底部或者碰到其他方块则不能继续下落;
5.每行方格满了,自动消除,并计一分;
6.当正中图形无法下落时,游戏结束

具体流程

  • 图形类
    记录7种图形的信息
    1.管理类型
    2.获取图形边界
    3.转转方块

图形类型

// 图形类型 0-7
enum Tetrominoes{
        NoShape,        // 无图形 0
        ZShape,         // Z      1
        SShape,         // S      2
        LineShape,      // |      3
        TShape,         // T      4
        SquareShape,    // 方块   5
        Lshape,         // L      6
        MirroredLshape  // 反L    7
};

8×4×2 : 8页 每页是一个4行2列的二维数组

  • 说明:
/**
* @brief 图形类
*
* @details
* 1.图形的基本信息
* 2.管理图形
* 3.获取图形边界
* 4.旋转图形
*/
class Shape{
public:
        /**
        * @brief 构造函数
        *
        * @details
        * 以无图形创建实例
        */
        Shape();


        /**
        * @brief 设置图形
        *
        * @details
        * 1.规定图形位置
        * 2.根据图形类型设置图形坐标,并保存当前图形类型
        *
        * @param shape 图形类型(enum)
        */
        SetShape(Tetrominoes shape);


        /**
        * @brief 设置图形
        *
        * @details
        * 1.规定图形位置
        * 2.根据图形类型设置图形坐标,并保存当前图形类型
        *
        * @param shape 图形类型(enum)
        */
        SetShape(Tetrominoes shape);


        /**
        * @brief 随机设置图形
        *
        * @details
        * 1.能够随机产生1-7之间的随机数
        * 2.根据随机数设置图形
        */
        SetRandomShape();


        /**
        * @brief 获取图形类型
        *
        * @return 图形类型
        *
        */
        Tetrominoes GetShape()const{return pieceShape;}


        /**
        * @brief 获取图形中一个方块的横/纵坐标
        *
        * @param 1.index 第index个方块 2.x/y 方块的横/纵坐标
        * 以无图形创建实例
        */
        int x(int index) const { return coords[index][0]; }
        int y(int index) const { return coords[index][1]; }


        /**
        * @brief 获取图形边界
        *
        * @return 最大/最小边界值
        */
        int MinX() const;
        int MaxX() const;
        int MinY() const;
        int MaxY() const;

        /**
        * @brief 获取图形边界
        *
        * @return 最大/最小边界值
        */
        int MinX() const;
        int MaxX() const;
        int MinY() const;
        int MaxY() const;

        /**
        * @brief 获取左旋图形
        *
        * @details
        * 以(0,0)为中心
        * x -> y
        * y -> -x
        *@return 图形(类)
        */
        //   o
        // o o ->  o  o
        // o          o  o
        Shape RotateLeft() const;


        /**
        * @brief 获取右旋图形
        *
        * @details
        * 以(0,0)为中心
        * x -> -y
        * y -> x
        * @return 图形(类)
        */
        //   o      o  o
        // o o  ->     o  o
        // o
        Shape RotateRight() const;
private:
        Tetrominoes pieceShape;  // 图形类别
        int coords[4][2];        // 图形坐标


        /**
        * @brief 设置图形的横、纵坐标
        *
        * @param 1.index:行数 2.x/y:横纵坐标
        */
        void SetX(int index, int x) { coords[index][0] = x; }
        void SetY(int index, int y) { coords[index][1] = y; }
};
  • 代码
// 图形类
// 1.管理类型
// 2.获取图形边界
// 3.旋转方块
class Shape{
public:
        Shape(){SetShape(NoShape);}                  // 构造函数
        void SetShape(Tetrominoes shape){            // 设置图形类型
                static const int coordsTable[8][4][2] = {           // 图形位置
                        {{0,0},{0,0},{0,0},{0,0}},                  // 无图形
                        {{0,-1},{0,0},{-1,0},{-1,1}},               // Z
                        {{0,-1},{0,0},{1,0},{1,1}},                 // S
                        {{0,-1},{0,0},{0,1},{0,2}},                 // -
                        {{-1,0},{0,0},{1,0},{0,1}},                 // T
                        {{0,0},{1,0},{0,1},{1,1}},                  // 方形
                        {{-1,-1},{0,-1},{0,0},{0,1}},               // L
                        {{1,-1},{0,-1},{0,0},{0,1}},                // 反L
                };
                for(int i=0;i<4;i++){         // 设置的当前图形
                        for(int j=0;j<2;j++){
                                coords[i][j] = coordsTable[shape][i][j];
                        }
                        pieceShape = shape;   // 保存当前类型
                }

        }
        void SetRandomShape(){                               // 随机设置图形类型
                int type = rand()%7+1;
                // rand()%7 0-6 -> 1-7
                SetShape(Tetrominoes(type));
        }
        Tetrominoes GetShape()const{return pieceShape;}      // 获取图形类型      
        int x(int index)const{return coords[index][0];}
        int y(int index)const{return coords[index][1];}
        int MaxX()const{
                int m = coords[0][0];
                for(int i=0;i<4;i++){
                        m = max(m,coords[i][0]);
                }
                return m;
        }
        int MinX()const{
                int m = coords[0][0];
                for(int i=0;i<4;i++){
                        m = min(m,coords[i][0]);
                }
                return m;
        }
        int MaxY()const{
                int m = coords[0][1];
                for(int i=0;i<4;i++){
                        m = max(m,coords[i][1]);
                }
                return m;
        }
        int MinY()const{
                int m = coords[0][1];
                for(int i=0;i<4;i++){
                        m = min(m,coords[i][1]);
                }
                return m;
        }
        Shape RotateLeft()const{                     // 获取左旋后的图形
                if(pieceShape == SquareShape) return *this;
                Shape result;
                result.pieceShape = pieceShape;
                for(int i = 0;i<4;i++){
                        result.SetX(i,y(i));
                        result.SetY(i,-x(i));
                }
                return result;
        }
        Shape RotateRight()const{                    // 获取右旋后的图形
                Shape result;
                result.pieceShape = pieceShape;
                for(int i = 0;i<4;i++){
                        result.SetX(i,-y(i));
                        result.SetY(i,x(i));
                }
                return result;
        }
private:
        void SetX(int index,int x){coords[index][0] = x;}
        void SetY(int index,int y){coords[index][1] = y;}
        Tetrominoes pieceShape;  // 图形类别
        int coords[4][2];        // 图形坐标
};
  • 面板类
    继承wxPanel
    控件(绘制、键盘、计时器、游戏过程等)
  • 说明
/**
* @brief 面板类
*
* @details
* 继承wxPanel
*/
class Board:public wxPanel{
public:

        /**
        * @brief 构造函数
        *
        * @details
        * 初始化父类的一些参数
        * 初始化部分成员变量
        * 绑定事件
        *
        * @param parent 框架类
        */
        Board(wxFrame *parent);


        /**
        * @brief 开始
        *
        * @details
        * 修改部分成员变量
        * 创建一个新的图形
        * 开始计时
        */
        void Start();


        /**
        * @brief 暂停
        *
        * @details
        * 根据 暂停标志 进行操作
        * 暂停   停止计时 分数栏显示 paused
        * 不暂停 开始计时 分数栏显示分数
        */
        void Pause();

protected:
        /**
        * @brief 绘制事件
        *
        * @param event 事件
        *
        * @details
        * 获取画笔
        * 获取面板区域大小 // 在框架类中初始化成员列表中定义过
        * 获取剩余面板的高度(偏移量)
        * 绘制正在移动的图形
        * 绘制底层堆积的图形
        */
        void OnPaint(wxPaintEvent& event);

        /**
        * @brief 键盘事件
        *
        * @param event 事件
        *
        * @details
        * 左移 右移
        * 左旋 右旋
        * <space> 下落到底
        * <d/D> 下降一行
        * <p/P> 暂停
        */
        void OnKeyDown(wxKeyEvent& event);


        /**
        * @brief 计时器事件
        *
        * @param event 事件
        *
        * @details
        * 判断下降标志
        * 不在下落过程:更改标志、创建新的图形
        * 在下落过程:下降一行
        */
        void OnTimer(wxCommandEvent& event);
private:
        /**
        * @brief 方块个数
        *
        * @details
        * 10*22个方块
        */
        enum {BoardWidth = 10,BoardHeight = 22};


        /**
        * @brief 获取图形类
        *
        * @details
        * 获取(i,j)坐标的图形类型 10*22、
        *
        * @return Tetrominoes 图形类型
        */
        Tetrominoes& ShapeAt(int x,int y){return board[(y*BoardWidth)+x];}


        /**
        * @brief 获取一个方块的尺寸
        *
        * @details
        * 方块的宽/高 = 面板的宽/高 / 方块个数
        */
        int SquareWidth(){return GetClientSize().GetWidth()/BoardWidth;}
        int SquareHeight(){return GetClientSize().GetHeight()/BoardHeight;}

        /**
        * @brief 清空面板
        *
        * @details
        * 将方块面板全部置为NoShape
        */
        void ClearBoard();


        /**
        * @brief 下落到最底层 <space>
        *
        * @details
        * 对y进行--
        */
        void DropDown();


        /**
        * @brief 下降一行
        *
        * @details
        * y-1
        */
        void OneLineDown();


        /**
        * @brief 更新下降图形后的信息
        *
        * @details
        * 将图形基点根据图形类的坐标进行扩展
        * 分别将拓展的坐标设置为当前图形的类别对应的颜色
        * 有满行消除满的行
        * 如果下降结束 创建新的图形
        */
        void PieceDropped();


        /**
        * @brief 消除已满的行
        *
        * @details
        * 从顶端开始一行一行的遍历
        * 如果第i行满了,满的行数++,将当前行的图形信息由上一行代替
        * 更新计分板数值
        */
        void RemoveFullLines();


        /**
        * @brief 创建新图形
        *
        * @details
        * 设置当前位置的坐标:当前位置位于面板中间最上方
        * 如果不能移动则游戏结束
        */
        void NewPiece();


        /**
        * @brief 尝试移动 <->> <<->
        *
        * @param newPiece(const Shape&)图形(类) newX newY:横纵坐标
        *
        * @details
        * 将当前的图形移动到(newX,newY)
        * 移动后不能超边界、不能重合
        *
        */
        bool TryMove(const Shape& newPiece,int newX,int newY);


        /**
        * @brief 绘制方块
        *
        * @param dc(wxPaintDC):画笔 x/y:图形类中坐标 shape(Tetrominoes):图形类别(决定方块颜色)
        * @details
        * 不同类型的图形 颜色不同
        * 绘制一个方块
        * x+1,y+1 线宽
        */
        void DrawSquare(wxPaintDC &dc,int x,int y,Tetrominoes shape);

        wxTimer *timer;                                   // 计时器
        bool isStarted;                                   // 标志:游戏开始
        bool isPaused;                                    // 标志:游戏暂停
        bool isFallingFinished;                           // 标志:方块下落过程
        Shape curPiece;                                   // 类:当前的图形
        int curX;                                         // 当前方块的x坐标
        int curY;                                         // 当前方块的y坐标 // 当前位置为基点 图形类中的坐标作为基点的扩展
        int numLinesRemoved;                              // 移除的行数->得分
        Tetrominoes board[BoardWidth*BoardHeight];        // 方块面板 10*22 用来显示去全部面板的方块信息 存放的图形类别 根据图形类别显示
        wxStatusBar *m_stsbar;                            // 分值状态栏
};
  • 代码
// 面板类:继承wxPanel
class Board:public wxPanel{
public:
        Board(wxFrame *parent)
                :wxPanel(parent,wxID_ANY,wxDefaultPosition,wxDefaultSize,wxBORDER_NONE){   // 构造函数
                timer = new wxTimer(this,1);

                m_stsbar = parent->GetStatusBar();
                isFallingFinished = false;
                isStarted = false;
                isPaused = false;
                numLinesRemoved = 0;
                curX = 0;
                curY = 0;

                ClearBoard(); // 清空面板
                // 绑定事件
                Connect(wxEVT_PAINT,wxPaintEventHandler(Board::OnPaint));
                Connect(wxEVT_KEY_DOWN,wxKeyEventHandler(Board::OnKeyDown));
                Connect(wxEVT_TIMER,wxCommandEventHandler(Board::OnTimer));
        }
        void Start(){                           // 启动
                if(isPaused) return;
                isStarted = true;
                isFallingFinished = false;
                numLinesRemoved = 0;

                ClearBoard();
                NewPiece();
                timer->Start(300);
        }
        void Pause(){                           // 暂停
                if(!isStarted) return;
                isPaused = !isPaused;
                if(isPaused){
                        timer->Stop();
                        m_stsbar->SetStatusText(wxT("paused"));
                }else{
                        timer->Start(300);
                        wxString str;
                        str.Printf(wxT("%d"),numLinesRemoved);
                        m_stsbar->SetStatusText(str);
                }
                Refresh();
        }
        void lineRemovedChanged(int numLines){  // 消除
        }
protected:
        void OnPaint(wxPaintEvent& event){            // 绘制事件
                wxPaintDC dc(this);            // 获取画笔
                wxSize size = GetClientSize(); // 获取面板区域大小
                int boardTop = size.GetHeight() - BoardHeight*SquareHeight();

                // 画最底层堆积的图形
                for(int i=0;i<BoardHeight;i++){
                        for(int j=0;j<BoardWidth;j++){
                                Tetrominoes shape = ShapeAt(j,BoardHeight-i-1);
                                if(shape != NoShape) DrawSquare(dc,0+j*SquareWidth(),boardTop+i*SquareHeight(),shape);
                        }
                }

                // 画目前移动中的图形
                if(curPiece.GetShape() != NoShape){
                        for(int i=0;i<4;i++){
                                int x = curX + curPiece.x(i);
                                int y = curY - curPiece.y(i);
                                DrawSquare(dc,0+x*SquareWidth(),boardTop+(BoardHeight-y-1)*SquareHeight(),curPiece.GetShape());
                        }
                }
        }
        void OnKeyDown(wxKeyEvent& event){            // 键盘事件
                if(!isStarted || curPiece.GetShape() == NoShape){
                        event.Skip();
                        return;
                }
                int keycode = event.GetKeyCode();   // 获取键盘事件

                if(keycode == 'p' || keycode == 'P'){
                        Pause();
                        return;
                }
                if(isPaused) return;
                switch(keycode){
                        case WXK_LEFT:
                                TryMove(curPiece,curX-1,curY);
                                break;
                        case WXK_RIGHT:
                                TryMove(curPiece,curX+1,curY);
                                break;
                        case WXK_DOWN:
                                TryMove(curPiece.RotateRight(),curX,curY);
                                break;
                        case WXK_UP:
                                TryMove(curPiece.RotateLeft(),curX,curY);
                                break;
                        case WXK_SPACE:
                                DropDown();
                                break;
                        case 'd':
                        case 'D':
                                OneLineDown();
                                break;
                        default:
                                event.Skip();
                }
        }
        void OnTimer(wxCommandEvent& event){          // 计时器事件
                if(isFallingFinished){
                        isFallingFinished = false;
                        NewPiece();
                }else{
                        OneLineDown();
                }
        }
private:
        enum {BoardWidth = 10,BoardHeight = 22};
        Tetrominoes& ShapeAt(int x,int y){return board[(y*BoardWidth)+x];}

        int SquareWidth(){return GetClientSize().GetWidth()/BoardWidth;}
        int SquareHeight(){return GetClientSize().GetHeight()/BoardHeight;};

        void ClearBoard(){        // 清空面板
                for(int i=0;i< BoardHeight*BoardWidth;i++){
                        board[i] = NoShape;
                }
        }
        void DropDown(){          // 下落
                int newY = curY;
                while(newY > 0){
                        if(!TryMove(curPiece,curX,newY - 1)) break;
                        newY--;
                }
                PieceDropped();
        }
        void OneLineDown(){       // 下落一行
                if(!TryMove(curPiece,curX,curY-1)) PieceDropped();
        }
        void PieceDropped(){
                for(int i=0;i<4;i++){
                        int x = curX + curPiece.x(i);
                        int y = curY - curPiece.y(i);
                        ShapeAt(x,y) = curPiece.GetShape();
                }
                RemoveFullLines();
                if(!isFallingFinished) NewPiece();
        }
        void RemoveFullLines(){
                int numFUllLines = 0;
                for(int i = BoardHeight-1;i>=0;i--){
                        bool lineIsFull = true;
                        for(int j=0;j<BoardWidth;j++){
                                if(ShapeAt(j,i) == NoShape){
                                        lineIsFull = false;
                                        break;
                                }
                        }
                        if(lineIsFull){
                                numFUllLines++;
                                for(int k=i;k<BoardHeight-1;k++){
                                        for(int j=0;j<BoardWidth;j++){
                                                ShapeAt(j,k) = ShapeAt(j,k+1);
                                        }
                                }
                        }
                }
                if(numFUllLines > 0){
                        numLinesRemoved += numFUllLines;
                        wxString str;
                        str.Printf(wxT("%d"),numLinesRemoved);
                        m_stsbar->SetStatusText(str);

                        isFallingFinished = true;
                        curPiece.SetShape(NoShape);
                        Refresh();
                }
        }
        void NewPiece(){                                                 // 创建新方块
                curPiece.SetRandomShape();  // 随机创建图形
                curX = BoardWidth/2 +1;
                curY = BoardHeight-1+curPiece.MinY();

                if(!TryMove(curPiece,curX,curY)){
                        curPiece.SetShape(NoShape);
                        timer->Stop();
                        isStarted = false;
                        m_stsbar->SetStatusText(wxT("Game over"));
                }

        }
        bool TryMove(const Shape& newPiece,int newX,int newY){           // 尝试移动
                for(int i=0;i<4;i++){
                        int x = newX + newPiece.x(i);
                        int y = newY - newPiece.y(i);
                        if(x<0 || x>= BoardWidth || y<0 || y>=BoardHeight) return false;
                        if(ShapeAt(x,y) != NoShape) return false;
                }
                curPiece = newPiece;
                curX = newX;
                curY = newY;
                Refresh();
                return true;
        }
        void DrawSquare(wxPaintDC &dc,int x,int y,Tetrominoes shape){    // 绘制方块
                static wxColour clours[] = {
                         wxColour(0, 0, 0), wxColour(204, 102, 102),
                         wxColour(102, 204, 102), wxColour(102, 102, 204),
                         wxColour(204, 204, 102), wxColour(204, 102, 204),
                         wxColour(102, 204, 204), wxColour(218, 170, 0)
                };
                static wxColour light[] = {
                        wxColour(0, 0, 0), wxColour(248, 159, 171),
                        wxColour(121, 252, 121), wxColour(121, 121, 252),
                        wxColour(252, 252, 121), wxColour(252, 121, 252),
                        wxColour(121, 252, 252), wxColour(252, 198, 0)
                };
                static wxColour dark[] = {
                        wxColour(0, 0, 0), wxColour(128, 59, 59),
                        wxColour(59, 128, 59), wxColour(59, 59, 128),
                        wxColour(128, 128, 59), wxColour(128, 59, 128),
                        wxColour(59, 128, 128), wxColour(128, 98, 0)
                };

                wxPen pen(light[int(shape)]);
                pen.SetCap(wxCAP_PROJECTING);
                dc.SetPen(pen);

                dc.DrawLine(x,y+SquareHeight()-1,x,y);
                dc.DrawLine(x,y,x+SquareWidth()-1,y);

                wxPen darkpen(dark[int(shape)]);
                darkpen.SetCap(wxCAP_PROJECTING);
                dc.SetPen(darkpen);

                dc.SetPen(*wxTRANSPARENT_PEN);
                dc.SetBrush(wxBrush(clours[int(shape)]));
                dc.DrawRectangle(x+1,y+1,SquareWidth()-2,SquareHeight()-2);
        }

        wxTimer *timer;                                  // 计时器
        bool isStarted;                                  // 开始状态
        bool isPaused;                                   // 暂停状态
        bool isFallingFinished;                          // 下落完成

        Shape curPiece;                                  // 当前方块
        int curX;                                        // 当前方块x坐标
        int curY;                                        // 当前方块y坐标

        int numLinesRemoved;                             // 移除的行数
        Tetrominoes board[BoardWidth*BoardHeight];       // 方块面板
        wxStatusBar *m_stsbar;                           // 分值状态栏
};
  • 框架类
    继承wxFrame
    创建面板
    其他的一些设置(计分板、初始分数、焦点等)
  • 说明
/**
* @brief 构造函数
*
* @details
* 以无图形创建实例
*/
class Teris:public wxFrame{
public:

        /**
        * @brief 构造函数
        *
        * @details
        * 以初始化成员列表方式,初始化继承父类的一些参数
        * 创建面板
        * 设置信息(计分版等)
        *
        * @param title 标题 
        */
        Teris(const wxString& title);
}
  • 代码
// 框架类 继承wxFrame
class Teris:public wxFrame{
public:
        Teris(const wxString& title):wxFrame(NULL,wxID_ANY,title,wxDefaultPosition,wxSize(180,380)){
                wxStatusBar *sb = CreateStatusBar();   // 创建计分状态栏
                sb->SetStatusText(wxT("0"));           // 设置初始分值为0
                Board *board = new Board(this);        // 创建面板
                board->SetFocus();                     // 设置焦点
                board->Start();                        // 启动
        }
};
  • 应用程序类
    继承wxAPP
    创建框架
    重载OnInit()
  • 说明
/**
* @brief 应用程序类
*
* @details
* 初始化框架
*/
class MyApp:public wxAPP{
public:
        /**
        * @brief 初始化
        * 
        * @details                                                    
        * 重写wxAPP类中的OnInit                                       
        + 创建框架                                                    
        * 对框架的一些设置                                            
        * 显示框架                                                    
        */
        bool OnInit(){}
};
  • 代码:
// 应用程序类 继承wxAPP
// 创建框架
// 重载 OnInit()
class MyApp:public wxApp{
public:
        bool OnInit()override{
                srand(time(NULL));                      // 设置随机种子
                Teris* teris = new Teris(wxT("Teris")); // 创建框架
                teris->Centre();                        // 框架居中
                teris->Show(true);                      // 框架显示
                return true;
        }
};
  • 应用程序实例化
    调用宏 程序实例化
    参数:应用程序类类名
// 调用宏 程序实例化
// 参数:应用程序类类名
wxIMPLEMENT_APP(MyApp);
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,616评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,020评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,078评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,040评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,154评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,265评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,298评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,072评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,491评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,795评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,970评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,654评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,272评论 3 318
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,985评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,223评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,815评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,852评论 2 351

推荐阅读更多精彩内容