最詳細(xì)的Android貪吃蛇,人人都學(xué)的會(huì)

關(guān)于我

我是IsCoding,11年開始做 Android 開發(fā) 已經(jīng)做了7年
在創(chuàng)業(yè)公司負(fù)責(zé)過技術(shù),拿到過融資。
想做一些事。這件事我想了很久研究了很久,現(xiàn)在時(shí)機(jī)成熟了。
QQ群號(hào) 121915371
QQ 號(hào) 1400100300 (個(gè)人QQ 建議加群咨詢)

引言

我相信大部分人都應(yīng)該玩過貪吃蛇。具體規(guī)則大家都懂,這里不一一介紹規(guī)則。
在網(wǎng)上有很多貪吃蛇的代碼,為什么你還要看我的代碼。看了我的方式有什么好處。
這里我跟你保證,只要你有點(diǎn)Java基礎(chǔ),看半個(gè)小時(shí),自己就能獨(dú)立寫出來一個(gè)完整的貪吃蛇游戲。而且能真的理解為什么這么寫程序。
如果有不懂的地方可以加上面的群咨詢

分析

下面來講講如何寫一個(gè)程序。
分析界面,界面元素有三個(gè),一個(gè)是背景格子,一個(gè)是蛇,一個(gè)是隨機(jī)產(chǎn)生的點(diǎn)。
那么我們就可以定義三個(gè)對(duì)象
GridBean 格子對(duì)象 就是游戲的背景表格。
PointBean 點(diǎn)對(duì)象,就是隨機(jī)產(chǎn)生的點(diǎn)
SnakeBean 蛇的對(duì)象
整個(gè)游戲用戶看到的就是這幾個(gè)東西,我們要做的就是把這些東西畫到頁(yè)面上。

操作,游戲過程主要的操作就是上下左右。
我們可以用按鈕實(shí)現(xiàn),在頁(yè)面上添加四個(gè)按鈕,供用戶點(diǎn)擊
也可以用手勢(shì)實(shí)現(xiàn),用戶在頁(yè)面上滑動(dòng)來改變方向。

這幾個(gè)功能實(shí)現(xiàn)了,一個(gè)小游戲就基本完成了,我們還可以添加暫停,開始,添加速度等等操作。

實(shí)現(xiàn)

接下來我們一步一步分析,把游戲?qū)崿F(xiàn)起來

第一步

我們要定義三個(gè)類,就是上面我們說的三個(gè)類
先寫第一個(gè)PointBean用來表示頁(yè)面上的一個(gè)格子的位置
我們用想x,y來確定格子的位置,值是從0開始計(jì)算的。
比如0,0代表的是左上角第一個(gè)格子,2,1代表第三行,第二個(gè)格子,為什么從0開始,是因?yàn)閿?shù)組下標(biāo)從0開始,具體這里不解釋了。
代碼非常簡(jiǎn)單,這里直接給出來了

public class PointBean {
    private int x;
    private int y;

    public PointBean(int x, int y) {
        this.x = x;
        this.y = y;
    }

    public int getX() {
        return x;
    }

    public void setX(int x) {
        this.x = x;
    }

    public int getY() {
        return y;
    }

    public void setY(int y) {
        this.y = y;
    }
}

第二個(gè)類SnakeBean 這個(gè)類就很有意思了,其實(shí)蛇就是由一個(gè)個(gè)連續(xù)的小格子組成的,SnakeBean 里面就只有一個(gè)PointBean的List 代碼如下

public class SnakeBean {
    private List<PointBean> snake  = new LinkedList<PointBean>();
    public List<PointBean> getSnake() {
        return snake;
    }
    public void setSnake(List<PointBean> snake) {
        this.snake = snake;
    } 
}

其實(shí)這里我們只要在View里面定這個(gè)List 也可以去做,但是為了封裝需求,我們還是定義了一個(gè)Bean
接下來我們定義的是格子類
格子類主要包括幾個(gè)東西,間距這里方便起見所有間距設(shè)置一樣,也可以為每個(gè)方向設(shè)置一個(gè)間距,第二個(gè)就是格子的總長(zhǎng)度,還有每個(gè)格子的長(zhǎng)度,還有格子的數(shù)量
這里以1080*1920 手機(jī)為例子,如果需要?jiǎng)e的手機(jī)直接把這個(gè)值賦值為獲取手機(jī)值就行

