拆輪子-唯美細膩的夕陽海浪動畫

本文鏈接http://immortalz.me/559.html 轉(zhuǎn)載請注明

好久沒有寫博客了,一直在彌補基礎(chǔ)堤框, 今天帶來的是一個博主有史以來見過最最精美的動畫效果了域滥。所以我才迫不及待的拆輪子纵柿。今天拆的部分是如下的效果。

sp161007_111657.png

無圖無真相呀

這里寫圖片描述

前人種樹启绰,后人乘涼昂儒。很早的時候大神CJJ關(guān)于這個庫的一些分析,大家可以去看看委可。

http://www.reibang.com/p/a4dabb3554c1

不過由于該文章中對于動畫的具體實現(xiàn)沒有提及渊跋,所以才有這篇文章的存在了=.=

這里寫圖片描述

因為本人水平不咋地,先奉上
這個庫的下載地址
https://github.com/danielzeller/Depth-LIB-Android-

大家如果之前接觸過類似的效果着倾,其實也就沒有必要看下去啦=.=


好了拾酝,廢話說了這么多,如果有興趣往下看屈呕,就繼續(xù)吧微宝!

一.說明

因為代碼已經(jīng)存在,所以我認為就沒有必要照著代碼一點點講虎眨,感覺這樣的方式更容易把讀者弄得云里霧里的,所以我這里決定從零開始一步步來實現(xiàn)這個效果(當(dāng)然因為我是先仔細看了一遍代碼的镶摘,所以你懂的)

這個地址是本文的代碼(基本都是從原來的庫取出來的,只不過精簡了些)凄敢,大家閱讀前也可以去下載看看扑庞。
本文demo 下載地址:https://github.com/ImmortalZ/Learn_Depth

二.分析

通過上面的效果圖罐氨,我們看到我們要實現(xiàn)的這樣的效果需要攻破幾個難關(guān)

1.水的背景波浪是浪起來的?
2.水面上的波紋是如何看起來隨機產(chǎn)生并且粗細不同的租悄?

答1:這里的背景波浪不同平常于我們經(jīng)常看到別人發(fā)的用正弦函數(shù)+三次貝塞爾曲線形成的這種效果

這里寫圖片描述

這篇博客有講這種效果的實現(xiàn)

我們可以注意到整個背景有一種被扭曲的效果纪吮,背景的色彩呈現(xiàn)擠壓然后釋放然后擠壓這種效果碾盟。

這里寫圖片描述

想要實現(xiàn)我們的這種效果,我們這里需要一個我們較少使用的方法canvas.drawBitmapMesh

答2:對于第二個問題熙尉,我想留在后面適當(dāng)?shù)奈恢迷訇U述。

知識點 drawBitmapMesh 補充

網(wǎng)上關(guān)于drawBitmapMesh這個知識點铅歼,有兩位大神已經(jīng)很好的用牛逼的例子說明了。
地址在這:

Android 吸入動畫效果實現(xiàn)分解

初學(xué)Android,圖形圖像之使用drawBitmapMesh扭曲圖像(三十二)

我就提煉出一些精要的東西好了

這里寫圖片描述
這里寫圖片描述

好了,假定你已經(jīng)知道drawBitmapMesh的大致用法了瓤的。

三.實現(xiàn)##

有了上面的分析圈膏,我們就開始一步步來實現(xiàn)吧
整個項目的工程如下

這里寫圖片描述

3.1先來介紹Renderable

這里寫圖片描述

可以看到Renderable很簡單医增。我們的Water類繼承自Renderable

3.2 Water類

然后我們創(chuàng)建Water類茫多,用來承載整個海浪的效果(背景大波浪+波紋)

3.2.1 實現(xiàn)背景大波浪的效果

為了避免混淆天揖,我把實現(xiàn)波紋的效果給注釋掉了些阅,

public class Water extends Renderable {

    private float mWidth;
    private float mHeight;
    private PathBitmapMesh mWaterMesh;
    private float mWaveHeight;
    private Path mWaterPath = new Path();
    private int mNumWaves;
    /*private Foam[] foams = new Foam[1];
    long lastEmit;
    private int emitInterWall = 1000;*/

