Pomelo Treasures

需求分析

  • 玩家進(jìn)入遍布寶物的地圖中忆矛,通過拾取寶物獲取積分皇帮。
  • 玩家積分排行
  • 每個玩家的行動對其它玩家都是實時的
  • 拾取寶物獲得積分時會實時更新積分排行榜亚兄,更新對所有玩家實時可見礼旅。
  • 寶物定時刷新

應(yīng)用目錄結(jié)構(gòu)

文件 描述
domain domain表示數(shù)據(jù)和模型,比如玩家、寶物、移動等抄课。

domain中的數(shù)據(jù)需要被序列化攒盈,因此需要定義序列化方法,比如toJSON。

domain中存在entity.js文件姿鸿,entity是一個抽象的bean笋熬,意味著entity只是作為子bean的模板并不會被實例化,它會通過對象屬性依賴注入到數(shù)值接口類中。

player作為entity的子類,通過在metadata配置中的parent繼承了entity的prototype原型中的方法。

游戲服務(wù)器

網(wǎng)關(guān)服務(wù)器

連接服務(wù)器

  • 創(chuàng)建連接服務(wù)器
    連接服務(wù)器用于和客戶端通訊,,要于客戶端通信需建立一臺前端服務(wù)器,用來維護(hù)與客戶端的連接捶枢。

  • 處理客戶端請求

場景服務(wù)器

  • 場景服務(wù)器時游戲場景在服務(wù)端的抽象蒜鸡,根據(jù)游戲類型和內(nèi)容不同其復(fù)雜度千差萬別畜眨。
  • 場景構(gòu)成是一張開放的地圖昼牛,地圖中的存在玩家與定時刷新的寶物。
  • 場景服務(wù)器要能夠存儲用戶和寶物信息辜伟,可直接使用一個放在內(nèi)存中的map存儲場景中所有的實體。
  • 將場景中中所有實體都抽象為一個Entity實體對象贪婉,放入map中。
  • 為了能操作數(shù)據(jù)需暴露對外接口

接口類型

  • 初始化接口:在init方法中設(shè)置場景信息并配置參數(shù)卢肃,同時啟動場景中的時鐘循環(huán)尤蒿。
  • 實體訪問接口:比如addEntity、removeEntity等接口用于訪問和修改場景中的實體
  • 刷新場景中的寶物:當(dāng)條件滿足時外部事件會調(diào)用該接口刷新地圖中的寶物逊脯。

使用一個無限循環(huán)的tick來驅(qū)動場景服務(wù)优质,在每個tick中更新場景中所有實體的狀態(tài)信息。

安裝依賴

創(chuàng)建項目

$ npm i -S pomelo
$ pomelo init ./treasure
$ cd treasure
$ npm-install.bat

安裝游戲服依賴組件

$ cd game-server
$ npm i -S bearcat
$ npm i -S path
$ vim game-server/package.json
{
    "name": "treasure",
    "version": "0.0.1",
    "private": false,
    "dependencies": {
        "bearcat": "^0.4.29",
        "path": "^0.12.7",
        "pomelo": "2.2.7"
    }
}

服務(wù)器配置

服務(wù)器 名稱 類型
gate 網(wǎng)關(guān)服務(wù)器 前端服務(wù)器
connector 連接服務(wù)端 前端服務(wù)器
area 地圖服務(wù)器 后端服務(wù)器
$ vim game-server/config/adminServer.json
[
    {
        "type": "gate",
        "token": "agarxhqb98rpajloaxn34ga8xrunpagkjwlaw3ruxnpaagl29w4rxn"
    },
    {
        "type": "connector",
        "token": "agarxhqb98rpajloaxn34ga8xrunpagkjwlaw3ruxnpaagl29w4rxn"
    },
    {
        "type": "area",
        "token": "agarxhqb98rpajloaxn34ga8xrunpagkjwlaw3ruxnpaagl29w4rxn"
    }
]
$ vim game-server/config/servers.json
{
  "development":{
    "gate": [
      {"id": "gate-server-1", "host": "127.0.0.1", "clientPort": 3010, "frontend": true}
    ],
    "connector": [
      {"id": "connector-server-1", "host": "127.0.0.1", "port": 3150, "clientHost": "127.0.0.1", "clientPort": 3011, "frontend": true}
    ],
    "area": [
      {"id": "area-server-1", "host": "127.0.0.1", "port": 3250}
    ]
  },
  "production":{
    "gate": [
      {"id": "gate-server-1", "host": "127.0.0.1", "clientPort": 3010, "frontend": true}
    ],
    "connector": [
      {"id": "connector-server-1", "host": "127.0.0.1", "port": 3150, "clientHost": "127.0.0.1", "clientPort": 3011, "frontend": true}
    ],
    "area": [
      {"id": "area-server-1", "host": "127.0.0.1", "port": 3250}
    ]
  }
}