public class GridBean {

    private int   height = 1920; //手機(jī)高
    private int   width = 1080; //手機(jī)寬

    private int offset = 90 ;//偏移量,就是間距  上 左 右 間距一樣

    private int gridSize = 30;//每行格子的數(shù)量
    private int lineLength;//線的長(zhǎng)度
    private int gridWidth  ;//格子寬

    public GridBean() {
        lineLength = width - offset * 2;
        gridWidth = lineLength / gridSize;// 格子數(shù)量
    }

    public int getOffset() {
        return offset;
    }

    public void setOffset(int offset) {
        this.offset = offset;
    }

    public int getGridSize() {
        return gridSize;
    }

    public void setGridSize(int gridSize) {
        this.gridSize = gridSize;
    }

    public int getLineLength() {
        return lineLength;
    }

    public void setLineLength(int lineLength) {
        this.lineLength = lineLength;
    }

    public int getGridWidth() {
        return gridWidth;
    }

    public void setGridWidth(int gridWidth) {
        this.gridWidth = gridWidth;
    }
} 

第二步,把格子和蛇畫到頁(yè)面上

首先你應(yīng)該了解自定義View,可以在自定義View中繪制直線,長(zhǎng)方形。
如果不了解請(qǐng)看這篇文章
http://www.lxweimin.com/p/2c3eb5924389
自定義View這里不需要多復(fù)雜的技術(shù),只用最簡(jiǎn)單部分就夠了

接下面我們一步步把這個(gè)自定義布局完成
首先初始化這個(gè)View編寫一個(gè)init方法
創(chuàng)建格子對(duì)象
初始化蛇對(duì)象

 private void init() {
        gridBean = new GridBean();//創(chuàng)建格子對(duì)象,畫格子時(shí)候使用
        snakeBean = new SnakeBean();//創(chuàng)建一個(gè)蛇對(duì)象。這時(shí)候蛇對(duì)象是空的,我們需要初始化一個(gè)值 
        PointBean pointBean = new PointBean(gridBean.getGridSize()/2,gridBean.getGridSize()/2);
        snakeBean.getSnake().add(pointBean);//定義一個(gè)中心點(diǎn) ,添加到蛇身上
    }

然后我們根據(jù)格子對(duì)象在頁(yè)面上畫直線就好了

   //畫豎線
        for (int i = 0; i <= gridBean.getGridSize(); i++) {
            int startX = gridBean.getOffset() + gridBean.getGridWidth() * i;
            int stopX = startX;
            int startY = gridBean.getOffset();//+gridBean.getGridWidth() * i
            int stopY = startY + gridBean.getLineLength();//
            canvas.drawLine(startX, startY, stopX, stopY, paint);
        }

這里給出畫豎線的方法,畫橫線跟豎線基本一樣
然后我們畫蛇,其實(shí)就是根據(jù)點(diǎn)畫一個(gè)方塊

   List<PointBean> snake = snakeBean.getSnake();
        for (PointBean point : snake) {
            int startX = gridBean.getOffset() + gridBean.getGridWidth() * point.getX();
            int stopX = startX + gridBean.getGridWidth();
            int startY = gridBean.getOffset() + gridBean.getGridWidth() * point.getY();
            int stopY = startY + +gridBean.getGridWidth();
            canvas.drawRect(startX, startY, stopX, stopY, paint);
        }

運(yùn)行程序,貪吃蛇這個(gè)項(xiàng)目就做出來了,蛇會(huì)背景都繪制完成了。
這里給出完整代碼,直接運(yùn)行就能看到效果了。

public class GameView extends View {
    private Paint paint = new Paint();

    private GridBean gridBean;
    private SnakeBean snakeBean;
 

    public GameView(Context context) {
        super(context);
        init();

    }