    /**
     *
     * @param water water圖像
     * @param foam 海浪圖像
     * @param y 海浪起始左上角坐標的y值
     * @param width 海浪顯示的寬度
     * @param height 海浪顯示的高度
     * @param numWaves 海浪整個寬度被分成多少份
     */
    public Water(Bitmap water, Bitmap foam, float y, float width, float height, int numWaves) {
        super(water, 0, y);
        mWidth = width;
        mHeight = height;
        mWaterMesh = new PathBitmapMesh(water, 1500);
        mWaveHeight = height / 20;
        mNumWaves = numWaves;
        /*foams[0] = new Foam(PathBitmapMesh.HORIZONTAL_COUNT, foam, 0, height / 12, 1500);
        foams[1] = new Foam(PathBitmapMesh.HORIZONTAL_COUNT, foam, -height / 5, height / 5, 1500);
        foams[1].setAlpha(100);
        foams[2] = new Foam(PathBitmapMesh.HORIZONTAL_COUNT, foam, -height / 12, height / 12, 1450);
        foams[2].setVerticalOffset(height / 7);
        foams[3] = new Foam(PathBitmapMesh.HORIZONTAL_COUNT, foam, -height / 12, height / 12, 1400);
        foams[3].setVerticalOffset(height / 4);
        lastEmit = System.currentTimeMillis();*/
        createPath();
    }

    private void createPath() {
        mWaterPath.reset();
        mWaterPath.moveTo(0, y);
        int step = (int) (mWidth / mNumWaves);
        boolean changeDirection = true;
        for (int i = 0; i < mNumWaves; i++) {
            if (changeDirection) {
                mWaterPath.cubicTo(x + step * i, y, x + step * i + step / 2f, y + mWaveHeight, x + step * i + step, y);
            } else {
                mWaterPath.cubicTo(x + step * i, y, x + step * i + step / 2f, y - mWaveHeight, x + step * i + step, y);
            }
            changeDirection = !changeDirection;
        }
    }

    @Override
    public void draw(Canvas canvas) {
        mWaterMesh.draw(canvas);
        /*for (Foam foam : foams) {
            foam.draw(canvas);
        }*/
    }

    @Override
    public void update(float deltaTime) {
        mWaterMesh.matchVertsToPath(mWaterPath, mHeight, ((bitmap.getWidth() / mNumWaves) * 4f));
        /*for (Foam foam : foams) {
            foam.update(deltaTime);
        }
        for (Foam foam : foams) {
            foam.matchVertsToPath(mWaterPath, ((foam.getBitmap().getWidth() / mNumWaves) * 4f));
        }
        if (lastEmit + emitInterWall < System.currentTimeMillis()) {
            for (Foam foam : foams) {
                foam.calcWave();
            }
            lastEmit = System.currentTimeMillis();
        }*/
    }
}

先介紹createPath這個方法恕刘,這里面利用cubicTo創(chuàng)建了一個三次貝塞爾曲線褐着,目的就是:我們知道圖像扭曲時的寬度是大于二維圖像平面的寬度的频敛。
所以我們這里一條多個三次貝塞爾曲線形成的曲線來模擬圖像扭曲時的寬度
這樣說比較抽象,大致想表達的就是紅色來模擬圖像扭曲時的長度

這里寫圖片描述

createPath這個方法中有個有趣的參數(shù)mNumWaves鹊碍,這個用來表示海浪整個寬度被分成多少份(這個例子中我們把海浪分成了6份)侈咕。

那我們就來分析我們的背景大波浪的形成辦法楼眷。

按照上面drawBitmapMesh的講解,我們要想形成大波浪张吉,就需要計算出Mesh格子各個頂點的坐標(事實上這也是最最關(guān)鍵的一步勺择,知道了這一步后面的都是小菜J『恕)
這里我們把海浪寬度分成了6份,高度分成了1份來處理笔刹。所以我們需要處理的頂點個數(shù)就是
(6+1)*(1+1) = 14(圖中14個黑點)

這里寫圖片描述

然后我們接下來的工作就是計算著14個點的坐標!
這里就是PathBitmapMesh類需要完成的工作了日月。
(注釋部分先忽略,后面再說)

public class PathBitmapMesh {