容器配置

$ vim game-server/context.json
{
  "name": "treasure",
  "scan": "app"
}

應(yīng)用入口

$ vim game-server/app.js
const pomelo = require('pomelo');
const bearcat = require("bearcat");
const crc = require("crc");

//獲取元數(shù)據(jù)配置文件的絕對路徑
const abspath = require.resolve("./context.json");
//初始化IoC容器
bearcat.createApp([abspath]);
//啟動IoC容器
bearcat.start(_=>{
    console.log("bearcat ioc container started");
    //創(chuàng)建應(yīng)用
    const app = pomelo.createApp();
    //應(yīng)用設(shè)置變量
    app.set('name', 'treasure');
    //應(yīng)用配置全局服務(wù)器
    app.configure('production|development', function(){
        app.set('connectorConfig',
            {
                connector : pomelo.connectors.hybridconnector,
                heartbeat : 10,
                useDict : false,
                useProtobuf : false
            });
    });
    //路由負(fù)載均衡分配
    const loadBalance = (session, serverType, channelName)=>{
        const servers = app.getServersByType(serverType);
        if(!servers || servers.length===0){
            return false;
        }
        let index = 0;
        let id = session.get(channelName);
        if(!!id){
            index = Math.abs(crc.crc32(id.toString())) % servers.length;
        }
        if(!servers[index]){
            return false;
        }
        return servers[index].id;
    };
    //應(yīng)用配置路由
    app.route("area", (session, msg, app, callback)=>{
        let serverId = loadBalance(session, "area", "cid");
        if(!serverId){
            callback(new Error("server not exists"));
            return;
        }
        callback(null, serverId);
    });
    //開啟應(yīng)用
    app.start();
});


process.on('uncaughtException', function (err) {
  console.error(' Caught exception: ' + err.stack);
});

網(wǎng)關(guān)服務(wù)器

路由 描述
gate.gateHandler.queryEntry 獲取連接服務(wù)器對外地址和端口
$ vim game-server/app/servers/gate/handler/gateHandler.js
const pomelo = require("pomelo");
const bearcat = require("bearcat");
const path = require("path");
const crc = require("crc");

let Handler = function(){
    this.$id = path.basename(__filename, path.extname(__filename));
};

Handler.prototype.queryEntry = function(msg, session, next){
    const app = pomelo.app;
    const uid = msg.aid;
    if(!uid){
        next(null, {code:500});
        return;
    }

    const servers = app.getServersByType("connector");
    if(!servers || servers.length===0){
        next(null, {code:500});
        return;
    }

    const index = Math.abs(crc.crc32(uid.toString())) % servers.length;
    const server = servers[index];

    next(null, {code:200, data:{host:server.host, port:server.clientPort}});
};

module.exports = function(){
    return bearcat.getBean(Handler);
};

連接器服務(wù)器

路由 描述
connector.entryHandler.entry 生成用戶編號军洼,設(shè)置用戶對應(yīng)的會話巩螃,設(shè)置連接與會話的對應(yīng)關(guān)系。
$ vim game-server/app/servers/connector/handler/entryHandler.js
const bearcat = require("bearcat");
const pomelo = require("pomelo");
const path = require("path");

//ID自增產(chǎn)生器
let incId = 1;

let Handler = function(){
    this.$id = path.basename(__filename, path.extname(__filename));
};