    public GameView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    private void init() {
        gridBean = new GridBean();//創(chuàng)建格子對(duì)象,畫格子時(shí)候使用
        snakeBean = new SnakeBean();//創(chuàng)建一個(gè)蛇對(duì)象。這時(shí)候蛇對(duì)象是空的,我們需要初始化一個(gè)值

        PointBean pointBean = new PointBean(gridBean.getGridSize()/2,gridBean.getGridSize()/2);
        snakeBean.getSnake().add(pointBean);//定義一個(gè)中心點(diǎn) ,添加到蛇身上
    }

    @Override
    protected void onDraw(Canvas canvas) {
        if (gridBean != null) {
            paint.setColor(Color.RED);
            drawGrid(canvas);
        }
        if (snakeBean != null) {
            paint.setColor(Color.GREEN);
            drawSnake(canvas);
        }
    }

    private void drawSnake(Canvas canvas) {
        List<PointBean> snake = snakeBean.getSnake();
        for (PointBean point : snake) {
            int startX = gridBean.getOffset() + gridBean.getGridWidth() * point.getX();
            int stopX = startX + gridBean.getGridWidth();
            int startY = gridBean.getOffset() + gridBean.getGridWidth() * point.getY();
            int stopY = startY + +gridBean.getGridWidth();
            canvas.drawRect(startX, startY, stopX, stopY, paint);
        }
    }

    private void drawGrid(Canvas canvas) {
        //畫豎線
        for (int i = 0; i <= gridBean.getGridSize(); i++) {
            int startX = gridBean.getOffset() + gridBean.getGridWidth() * i;
            int stopX = startX;
            int startY = gridBean.getOffset();//+gridBean.getGridWidth() * i
            int stopY = startY + gridBean.getLineLength();//
            canvas.drawLine(startX, startY, stopX, stopY, paint);
        }
        //畫橫線
        for (int i = 0; i <= gridBean.getGridSize(); i++) {
            int startX = gridBean.getOffset();//+gridBean.getGridWidth() * i
            int stopX = startX + gridBean.getLineLength();

            int startY = gridBean.getOffset() + gridBean.getGridWidth() * i;
            int stopY = startY;
            canvas.drawLine(startX, startY, stopX, stopY, paint);
        }
    }


}

好了今天課程講完了。

開個(gè)玩笑,寫了這么半天我們只實(shí)現(xiàn)了一個(gè)功能就是,繪制頁(yè)面。
接下來我們要實(shí)現(xiàn)的功能就是如何讓蛇動(dòng)起來,這樣才是一個(gè)游戲嘛
那么如何讓蛇動(dòng)起來呢,其實(shí)很簡(jiǎn)單,就是不停的繪制頁(yè)面,繪制蛇在不同位置的頁(yè)面,這樣就可以繪制出蛇動(dòng)的效果了。
如何不停的繪制頁(yè)面呢,這里只要啟動(dòng)一個(gè)線程,不停的發(fā)送消息就可以了,告訴頁(yè)面要重新繪制。

這里分析下控制流程
貪吃蛇游戲默認(rèn)有個(gè)移動(dòng)方向,比如上,用戶可以操作上下左右改變方向。
所以這里定義一個(gè)操作類,用于記錄用戶的操作。
上下左右是默認(rèn)值,可以用枚舉實(shí)現(xiàn),更適合

public enum  Control {
  UP,DOWN,LEFT,RIGHT
}

這里簡(jiǎn)單分析下用戶操作時(shí)候發(fā)生的變化。
蛇默認(rèn)會(huì)在收到消息之后往上走一個(gè),如果用戶做了一個(gè)轉(zhuǎn)左的操作,那么蛇的下一步就是往左走一個(gè),實(shí)際上蛇每次都是按一個(gè)固定方向行走的,那么我們寫代碼的時(shí)候只要實(shí)現(xiàn)一個(gè)方法是根據(jù)下一步方向來繪制蛇就行,而用戶的操作僅僅只是告訴View下一步的方向是什么。
這樣做的一個(gè)好處就是,把操作分割開了,便于實(shí)現(xiàn),用戶的操作只是告訴了View去改變方向,而蛇每次的真正移動(dòng)只是根據(jù)線程消息移動(dòng),這兩個(gè)地方就不會(huì)相互影響了。