    protected static int HORIZONTAL_COUNT = 6;//水平方向分片數(shù)
    protected static int VERTICAL_COUNT = 1;//垂直方向分片
    private int mTotalCount;//總共需要計算的網(wǎng)格頂點個數(shù)
    protected Bitmap bitmap;
    protected float[] drawingVerts;//需要繪制的Verts網(wǎng)格坐標
    protected float[] staticVerts;//最初始的Verts網(wǎng)格坐標
    private Paint mPaint = new Paint();
    //private ValueAnimator mValueAnimator;
    //protected float pathOffsetPercent;
    protected float[] coordsX = new float[2];
    protected float[] coordsY = new float[2];

    public PathBitmapMesh(Bitmap bitmap, long duration) {
        mTotalCount = (HORIZONTAL_COUNT + 1) * (VERTICAL_COUNT + 1);
        drawingVerts = new float[mTotalCount * 2];
        staticVerts = new float[mTotalCount * 2];
        this.bitmap = bitmap;
        initVert();
        //startValuesAnim(duration);
    }

    /*private void startValuesAnim(long duration) {
        mValueAnimator = ValueAnimator.ofFloat(0, 0.3334f);
        mValueAnimator.setDuration(duration);
        mValueAnimator.setRepeatCount(ValueAnimator.INFINITE);
        mValueAnimator.setRepeatMode(ValueAnimator.RESTART);
        mValueAnimator.setInterpolator(new LinearInterpolator());
        mValueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                pathOffsetPercent = (float) animation.getAnimatedValue();
            }
        });
        mValueAnimator.start();
    }*/

    private void initVert() {
        float bitmapWidth = (float) bitmap.getWidth();
        float bitmapHeight = (float) bitmap.getHeight();
        int index = 0;
        for (int y = 0; y <= VERTICAL_COUNT; y++) {
            float fy = bitmapHeight / VERTICAL_COUNT * y;
            for (int x = 0; x <= HORIZONTAL_COUNT; x++) {
                float fx = bitmapWidth / HORIZONTAL_COUNT * x;
                setXY(drawingVerts, index, fx, fy);
                setXY(staticVerts, index, fx, fy);
                index++;
            }
        }
    }

    protected void setXY(float[] arrys, int index, float x, float y) {
        arrys[2 * index] = x;
        arrys[2 * index + 1] = y;
    }

    public void matchVertsToPath(Path path, float bottomY, float extraOffset) {
        PathMeasure pm = new PathMeasure(path, false);
        for (int i = 0; i < staticVerts.length / 2; i++) {
            float orignX = staticVerts[2 * i];
            float orignY = staticVerts[2 * i + 1];
            float percentOffsetX = orignX / bitmap.getWidth();
            float percentOffsetY = orignX / (bitmap.getWidth() + extraOffset);
            //percentOffsetY += pathOffsetPercent;
            pm.getPosTan(pm.getLength() * (percentOffsetX), coordsX, null);
            pm.getPosTan(pm.getLength() * (percentOffsetY), coordsY, null);
            if (orignY == 0) {
                setXY(drawingVerts, i, coordsX[0], coordsY[1]);
            } else {
                setXY(drawingVerts, i, coordsX[0], bottomY);
            }
        }
    }

    public void draw(Canvas canvas) {
        canvas.drawBitmapMesh(bitmap, HORIZONTAL_COUNT, VERTICAL_COUNT, drawingVerts, 0, null, 0, mPaint);
    }

    public Bitmap getBitmap() {
        return bitmap;
    }

    public void setAlpha(int alpha) {
        mPaint.setAlpha(alpha);
    }
}

可以看到initVert()進行了drawingVerts蜂绎,staticVerts兩個記錄頂點坐標數(shù)組初始化工作。
draw方法中直接調(diào)用drawBitmapMesh完成扭曲圖像的繪制。
本文鏈接http://immortalz.me/559.html 轉(zhuǎn)載請注明
重點在于matchVertsToPath方法找岖!

這里寫圖片描述

上面說過了,我們用一條多個三次貝塞爾曲線形成的曲線來模擬圖像扭曲時的寬度帖旨。那我們怎么來取得這條曲線上任一點的坐標呢箕昭?答案就是PathMeasure。我們可以通過該函數(shù)的getPosTan方法解阅,通過給定曲線的某一長度落竹,得到該點的坐標。

例如:pm.getPosTan(pm.getLength() * (percentOffsetX), coordsX, null);