Handler.prototype.entry = function(msg, session, next){
    const app = pomelo.app;
    //獲取參數(shù)
    const userId = msg.aid;
    const channelId = msg.cid;
    //獲取當(dāng)前服務(wù)器編號中的數(shù)字
    const serverId = app.get("serverId");
    const svrId = serverId.split("-").pop();
    //獲取唯一用戶編號
    const uid = [svrId, channelId, userId, (++incId)].join("*");
    //判斷連接是否已綁定過 todo
    //連接綁定用戶編號
    session.bind(uid);
    //設(shè)置會話參數(shù)
    session.set("cid", channelId);
    session.pushAll();
    //監(jiān)聽連接斷開
    session.on("closed", onClosed.bind(null, app));
    //返回用戶編號
    next(null, {code:200, data:{uid}});
};

const onClosed = function(session, app){
    if(session && session.uid){
        app.rpc.area.playerRemote.kick(session, app.get("serverId"), session.uid, session.get("cid"), null);
    }
};

module.exports = function(){
    return bearcat.getBean(Handler);
};

地圖服務(wù)器

Remote

playerRemote

$ vim game-server/app/servers/area/remote/playerRemote.js
const bearcat = require("bearcat");
const pomelo = require("pomelo");
const path = require("path");

let Remote = function(){
    this.$id = path.basename(__filename, path.extname(__filename));
};

Remote.prototype.kick = function(serverId, uid, channelName, callback){
    const app = pomelo.app;
    const channelService = app.get("channelService");
    const channel = channelService.getChannel(channelName, false);
    channel.leave(uid, serverId);
    channel.pushMessage("onKick", uid);
    callback(uid);
};

module.exports = function(){
    return bearcat.getBean(Remote);
};

Handler

playerHandler

$ vim game-server/app/servers/area/handler/playerHandler.js
const bearcat = require("bearcat");
const path = require("path");
const filename = path.basename(__filename, path.extname(__filename));

let Handler = function(app){
    this.app = app;
    this.areaService = null;
    this.dataService = null;
};
/**玩家進(jìn)入地圖*/
Handler.prototype.enter = function(msg, session, next){
    //獲取參數(shù)
    const playerId = msg.playerId || new Date().getTime();
    const serverId = session.frontendId;
    //console.log(session, session.frontendId);

    //隨機獲取玩家角色
    const role = this.dataService.init("role").getRandomData();
    console.log(role);
    const roleId = role.id;

    //創(chuàng)建玩家
    const player = bearcat.getBean("player", {playerId, roleId, serverId});
    console.log(player);

    //獲取地圖參數(shù)
    const area = this.dataService.init("area").getRandomData();
    console.log(area);
    const areaId = area.id;
    const width = area.width;
    const height = area.height;

    //獲取地圖服務(wù)
    const areaService = this.areaService.init({areaId, width, height});
    //console.log(areaService);

    //地圖添加隨機玩家
    let flag = areaService.addEntity(player);
    console.log(flag, areaService);
    if(!flag){
        next(new Error("fail to add user into area"), {route:msg.route, code:200});
        return;
    }
    //獲取玩家與地圖中所有實體信息
    let data = {};
    data.playerId = playerId;
    data.area = this.areaService.getAreaInfo();
    //返回地圖數(shù)據(jù)和玩家數(shù)據(jù)
    next(null, {code:200, data:data});
};


module.exports = function(app){
    let bean = {};
    bean.id = filename;
    bean.func = Handler;
    bean.args = [
        {name:"app", value:app}
    ];
    bean.props = [
        {name:"areaService", ref:"areaService"},
        {name:"dataService", ref:"dataService"},
    ];
    return bearcat.getBean(bean);
};

數(shù)值處理

創(chuàng)建數(shù)值配置文件