好了現(xiàn)在我們來實(shí)現(xiàn)這個(gè)步驟
我們定義一個(gè)Control對(duì)象記錄用戶下一步要走的方向。
我們刷新頁(yè)面是根據(jù)下一步走的方向去改變蛇的位置的。
private Control control = Control.UP;
然后我們看看刷新頁(yè)面時(shí)候我們要做什么。
刷新頁(yè)面說明蛇是要往前走一個(gè),根據(jù)下一步方向走。
我們?nèi)绾螌?shí)現(xiàn)蛇走下一步呢
其實(shí)這個(gè)規(guī)則很簡(jiǎn)單就是在蛇的control方向添加一個(gè)點(diǎn),然后刪除最后一個(gè)點(diǎn),這樣蛇就根據(jù)方向變化了
然后刷新頁(yè)面就ok了

  public void refreshView(boolean isAdd){
        List<PointBean> pointList = snakeBean.getSnake();
        PointBean point = pointList.get(0); 
        PointBean pointNew = null;
        if (control == Control.LEFT) {
            pointNew = new PointBean(point.getX() - 1, point.getY());
        } else if (control == Control.RIGHT) {
            pointNew = new PointBean(point.getX() + 1, point.getY());
        } else if (control == Control.UP) {
            pointNew = new PointBean(point.getX(), point.getY() - 1);
        } else if (control == Control.DOWN) {
            pointNew = new PointBean(point.getX(), point.getY() + 1);
        }
        if (pointNew != null) {
            pointList.add(0, pointNew);
            if(!isAdd){
                pointList.remove(pointList.get(pointList.size() - 1));
            }
        }

        invalidate();
        //此處只是刷新頁(yè)面
        //刷新頁(yè)面會(huì)重新繪制
    }

這個(gè)就是刷新頁(yè)面的方法了
里面的規(guī)則就是根據(jù)位置確定下一個(gè)頂點(diǎn)的位置,然后把這個(gè)新的頂點(diǎn)添加到蛇的頭部,刪除蛇的尾部就可以了。邏輯是不是很清晰?
這樣蛇就從上一個(gè)位置移動(dòng)到下一個(gè)位置了。
現(xiàn)在就開啟線程不停的調(diào)用刷新方法蛇就可以動(dòng)起來了。
下面給出開啟線程的代碼

public class MainActivity extends AppCompatActivity {
    public static final int WHAT_REFRESH = 200;
    private GameView gameView;
    private Handler handler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            if(WHAT_REFRESH == msg.what){
                gameView.refreshView(false);
                sendControlMessage();
            }
        }
    };
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        gameView = new GameView(this);
        setContentView(gameView);
        sendControlMessage();
    }
    private void sendControlMessage(){
        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                handler.sendEmptyMessage(WHAT_REFRESH);
            }
        },300);
    }
} 

這段代碼只是不停的調(diào)用線程每300 毫秒告訴一次View要刷新頁(yè)面
此時(shí)View的完整代碼是這個(gè)

public class GameView extends View {
    private Paint paint = new Paint();

    private GridBean gridBean;
    private SnakeBean snakeBean;

    private Control control = Control.UP;
    public GameView(Context context) {
        super(context);
        init();

    }

    public GameView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    private void init() {
        gridBean = new GridBean();//創(chuàng)建格子對(duì)象,畫格子時(shí)候使用
        snakeBean = new SnakeBean();//創(chuàng)建一個(gè)蛇對(duì)象。這時(shí)候蛇對(duì)象是空的,我們需要初始化一個(gè)值

        PointBean pointBean = new PointBean(gridBean.getGridSize()/2,gridBean.getGridSize()/2);
        snakeBean.getSnake().add(pointBean);//定義一個(gè)中心點(diǎn) ,添加到蛇身上
    }