pm.getLength()得到整條曲線長度货抄,percentOffsetX得到曲線上比例值述召,最后把得到的坐標返回給coordsX數(shù)組。

這里寫圖片描述

假設(shè)我們的bitmap寬度為60蟹地,這里我們把整個圖像分成了6份遍愿,以A點舉例。
percentOffsetX = 1/6曲管;
因為我們在繪制path時是以整個圖像顯示的寬度作為標準的,而不是bitmap的寬度胰默。
所以我們的path長度不等于bitmap的寬度挺据,這也就是為什么bitmap的寬度很小白嘁,卻能鋪滿整個屏幕的寬度

這里寫圖片描述

如果path的長度為600策肝,那么A的y值也就是coordsX[0] = 600*1/6=100
通過這樣的方法我們就可以得到14個頂點的坐標


細心的朋友會發(fā)現(xiàn),那這樣我們有一個percentOffsetX也好了呀蛀醉,為啥需要percentOffsetY奶躯?
(percentOffsetX字面理解為X方向偏移占據(jù)比例)
如果我們試著把extraOffset給注釋掉

這里寫圖片描述

那么運行的效果就是

這里寫圖片描述

你也許會想不會呀开呐,明明我們的path是三次貝塞爾曲線丛塌,不是彎的嗎?怎么直了!
原因就是:path只是用來模擬圖像扭曲時寬度播揪,并不是真正的形狀!
按照我們之前的計算結(jié)果A,B點的坐標y值都一樣谓形,所以整個圖像看起來效果是直的寒跳。

這里寫圖片描述

而如果我們加上extraOffset誓琼,用藍色點的y值來表示A,B 坐標的y值巧颈,那么就會出現(xiàn)這樣的效果了勾栗!

這里寫圖片描述

那我們怎么讓我們的波浪動起來呢?
很簡單盏筐!讓A,B第一行的七個坐標y值不斷變化即可围俘!
創(chuàng)建一個ValueAnimator,讓其循環(huán)周期的變化即可,具體大家可以看之前代碼注釋部分

這里寫圖片描述

為什么是0-1/3f呢?
很簡單琢融,還記得我們設(shè)置的extraOffset=((bitmap.getWidth() / mNumWaves) * 4f)界牡;
也就是extraOffset = w/62 = 2w/3; (w表示bitmap.getWidth())

這里寫圖片描述
這里寫圖片描述