$ vim game-server/app/data/area.json
[
    ["地圖編號", "地圖名稱", "地圖標(biāo)識", "地圖等級", "地圖寬度", "地圖高度", "數(shù)據(jù)地址"],
    ["id", "name", "identifier", "level", "width", "height", "dataurl"],
    ["1", "Oasis", "Oasis", 0, 2200, 1201, ""]
]
$ vim game-server/app/data/role.json
[
  ["角色編號", "角色名稱", "角色標(biāo)識", "角色等級", "初始血量", "初始魔法", "初始攻擊值","初始防御值", "初始命中率", "初始閃避率","初始攻速", "初始移速","升級系數(shù)", "基礎(chǔ)經(jīng)驗值"],
  ["id", "name", "identifier", "level", "healthPoint", "magicPoint", "attackValue", "defenceValue", "hitRate", "dodgeRate", "attackSpeed", "walkSpeed", "upgradeValue","baseExp"],
  [201,"蜻蜓","Dragonfly","1",180,40,25,"8",90,15,"1",260,0.25,20],
  [202,"鳥面人","Harpy","1",60,40,15,"8",90,10,"1",160,0.3,10],
  [203,"燈泡龍","Bulb Dragon","3",15000,40,45,25,200,50,"1.8",360,0.28,2500],
  [204,"藍(lán)龍","BlueDragon","3",6000,40,40,28,90,0,0.6,180,0.27,500],
  [205,"甲蟲","Beetle","3",600,40,32,20,90,10,"1",220,0.25,55],
  [206,"椰子怪","Coconut monster","1",300,40,22,13,90,10,"1",180,0.23,30],
  [207,"石頭怪","Rock","3",800,40,32,25,70,10,0.6,180,0.25,45],
  [208,"獨角仙","Unicorn Beetle","1",1600,40,30,18,90,10,"1",200,0.24,150],
  [209,"食人花","Corpse flower","1",120,40,20,"8",90,"5","1",220,0.2,15],
  [210,"天使","Angle","1",220,20,23,"9",90,13,"1.2",240,0.3,20],
  [211,"煉金術(shù)士","Alchemist","1",180,60,18,12,95,10,"1.2",240,0.3,20]
]
$ vim game-server/app/data/treasure.json
[
  ["寶物編號","寶物名稱","寶物標(biāo)識","寶物描述","寶物類型","攻擊值","防御值","賣出價格","寶物顏色","英雄等級","圖片編號"],
  ["id","name","identifier","remark","kind","attackValue","defenceValue","price","color","heroLevel","imgId"],
  ["1","星火劍","Red tasselled pear","攻擊力","Weapon",33,0,400,"white","4",301304],
  ["2","雷云劍","Double dagger","攻擊力","Weapon",52,0,1800,"white",12,301504],
  ["3","極限法劍","Bronze dagger","攻擊力","Weapon",71,0,3200,"white",20,301804],
  ["4","吳越劍","Wuyue sword","攻擊力","Weapon",90,0,4600,"blue",28,301904],
  ["5","龍泉劍","Longquan sword","攻擊力","Weapon",109,0,6000,"blue",36,304204],
  ["6","龍淵","Ebony trident","攻擊力","Weapon",128,0,7400,"blue",44,304304],
  ["7","金蛇信","Golden snake sword","攻擊力","Weapon",147,0,8800,"blue",52,304404],
  ["8","寒雪槍","Bronze axe","攻擊力","Weapon",166,0,10200,"blue",60,304501],
  ["9","豐城劍","Spike knife","攻擊力","Weapon",185,0,11600,"blue",68,304504],
  [10,"悲歡劍","Bamboo double sword","攻擊力","Weapon",204,0,13000,"blue",76,304584]
]

創(chuàng)建數(shù)值服務(wù)

$ vim game-server/app/service/dataService.js
const path = require("path");
const filename = path.basename(__filename, path.extname(__filename));

let DataService = function(){
    this.name = "";
    this.data = {};
};
DataService.prototype.init = function(name){
    this.name = name;
    if(this.data[this.name]===undefined){
        this.load();
    }
    return this;
};
DataService.prototype.load = function(){
    const file = path.join(path.resolve(__dirname, ".."), "data", this.name);
    const json = require(file);
    //console.log(json);
    //獲取字段
    let fields = {};
    json[1].forEach(function(value, index){
        fields[value] = index;
    });

    //去掉數(shù)據(jù)中第一行與第二行
    json.splice(0, 2);
    //console.log(json);
    //將數(shù)據(jù)轉(zhuǎn)化為對象
    let rows = {}, ids = [];
    json.forEach(function(item){
        let obj = {};
        for(let key in fields){
            let index = fields[key];
            obj[key] = item[index];
        }
        let id = obj.id;
        rows[id] = obj;
        ids.push(id);
    });
    this.data[this.name] = {rows,ids};
};