    @Override
    protected void onDraw(Canvas canvas) {
        if (gridBean != null) {
            paint.setColor(Color.RED);
            drawGrid(canvas);
        }
        if (snakeBean != null) {
            paint.setColor(Color.GREEN);
            drawSnake(canvas);
        }
    }

    private void drawSnake(Canvas canvas) {
        List<PointBean> snake = snakeBean.getSnake();
        for (PointBean point : snake) {
            int startX = gridBean.getOffset() + gridBean.getGridWidth() * point.getX();
            int stopX = startX + gridBean.getGridWidth();
            int startY = gridBean.getOffset() + gridBean.getGridWidth() * point.getY();
            int stopY = startY + +gridBean.getGridWidth();
            canvas.drawRect(startX, startY, stopX, stopY, paint);
        }
    }

    private void drawGrid(Canvas canvas) {
        //畫豎線
        for (int i = 0; i <= gridBean.getGridSize(); i++) {
            int startX = gridBean.getOffset() + gridBean.getGridWidth() * i;
            int stopX = startX;
            int startY = gridBean.getOffset();//+gridBean.getGridWidth() * i
            int stopY = startY + gridBean.getLineLength();//
            canvas.drawLine(startX, startY, stopX, stopY, paint);
        }
        //畫橫線
        for (int i = 0; i <= gridBean.getGridSize(); i++) {
            int startX = gridBean.getOffset();//+gridBean.getGridWidth() * i
            int stopX = startX + gridBean.getLineLength();

            int startY = gridBean.getOffset() + gridBean.getGridWidth() * i;
            int stopY = startY;
            canvas.drawLine(startX, startY, stopX, stopY, paint);
        }
    }

    public void refreshView(boolean isAdd){
        List<PointBean> pointList = snakeBean.getSnake();
        PointBean point = pointList.get(0);
        PointBean pointNew = null;
        if (control == Control.LEFT) {
            pointNew = new PointBean(point.getX() - 1, point.getY());
        } else if (control == Control.RIGHT) {
            pointNew = new PointBean(point.getX() + 1, point.getY());
        } else if (control == Control.UP) {
            pointNew = new PointBean(point.getX(), point.getY() - 1);
        } else if (control == Control.DOWN) {
            pointNew = new PointBean(point.getX(), point.getY() + 1);
        }
        if (pointNew != null) {
            pointList.add(0, pointNew);
            if(!isAdd){
                pointList.remove(pointList.get(pointList.size() - 1));
            }
        }

        invalidate();
        //此處只是刷新頁(yè)面
        //刷新頁(yè)面會(huì)重新繪制
    }
}

運(yùn)行的小伙伴有沒有發(fā)現(xiàn),蛇跑出格子了,沒錯(cuò)這里沒有加任何的判斷,蛇會(huì)一直往上走。
這里我們要做的就是添加一個(gè)判斷結(jié)束的方法
這里只簡(jiǎn)單寫一個(gè)判斷蛇越界算輸?shù)姆椒ǎ』锇榭梢宰约和晟祈?xiàng)目做更多的判斷輸贏

  private boolean isFailed( PointBean point){
        if (point.getX() == 0 && control == Control.UP ) { 
            return true;
        } else if ( point.getY()  == 0 && control == Control.LEFT) {
            return true;
        } else if (point.getX() == gridBean.getGridSize() - 1 && control == Control.DOWN  ) {
            return true;
        } else if (point.getY() == gridBean.getGridSize() - 1 && control == Control.RIGHT ) {
            return true;
        }
        return false;
    }