那么代入計算得到A點的percentOffsetY = 1/(w+2w/3)=3w/5(也就是A'的y位置)
我們要想讓波浪形成一個周期,很明顯吏奸,讓A'運動至A''即可
得到A''-A'=w/3
所以ValueAnimator.ofFloat(0, 1 / 3f)

進行到欢揖,大波浪終于算是完成了!

這里寫圖片描述

3.2.1 實現(xiàn)水紋效果
有了前面大波浪的經(jīng)驗奋蔚,我們實現(xiàn)水紋應(yīng)該更簡單了她混!因為原理類似呀!
首先創(chuàng)建一個類Foam 繼承自 PathBitmapMesh (意味著我們可以復(fù)用PathBitmapMesh里面的東西)

public class Foam extends PathBitmapMesh {

    private float[] foamCoords;
    private float[] easedFoamCoords;
    private int mHorizontalSlices;//水紋水平方向分片
    private float minHeight;//水紋最小高度
    private float maxHeight;//水紋最大高度
    private float verticalOffset;

    public Foam(int horizontalSlices, Bitmap bitmap, float minHeight, float maxHeight, long duration) {
        super(bitmap, duration);
        mHorizontalSlices = horizontalSlices;
        this.minHeight = minHeight;
        this.maxHeight = maxHeight;
        init();
    }

    private void init() {
        foamCoords = new float[mHorizontalSlices];
        easedFoamCoords = new float[mHorizontalSlices];
        for (int i = 0; i < mHorizontalSlices; i++) {
            foamCoords[i] = 0;
            easedFoamCoords[i] = 0;
        }
    }

    /**
     * 隨著時間的流逝不斷更改
     * @param deltaTime
     */
    public void update(float deltaTime) {
        for (int i = 0; i < foamCoords.length; i++) {
            easedFoamCoords[i] += ((foamCoords[i] - easedFoamCoords[i])) * deltaTime;
        }
    }

    /**
     * 根據(jù)傳入的最低泊碑,最高高度得到一個適合的高度
     */
    public void calcWave() {
        for (int i = 0; i < foamCoords.length; i++) {
            foamCoords[i] = MathHelper.randomRange(minHeight, maxHeight);
        }
    }

    /**
     * 計算水紋的各個頂點坐標
     * @param path
     * @param extraOffset
     */
    public void matchVertsToPath(Path path, float extraOffset) {
        PathMeasure pm = new PathMeasure(path, false);
        int index = 0;
        for (int i = 0; i < staticVerts.length / 2; i++) {
            float orignX = staticVerts[2 * i];
            float orignY = staticVerts[2 * i + 1];
            float percentOffsetX = orignX / bitmap.getWidth();
            float percentOffsetY = orignX / (bitmap.getWidth() + extraOffset);
            percentOffsetY += pathOffsetPercent;
            pm.getPosTan(pm.getLength() * percentOffsetX, coordsX, null);
            pm.getPosTan(pm.getLength() * percentOffsetY, coordsY, null);
            if (orignY == 0) {
                setXY(drawingVerts, i, coordsX[0], coordsY[1]+verticalOffset);
            } else {
                float desiredYCoord = Math.max(coordsY[1], coordsY[1] + easedFoamCoords[Math.min(easedFoamCoords.length - 1, index)]);
                setXY(drawingVerts, i, coordsX[0], desiredYCoord+verticalOffset);
                index += 1;
            }
        }
    }

    public void setVerticalOffset(float verticalOffset) {
        this.verticalOffset = verticalOffset;
    }
}

還是重點來看matchVertsToPath方法

這里寫圖片描述

這里我畫了一個水紋的簡圖(藍色的線所圍成)

這里寫圖片描述

可以看到對于第一排坐標就是跟隨者大波浪的坐標即可

這里寫圖片描述

我們需要改變的是第二排的坐標y值坤按,這里就根據(jù)我們傳入的minHeight,maxHeight計算所得(具體計算方式也好理解,可以看代碼馒过,我們實際上的計算方式可以不按照原代碼的臭脓,只需要y值不一樣即可)
參量verticalOffset我們可以設(shè)定水紋的起始高度,這樣通過修改verticalOffset值腹忽,我們可以讓多個水紋在垂直高度不同位置顯示来累。
最后實現(xiàn)的效果就是(把Water代碼注釋部分去掉)因為圖像就是扭曲的,水紋給我們的感覺就像是隨機產(chǎn)生窘奏,又水紋每一份頂點的y值不同嘹锁,所以就粗細不同了。

這里寫圖片描述

注意着裹,因為我們的大波浪頂點的高度是需要時刻變化的领猾,而水紋的高度并不需要時刻變化,只需要每隔一段時間變化即可骇扇,所以我們可以設(shè)置讓水紋的高度每隔1秒計算變化一次

這里寫圖片描述

四.合成##

通過上面的分析摔竿,我們已經(jīng)成功掌握了大波浪+水紋實現(xiàn)的原理,最后再創(chuàng)建WaterScreenView類少孝,把背景山和太陽的光輝加上继低,就完美實現(xiàn)了!

public class WaterScreenView extends View {

    private Water mWater;
    private Renderable[] mRenderables;

    public WaterScreenView(Context context) {
        super(context);
    }

    public WaterScreenView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public WaterScreenView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @Override
    protected void onAttachedToWindow() {
        super.onAttachedToWindow();
        if (mRenderables == null && getWidth() != 0) {
            init();
        }
    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);
        if (mRenderables == null) {
            init();
        }
    }

    private void init() {
        mRenderables = new Renderable[1];
        Bitmap waterBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.water);
        Bitmap foam = BitmapFactory.decodeResource(getResources(), R.drawable.foam);
        setLayerType(View.LAYER_TYPE_HARDWARE, null);
        mWater = new Water(waterBitmap, foam, getHeight() * 0.65f, getWidth(), getHeight(), 6);
        mRenderables[0] = mWater;
        Bitmap aura = BitmapFactory.decodeResource(getResources(), R.drawable.sun_aura);
        mRenderables[1] = new Renderable(aura, getWidth() * 0.5f, getHeight() * 0.35f);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        float deltaTime = FrameRateCounter.timeStep();

        for (Renderable renderable : mRenderables) {
            renderable.draw(canvas);
            renderable.update(deltaTime);
        }
        if (!isPause) {
            invalidate();
        }
    }

    private boolean isPause = false;
}