DataService.prototype.findById = function(id){
    const rows = this.data[this.name].rows;
    return rows[id];
};
DataService.prototype.getRandomData = function(){
    const ids = this.data[this.name].ids;
    const rows = this.data[this.name].rows;

    const length = ids.length;
    const index = Math.floor(Math.random() * length);
    const id = ids[index];

    return rows[id];
};
DataService.prototype.getData = function(){
    return this.data[this.name].rows;
};
DataService.prototype.getIds = function(){
    return this.data[this.name].ids;
};

module.exports = {id:filename, func:DataService, scope:"prototype"};

常量服務(wù)

$ vim game-server/app/service/codeService.js
const path = require("path");
const filename = path.basename(__filename, path.extname(__filename));

let CodeService = function(){
    this.EntityType = {PLAYER:"player", TREASURE:"treasure"};
};

module.exports = {id:filename, func:CodeService};

地圖服務(wù)

$ vim game-server/app/service/areaService.js
const pomelo = require("pomelo");
const path = require("path");
const filename = path.basename(__filename, path.extname(__filename));

let AreaService = function(){
    this.areaId = 0;
    this.width = 0;
    this.height = 0;
    this.distance = 50;
    this.entities = {};//實體列表
    this.players = {};//玩家列表
    this.reduced = {};//已刪除的實體
    this.channel = null;//頻道對象
    this.codeService = null;
};

AreaService.prototype.init = function(opts){
    this.areaId = opts.areaId || 1;
    this.width = opts.width || 0;
    this.height = opts.height || 0;
    return this;
};
/*地圖增加實體*/
AreaService.prototype.addEntity = function(entity){
    console.log(entity);
    const self = this;
    if(!entity || !entity.entityId){
        return false;
    }
    this.entities[entity.entityId] = entity;
    if(!entity.x && !entity.y){
        const pos = this.setRandomPosition();
        entity.x = pos.x;
        entity.y = pos.y;
    }
    if(entity.entityType === this.codeService.EntityType.PLAYER){
        this.players[entity.playerId] = entity.entityId;
        //將用戶和前端服務(wù)器對應(yīng)關(guān)系存儲到頻道
        if(entity.playerId && entity.serverId){
            self.getChannel().add(entity.playerId, entity.serverId);
            //玩家注冊拾取事件
            entity.on("pick", function(args){
                //獲取當(dāng)前玩家
                const player = self.entities[args.entityId];
                //獲取拾取目標(biāo)
                const target = self.entities[args.targetId];
                if(target){
                    //玩家增加積分
                    //player.addScore(target.score);
                    //移除拾取目標(biāo)
                    //self.removeEntity(args.targetId);
                    //推送拾取成功消息
                    //self.getChannel().pushMessage({route:"onPick", entityId:args.entityId, targetId:args.targetId, score:target.score});
                }
            });
        }
    }
    return true;
};
/**地圖移除實體*/
AreaService.prototype.removeEntity = function(entityId){

    //判斷實體是否存在
    const entity = this.entities[entityId];
    if(!entity){
        return true;
    }
    //刪除玩家實體
    if(entity.entityType === this.codeService.EntityType.PLAYER){
        //用戶踢下線
        this.getChannel().leave(entity.playerId, entity.serverId);
        //忽略實體動作 todo
        //從玩家列表中刪除
        delete this.players[entity.playerId];
    }
    //從實體集合中刪除
    delete this.entities[entityId];
    //寫入已刪除對象
    this.reduced.push(entityId);

    return true;

};

AreaService.prototype.getChannel = function(){
    if(!this.channel){
        const app = pomelo.app;
        const channelName = "area_"+this.areaId;
        this.channel = app.get("channelService").getChannel(channelName, true);
    }
    return this.channel;
};

/*設(shè)置隨機地圖坐標(biāo)*/
AreaService.prototype.setRandomPosition = function(){
    const random = (min, max)=>Math.round(Math.random()*(max - min)) + min;
    const x = random(this.distance, this.width - this.distance);
    const y = random(this.distance, this.height - this.distance);
    return {x, y};
};