下面我們要為游戲添加手勢(shì)了喲
這個(gè)地方其實(shí)網(wǎng)上很多地方都有,就是獲取滑動(dòng)方向的,
獲取完方向如何使用呢。因?yàn)橹坝昧藗€(gè)小技巧,這里其實(shí)做的就是改變之前control的值而已,沒有其他任何操作,直接上代碼

  int x;
    int y;
    @Override
    public boolean onTouchEvent(MotionEvent event) { //通過手勢(shì)來改變蛇體運(yùn)動(dòng)方向 
        int action = event.getAction()  & MotionEvent.ACTION_MASK;
        LogUtil.e("x =" + x + " y = " + y + " action() = " + action);
        // TODO Auto-generated method stub
        if (action == KeyEvent.ACTION_DOWN) {
            //每次Down事件,都置為Null
            x = (int) (event.getX());
            y = (int) (event.getY());
        }
        if (action== KeyEvent.ACTION_UP) {
            //每次Down事件,都置為Null
            int x = (int) (event.getX());
            int y = (int) (event.getY());

//            新建一個(gè)滑動(dòng)方向,
            Control control  = null ;
            // 滑動(dòng)方向x軸大說明滑動(dòng)方向?yàn)?左右
            if (Math.abs(x - this.x) > Math.abs(y - this.y)) {
                if (x > this.x) {
                    control = Control.RIGHT;
                    LogUtil.i("用戶右劃了");
                }
                if (x < this.x) {
                    control = Control.LEFT;
                    LogUtil.i("用戶左劃了");
                }
            }else{
                if (y < this.y) {
                    control = Control.UP;
                    LogUtil.i("用戶上劃了");
                }
                if (y > this.y) {
                    control = Control.DOWN;
                    LogUtil.i("用戶下劃了");
                }
            }

            if (this.control == Control.UP || this.control == Control.DOWN) {
                if(control==Control.UP ||Control.UP==Control.DOWN ){
                    LogUtil.i("已經(jīng)是上下移動(dòng)了,滑動(dòng)無效");
                }else{
                    this.control = control;
                }
            } else if (this.control == Control.LEFT || this.control == Control.RIGHT) {
                if(control==Control.LEFT ||Control.UP==Control.RIGHT ){
                    LogUtil.i("已經(jīng)是左右移動(dòng)了,滑動(dòng)無效");
                }else{
                    this.control = control;
                }
            }
        }
        //Log.e(TAG, "after adjust mSnakeDirection = " + mSnakeDirection);
        return super.onTouchEvent(event);
    }

代碼有點(diǎn)多
簡(jiǎn)單分析下,
根據(jù)用戶手指落下 和抬起位置的差值,計(jì)算用戶是哪個(gè)方向滑動(dòng)了。
如果用戶滑滑動(dòng)方向是左 判斷用戶是否可以左滑,比如用戶之前是往右是不允許左劃的 ,滑動(dòng)也不會(huì)有任何處理。這里就是幾個(gè)簡(jiǎn)單判斷,實(shí)際使用的就是 把Control的方向改為用戶滑動(dòng)成功的方向。
這樣整個(gè)程序基本就做完了。
剩下的就是優(yōu)化項(xiàng)目了,第一個(gè)就是現(xiàn)在程序的蛇只有一個(gè)點(diǎn),我們希望蛇是不斷增加的
那么我們可以設(shè)置一個(gè)方法讓蛇 在一段時(shí)間就增加一個(gè)格子 也可以隨機(jī)生成一個(gè) 點(diǎn),然后蛇碰到這個(gè)點(diǎn)就增加一個(gè)一個(gè)點(diǎn),第二個(gè)就是速度問題,我們希望隨著時(shí)間的推移蛇越來越快
這里我先設(shè)置個(gè)計(jì)步器,count 每20步 我就讓蛇添加1格

https://github.com/zujianhua/Snake
完整源碼發(fā)布到Github上,如有問題請(qǐng)指正。
歡迎加上面的群來交流

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,461評(píng)論 6 532
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,538評(píng)論 3 417
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,423評(píng)論 0 375
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,991評(píng)論 1 312
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,761評(píng)論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,207評(píng)論 1 324
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,268評(píng)論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,419評(píng)論 0 288
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,959評(píng)論 1 335
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,782評(píng)論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,983評(píng)論 1 369
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,528評(píng)論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,222評(píng)論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,653評(píng)論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,901評(píng)論 1 286
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,678評(píng)論 3 392
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,978評(píng)論 2 374

推薦閱讀更多精彩內(nèi)容