最終效果:

這里寫圖片描述

五.結(jié)尾##

嘩啦啦的寫了這么多稍走,畫圖好累呀郁季。原效果中的噪聲效果還沒有來得及分享冷溃,一篇文章內(nèi)容太多就太亂了。
總而言之梦裂,就是好好利用drawBitmapMesh這個牛逼的東東吧
有機會分享給大家怎么利用drawBitmapMesh讓這個圖像的屁股扭動起來!

這里寫圖片描述

嗯盖淡,我就是ImmortalZ,一個Android小菜鳥年柠,歡迎大家一起學(xué)習(xí)。

六.下載##

原裝效果代碼下載地址:
https://github.com/danielzeller/Depth-LIB-Android-

本次拆輪子精簡版代碼下載地址:https://github.com/ImmortalZ/Learn_Depth

歡迎star,如果對我感興趣褪迟,可以follow哦冗恨!

本文來自個人博客 http://immortalz.me/559.html

聯(lián)系方式
我的微信

這里寫圖片描述

我的微博:
http://weibo.com/u/1956502961

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市味赃,隨后出現(xiàn)的幾起案子掀抹,更是在濱河造成了極大的恐慌,老刑警劉巖心俗,帶你破解...
    沈念sama閱讀 211,265評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件傲武,死亡現(xiàn)場離奇詭異,居然都是意外死亡城榛,警方通過查閱死者的電腦和手機揪利,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,078評論 2 385
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來狠持,“玉大人疟位,你說我怎么就攤上這事〈梗” “怎么了甜刻?”我有些...
    開封第一講書人閱讀 156,852評論 0 347
  • 文/不壞的土叔 我叫張陵,是天一觀的道長正勒。 經(jīng)常有香客問我得院,道長,這世上最難降的妖魔是什么昭齐? 我笑而不...
    開封第一講書人閱讀 56,408評論 1 283
  • 正文 為了忘掉前任尿招,我火速辦了婚禮,結(jié)果婚禮上阱驾,老公的妹妹穿的比我還像新娘就谜。我一直安慰自己,他們只是感情好里覆,可當(dāng)我...
    茶點故事閱讀 65,445評論 5 384
  • 文/花漫 我一把揭開白布丧荐。 她就那樣靜靜地躺著,像睡著了一般喧枷。 火紅的嫁衣襯著肌膚如雪虹统。 梳的紋絲不亂的頭發(fā)上弓坞,一...
    開封第一講書人閱讀 49,772評論 1 290
  • 那天,我揣著相機與錄音车荔,去河邊找鬼渡冻。 笑死,一個胖子當(dāng)著我的面吹牛忧便,可吹牛的內(nèi)容都是我干的族吻。 我是一名探鬼主播,決...
    沈念sama閱讀 38,921評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼珠增,長吁一口氣:“原來是場噩夢啊……” “哼超歌!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起蒂教,我...
    開封第一講書人閱讀 37,688評論 0 266
  • 序言:老撾萬榮一對情侶失蹤巍举,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后凝垛,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體懊悯,經(jīng)...
    沈念sama閱讀 44,130評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,467評論 2 325
  • 正文 我和宋清朗相戀三年苔严,在試婚紗的時候發(fā)現(xiàn)自己被綠了定枷。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,617評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡届氢,死狀恐怖欠窒,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情退子,我是刑警寧澤岖妄,帶...
    沈念sama閱讀 34,276評論 4 329
  • 正文 年R本政府宣布,位于F島的核電站寂祥,受9級特大地震影響荐虐,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜丸凭,卻給世界環(huán)境...
    茶點故事閱讀 39,882評論 3 312
  • 文/蒙蒙 一福扬、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧惜犀,春花似錦铛碑、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,740評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至莉御,卻和暖如春撇吞,著一層夾襖步出監(jiān)牢的瞬間俗冻,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,967評論 1 265
  • 我被黑心中介騙來泰國打工牍颈, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留迄薄,地道東北人。 一個月前我還...
    沈念sama閱讀 46,315評論 2 360
  • 正文 我出身青樓煮岁,卻偏偏與公主長得像噪奄,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子人乓,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,486評論 2 348

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