/**獲取地圖與所有實體信息*/
AreaService.prototype.getAreaInfo = function(){
    const areaId = this.areaId;
    const width = this.width;
    const height = this.height;
    const entities = this.getEntities();
    return {areaId, width, height, entities};
};

/**獲取地圖中所有實體信息*/
AreaService.prototype.getEntities = function(){
    let result = {};
    for(let entityId in this.entities){
        result[entityId] = this.entities[entityId].toJson();
    }
    return result;
};

module.exports = {
    id:filename,
    func:AreaService,
    props:[
        {name:"codeService", ref:"codeService"}
    ]
};

實體處理

創(chuàng)建基礎(chǔ)實體抽象父類

$ vim game-server/app/domain/entity.js
//加載事件模塊中事件觸發(fā)器
const EventEmitter  = require("events").EventEmitter;
const path = require("path");
const util = require("util");
//獲取當(dāng)前文件名稱
const filename = path.basename(__filename, path.extname(__filename));
//實體編號 自增唯一
let incId = 1;

/**實體構(gòu)造函數(shù)*/
let Entity = function(opts){
    EventEmitter .call(this);
    //實體編號
    this.entityId = incId++;
    //實體類型
    this.entityType = opts.entityType || "";
    //前端服務(wù)器ID
    this.serverId = opts.serverId || "";
    //實體坐標(biāo)
    this.x = opts.x || 0;//X坐標(biāo)值
    this.y = opts.y || 0;//Y坐標(biāo)值
};

/**Entity實體類使用原型鏈繼承自EventEmitter事件觸發(fā)器*/
util.inherits(Entity, EventEmitter );

//獲取實體坐標(biāo)
Entity.prototype.getPosition = function(){
    const x = this.x;
    const y = this.y;
    return {x, y};
};

//設(shè)置實體坐標(biāo)
Entity.prototype.setPosition = function(x, y){
    this.x = x;
    this.y = y;
};

//實體數(shù)據(jù)結(jié)構(gòu)
Entity.prototype._toJson = function(){
    let json = {};
    json.entityId = this.id;
    json.entityType = this.entityType;
    json.x = this.x;
    json.y = this.y;
    json.serverId = this.serverId;
    return json;
};

//抽象實體類
module.exports = {id:filename, func:Entity, abstract:true};

創(chuàng)建玩家實體

$ vim game-server/app/domain/player.js
const bearcat = require("bearcat");
const path = require("path");

//獲取當(dāng)前文件名稱
const filename = path.basename(__filename, path.extname(__filename));

/**玩家構(gòu)造函數(shù)*/
let Player = function(opts){
    //實體公共屬性
    this.opts = opts;
    this.opts["entityType"] = filename;
    //玩家專用屬性
    this.playerId = opts.playerId || 0;//編號
    this.roleId = opts.roleId || 0;//角色
    this.score = opts.score || 0;//積分
};

/**玩家初始化*/
Player.prototype.init = function(){
    const entity = bearcat.getFunction("entity");
    entity.call(this, this.opts);
};

/**玩家增減積分*/
Player.prototype.addScore = function(score = 0){
    this.score += score;
};

/**玩家數(shù)據(jù)結(jié)構(gòu)*/
Player.prototype.toJson = function(){
    let json = this._toJson();
    json["playerId"] = this.playerId;
    json["roleId"] = this.roleId;
    json["score"] = this.score;
    return json;
};


module.exports = {id:filename, func:Player, scope:"prototype", parent:"entity", init:"init", args:[{name:"opts", type:"Object"}]};

創(chuàng)建目標(biāo)實體

$ vim game-server/app/domain/target.js
const path = require("path");
const bearcat = require("bearcat");

const filename = path.basename(__filename, path.extname(__filename));
const parentClass = "entity";

let Target = function(opts){
    //父類實體屬性
    this.opts = opts;
    this.entityType = filename;
    //專有屬性
    this.score = opts.score || 0;
};
Target.prototype.init = function(){
    const ParentClass = bearcat.getFunction(parentClass);

    ParentClass.call(this, this.opts);
};
Target.prototype.toJson = function(){
    //獲取父類方法
    let json = this.toJson();
    //增加子類屬性
    json.score = this.score;

    return json;
};

module.exports = {
    id:filename,
    func:Target,
    args:[{name:"opts", type:"Object"}],
    scope:"prototype",
    init:"init",
    parent:parentClass
};
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末匕争,一起剝皮案震驚了整個濱河市避乏,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌甘桑,老刑警劉巖拍皮,帶你破解...
    沈念sama閱讀 216,402評論 6 499
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件歹叮,死亡現(xiàn)場離奇詭異,居然都是意外死亡铆帽,警方通過查閱死者的電腦和手機咆耿,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,377評論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來爹橱,“玉大人萨螺,你說我怎么就攤上這事±⑶” “怎么了慰技?”我有些...
    開封第一講書人閱讀 162,483評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長组砚。 經(jīng)常有香客問我吻商,道長,這世上最難降的妖魔是什么糟红? 我笑而不...
    開封第一講書人閱讀 58,165評論 1 292
  • 正文 為了忘掉前任艾帐,我火速辦了婚禮,結(jié)果婚禮上改化,老公的妹妹穿的比我還像新娘掩蛤。我一直安慰自己,他們只是感情好陈肛,可當(dāng)我...
    茶點故事閱讀 67,176評論 6 388
  • 文/花漫 我一把揭開白布揍鸟。 她就那樣靜靜地躺著,像睡著了一般句旱。 火紅的嫁衣襯著肌膚如雪阳藻。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,146評論 1 297
  • 那天谈撒,我揣著相機與錄音腥泥,去河邊找鬼。 笑死啃匿,一個胖子當(dāng)著我的面吹牛蛔外,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播溯乒,決...
    沈念sama閱讀 40,032評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼夹厌,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了裆悄?” 一聲冷哼從身側(cè)響起矛纹,我...
    開封第一講書人閱讀 38,896評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎光稼,沒想到半個月后或南,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體孩等,經(jīng)...
    沈念sama閱讀 45,311評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,536評論 2 332
  • 正文 我和宋清朗相戀三年采够,在試婚紗的時候發(fā)現(xiàn)自己被綠了肄方。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,696評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡吁恍,死狀恐怖扒秸,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情冀瓦,我是刑警寧澤,帶...
    沈念sama閱讀 35,413評論 5 343
  • 正文 年R本政府宣布写烤,位于F島的核電站翼闽,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏洲炊。R本人自食惡果不足惜感局,卻給世界環(huán)境...
    茶點故事閱讀 41,008評論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望暂衡。 院中可真熱鬧询微,春花似錦、人聲如沸狂巢。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽唧领。三九已至藻雌,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間斩个,已是汗流浹背胯杭。 一陣腳步聲響...
    開封第一講書人閱讀 32,815評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留受啥,地道東北人做个。 一個月前我還...
    沈念sama閱讀 47,698評論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像滚局,于是被迫代替她去往敵國和親居暖。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,592評論 2 353

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

  • Swift1> Swift和OC的區(qū)別1.1> Swift沒有地址/指針的概念1.2> 泛型1.3> 類型嚴(yán)謹(jǐn) 對...
    cosWriter閱讀 11,097評論 1 32
  • 這部分主要是開源Java EE框架方面的內(nèi)容核畴,包括Hibernate膝但、MyBatis、Spring谤草、Spring ...
    雜貨鋪老板閱讀 1,367評論 0 2
  • 生活中我們難免犯錯跟束,所有的錯誤歸根結(jié)底都是因為自己不完美莺奸,不完美是絕對的,但我們不能就此止住冀宴。錯誤會導(dǎo)致我們產(chǎn)生負(fù)...
    哥是八路閱讀 1,518評論 17 30
  • 今天灭贷,咱們聊聊投資這個話題。 首先略贮,我們先談?wù)勱P(guān)于投資的三個問題: 1.投資的行為需要圍繞目的進(jìn)行(投資是要圍繞自...
    進(jìn)擊的小銳閱讀 229評論 0 0
  • 1甚疟、“頓悟”這個詞可能在武俠小說了比較多,一位內(nèi)功高手在一個境界卡了多年逃延,一朝頓悟览妖,成為大師。我們現(xiàn)實生活上揽祥,怎樣...
    在學(xué)習(xí)的蝸牛閱讀 247評論 1 4