[{"data":1,"prerenderedAt":1420},["ShallowReactive",2],{"page-c++-1":3,"page-count-c++":403},[4,134,640,699,758],{"id":5,"title":6,"body":7,"date":109,"description":13,"extension":110,"meta":111,"navigation":114,"path":126,"seo":127,"stem":128,"tags":129,"__hash__":133},"blogs\u002F_legacy\u002F2015\u002F2015-08-19-ue4-fmod-usage-in-cpp.md","UE4中C++模式FMod的使用",{"type":8,"value":9,"toc":102},"minimark",[10,14,17,20,24,27,30,41,44,50,53,56,60,63,69,72,75,78,84,87,93,96],[11,12,13],"p",{},"FMod在为UE4提供音效便利的同时，有提供底层的API来方便更加详尽的需求。",[11,15,16],{},"当前UE4版本4.9.2；FMod版本1.07.00。",[11,18,19],{},"目前版本下对FMod的使用和之前进行UE4与FMod音乐可视化验证的时候并没有什么不同，这里主要是总结下使用中遇到的问题。",[21,22,23],"h2",{"id":23},"编码问题",[11,25,26],{},"编码问题主要出在中文路径的处理上，UE4内部使用的是UTF-16编码。",[11,28,29],{},"因此，将通过Save&Load之类保存起来的路径提供给FMod使用的时候，需要对字符编码进行转换。",[31,32,37],"pre",{"className":33,"code":35,"language":36},[34],"language-text","\u002F\u002F 传入参数：const FString& FileFullPath\n\nstd::stringstream dts;\ndts \u003C\u003C TCHAR_TO_UTF8(*FileFullPath);\nresult = system->createStream(dts.str().c_str(), FMOD_LOOP_NORMAL | FMOD_2D, 0, &sound);\n","text",[38,39,35],"code",{"__ignoreMap":40},"",[11,42,43],{},"关于字符编码，在使用Tag系统的时候还是会遇到。",[31,45,48],{"className":46,"code":47,"language":36},[34],"int NumTags;\nresult = sound_to_analyse->getNumTags(&NumTags, NULL);\nif (result != FMOD_RESULT::FMOD_OK) break;\nif (NumTags \u003C= 0) break;\nFMOD_TAG MusicTag;\nfor (int mTag = 0; mTag \u003C NumTags; ++mTag){ sound_to_analyse->getTag(NULL, mTag, &MusicTag);\nstd::stringstream ts;\nts \u003C\u003C \"Tag:\";\nts \u003C\u003C MusicTag.name;\nts \u003C\u003C \" Type:\";\nts \u003C\u003C MusicTag.type;\nts \u003C\u003C \" Data:\";\nts \u003C\u003C std::string((char*)MusicTag.data);\nts \u003C\u003C \" DataLength:\";\nts \u003C\u003C MusicTag.datalen;\nts \u003C\u003C \"\\n\"; OutputDebugStringA(ts.str().c_str()); } result = sound_to_analyse->getTag(\"TITLE\", 0, &MusicTag);\n",[38,49,47],{"__ignoreMap":40},[11,51,52],{},"这里目前似乎是有BUG存在的，通过getTag对音乐的标签进行读取时，如果标签是非英文字符的话，读取出来的字符编码无法被正常的解析。并不是读写方式的问题，通过断点直接查看内存的话会看到其中的编码不符合文档中所描述的编码格式。",[11,54,55],{},"因此建议音乐的预览图片使用FMod来读取APIC的tag，而其他的tag使用别的库进行读取，例如使用TagLib。",[21,57,59],{"id":58},"apic图片读取","APIC图片读取",[11,61,62],{},"音乐文件的预览图片信息一般存储于APIC标签中，要将读取出的图片数据展示到界面上。可以借助ImageWrapper和SImage来实现。",[31,64,67],{"className":65,"code":66,"language":36},[34],"\u002F\u002F 变量定义\nTSharedPtr ImageTitle;\nIImageWrapperPtr ImageWrapper;\nUTexture2D* mImageHolder;\nFSlateDynamicImageBrush* mSlateDyn;\n\u002F\u002F 实际读取\nresult = sound_to_analyse->getTag(\"APIC\", 0, &MusicTag);\nif (result != FMOD_RESULT::FMOD_OK) break;\nTArray RawFloatImgData;\nRawFloatImgData.AddUninitialized(MusicTag.datalen);\nFMemory::Memcpy(RawFloatImgData.GetData(), MusicTag.data, MusicTag.datalen*sizeof(uint8));\nEImageFormat::Type MusicFormat = EImageFormat::PNG;\nchar tc = RawFloatImgData[1];\nif (tc == 'i'){\ntc = RawFloatImgData[7];\nswitch (tc)\n{\ncase 'j':\ncase 'J':\nMusicFormat = EImageFormat::JPEG;\nbreak;\ncase 'b':\ncase 'B':\nMusicFormat = EImageFormat::BMP;\nbreak;\ndefault:\nbreak;\n}\n}\nIImageWrapperModule& ImageWrapperModule = FModuleManager::LoadModuleChecked(FName(\"ImageWrapper\"));\nImageWrapper = ImageWrapperModule.CreateImageWrapper(MusicFormat);\nif (!ImageWrapper.IsValid()) break;\nif (!ImageWrapper->SetCompressed(RawFloatImgData.GetData(), RawFloatImgData.Num())) break;\nOutputDebugStringA(\"APIC Read Success\\n\");\nconst TArray* UncompressedBGRA = NULL;\nif (!ImageWrapper->GetRaw(ERGBFormat::BGRA, 8, UncompressedBGRA)) break;\nOutputDebugStringA(\"APIC UTexture2D OK\\n\");\nmImageHolder = UTexture2D::CreateTransient(ImageWrapper->GetWidth(), ImageWrapper->GetHeight(), PF_B8G8R8A8);\nvoid* TextureData = mImageHolder->PlatformData->Mips[0].BulkData.Lock(LOCK_READ_WRITE);\nFMemory::Memcpy(TextureData, UncompressedBGRA->GetData(), UncompressedBGRA->Num());\nmImageHolder->PlatformData->Mips[0].BulkData.Unlock();\nmImageHolder->UpdateResource();\nmSlateDyn = new FSlateDynamicImageBrush(mImageHolder, FVector2D(ImageWrapper->GetWidth(), ImageWrapper->GetHeight()), FName(\"tabActiveImage\"));\nImageTitle->SetImage(mSlateDyn);\n",[38,68,66],{"__ignoreMap":40},[11,70,71],{},"由于部分的变量的初始化没有复制过来，代码仅作交流用。",[21,73,74],{"id":74},"播放回调",[11,76,77],{},"如果有需要对音乐播放的状态进行追踪，例如在音乐播放完成后进入积分画面的话。使用FMod提供的回调系统是一个不错的解决方案。",[31,79,82],{"className":80,"code":81,"language":36},[34],"channel->setMode(FMOD_LOOP_OFF);\nif (result != FMOD_RESULT::FMOD_OK) break;\nresult = channel->setCallback(FModHolders::EndCallBack);\nif (result != FMOD_RESULT::FMOD_OK) break;\n",[38,83,81],{"__ignoreMap":40},[11,85,86],{},"由于设置回调时并没有指定回调类型，故而在回调函数内部对事件进行过滤",[31,88,91],{"className":89,"code":90,"language":36},[34],"FMOD_RESULT FModHolders::EndCallBack(FMOD_CHANNELCONTROL *chanControl, FMOD_CHANNELCONTROL_TYPE controlType, FMOD_CHANNELCONTROL_CALLBACK_TYPE callbackType, void *commandData1, void *commandData2)\n{\nif (controlType == FMOD_CHANNELCONTROL_TYPE::FMOD_CHANNELCONTROL_CHANNEL){\nif (callbackType == FMOD_CHANNELCONTROL_CALLBACK_TYPE::FMOD_CHANNELCONTROL_CALLBACK_END){\n\u002F\u002F 处理代码\n",[38,92,90],{"__ignoreMap":40},[11,94,95],{},"这里需要注意的是，回调函数本身的声明必须要是Static的。",[31,97,100],{"className":98,"code":99,"language":36},[34],"static FMOD_RESULT F_CALLBACK EndCallBack(FMOD_CHANNELCONTROL *chanControl, FMOD_CHANNELCONTROL_TYPE controlType, FMOD_CHANNELCONTROL_CALLBACK_TYPE callbackType, void *commandData1, void *commandData2);\n",[38,101,99],{"__ignoreMap":40},{"title":40,"searchDepth":103,"depth":104,"links":105},2,3,[106,107,108],{"id":23,"depth":103,"text":23},{"id":58,"depth":103,"text":59},{"id":74,"depth":103,"text":74},"2015-08-19","md",{"layout":112,"status":113,"published":114,"author":115,"author_login":116,"author_email":117,"author_url":118,"wordpress_id":119,"wordpress_url":120,"date_gmt":121,"excerpt":122},"post","publish",true,{"display_name":116,"login":116,"email":117,"url":118},"chaoshikari","chaoshikari@gmail.com","\u002F",1516,"\u002F\u002F?p=1516","2015-08-18 23:48:29 +0000",{"type":8,"value":123},[124],[11,125,13],{},"\u002F2015-08-19-ue4-fmod-usage-in-cpp",{"title":6,"description":13},"_legacy\u002F2015\u002F2015-08-19-ue4-fmod-usage-in-cpp",[130,131,132],"c++","UE4","FMod","x4VnHG8oYgpU4XCrWiG9_Wzrb-tAVEXhAGEkpJn3jNI",{"id":135,"title":136,"body":137,"date":625,"description":141,"extension":110,"meta":626,"navigation":114,"path":635,"seo":636,"stem":637,"tags":638,"__hash__":639},"blogs\u002F_legacy\u002F2014\u002F2014-08-09-ue4%e5%ae%98%e6%96%b9fps%ef%bc%88c%ef%bc%89%e8%8c%83%e4%be%8b%e5%ae%9e%e7%8e%b0%e8%ae%b0%e5%bd%95.md","UE4官方FPS（C++）范例实现记录",{"type":8,"value":138,"toc":615},[139,142,152,155,158,166,172,185,188,192,195,202,217,220,230,233,240,243,246,257,260,274,277,284,287,290,293,296,299,302,305,587,590,593,596,599,602,608,611],[11,140,141],{},"看完Digital Tutors的UE4教程之后，参照官方wiki的教程文章把FPS的范例实现了一遍。于是趁热打铁，用文字的形式记录和总结一下。",[11,143,144,145,151],{},"教程原文地址：",[146,147,148],"a",{"href":148,"rel":149},"https:\u002F\u002Fwiki.unrealengine.com\u002FFirst_Person_Shooter_C%2B%2B_Tutorial",[150],"nofollow","。",[11,153,154],{},"使用的UE版本是4.4版，按照教程中的顺序来：",[21,156,157],{"id":157},"新建项目",[11,159,160,161,165],{},"直接新建一个空白项目，不要默认的资源文件。项目名",[162,163,164],"strong",{},"FPSProject","，为了方便后面代码的复制粘贴。在这里不做变更。",[11,167,168,169,151],{},"新建后点保存，将地图保存为",[162,170,171],{},"FPSMap",[11,173,174,175,178,179,182,183,151],{},"然后有一个步骤是在",[162,176,177],{},"Game>Project Settings",">",[162,180,181],{},"Maps & Modes","中将编辑器默认地图设置为刚刚保存的",[162,184,171],{},[11,186,187],{},"这一步在操作的时候不知为何自动被添加了一块地板，总之不影响操作，直接无视。",[21,189,191],{"id":190},"创建gamemode","创建GameMode",[11,193,194],{},"粗略的浏览了下文档之后，发现GameMode大概相当于游戏规则的核心管理类。大体上的地位相当于cocos2d中的Scene。如下图：",[11,196,197],{},[198,199],"img",{"alt":200,"src":201,"title":200},"clip_image001","\u002Fwp-content\u002Fuploads\u002F2014\u002F08\u002Fclip_image001_thumb.jpg",[11,203,204,205,208,209,212,213,216],{},"在菜单",[162,206,207],{},"File","下",[162,210,211],{},"Add Code to Project","中新建一个类，基类选择为",[162,214,215],{},"GameMode","。选择编辑会自动打开VS2013。这个时候intellisense会报错，按照官方的建议，直接无视即可。原因似乎是有的文件要到编译的时候才会生成，这里的情况问题出在\"FPSGameMode.generated.h\"上。",[11,218,219],{},"在生成的类中覆盖掉BeginPlay函数，并在屏幕上输出HelloWolrd。关闭UEEditor，在VS中进行代码编译。要注意如果不关闭编辑器的话，VS会无法写入文件导致失败。",[11,221,222,223,226,227,151],{},"生成完毕之后重新打开UE，在配置中的",[162,224,225],{},"Game>Project Settings>Maps & Modes","将Default Mode设置为",[162,228,229],{},"FPSGameMode",[21,231,232],{"id":232},"创建角色",[11,234,235,236,239],{},"和上面一样，添加代码命名",[162,237,238],{},"FPSCharacter","，继承Charater。和上面的步骤几乎没什么不同，继承BeginPlay并输出调试文字。",[11,241,242],{},"完成操作之后在FPSGameMode的构造函数中添加DefaultPawnClass = AFPSCharacter::StaticClass()。",[21,244,245],{"id":245},"玩家操作",[11,247,248,249,252,253,256],{},"UE的操作接口分为",[162,250,251],{},"Axis Mappings","和",[162,254,255],{},"Action Mapings","，分别对应连续输入的方向控制操作和离散输入的按键操作。设定在项目配置中的Input项内进行。",[11,258,259],{},"接口的作用是将硬件输入绑定到特定的名称上，然后由Charater类来注册。主要提供一个映射的操作来隔离游戏逻辑和硬件操作，很常见的引擎输入控制模式，基本上按照文档描述没有遇到什么问题。",[11,261,262,263,266,267,266,270,273],{},"途中有介绍到",[162,264,265],{},"UFUNCTION","、",[162,268,269],{},"UCLASS",[162,271,272],{},"UPROPERTY","这几个宏，它们的作用是将特定的函数、类、属性暴露给引擎，代码中出现这几个宏的代码变动时必须要在VS中重新编译。",[21,275,276],{"id":276},"为角色添加网格",[11,278,279,280,283],{},"新建一个BlusPrint继承刚刚建立的",[162,281,282],{},"FPSCharater","。通过BluePrint的编辑器将Mesh设置为下载并导入的人物模型。没什么特别的问题。",[11,285,286],{},"需要在VC中将玩家的Chara修改为刚刚新建的BluePrint,看起来有点繁琐，不过也就是复制粘贴一下。",[11,288,289],{},"添加完后会发现视角有点低，通过添加一个UCameraComponent来解决。根据文档描述，个类就是作为摄像机的配置而存在的。",[21,291,292],{"id":292},"为角色添加第一人称网格",[11,294,295],{},"在这个游戏模式的定义中，玩家是看不见自己的身体网格的，只能看见自己的手。似乎和通常遇到的FPS有点不一样，不过Demo就是这么定义的。",[11,297,298],{},"和上一步没啥不同，关键性的部分是调整可见性的语句。",[21,300,301],{"id":301},"子弹和射击",[11,303,304],{},"新建一个继承自Actor的类，创建碰撞形态和移动逻辑的Component，并且设定生命周期为3秒。",[31,306,310],{"className":307,"code":308,"language":309,"meta":40,"style":40},"language-cpp shiki shiki-themes github-light-high-contrast github-dark monokai","\u002F\u002F Use a sphere as a simple collision representation\nCollisionComp = PCIP.CreateDefaultSubobject\u003CUSphereComponent>(this, TEXT(\"SphereComp\"));\nCollisionComp->InitSphereRadius(15.0f);\nCollisionComp->BodyInstance.SetCollisionProfileName(\"Projectile\");\nCollisionComp->OnComponentHit.AddDynamic(this, &AFPSProjectile::OnHit);\nRootComponent = CollisionComp;\n\n\u002F\u002F Use a ProjectileMovementComponent to govern this projectile's movement\nProjectileMovement = PCIP.CreateDefaultSubobject\u003CUProjectileMovementComponent>(this, TEXT(\"ProjectileComp\"));\nProjectileMovement->UpdatedComponent = CollisionComp;\nProjectileMovement->InitialSpeed = 3000.f;\nProjectileMovement->MaxSpeed = 3000.f;\nProjectileMovement->bRotationFollowsVelocity = true;\nProjectileMovement->bShouldBounce = true;\nProjectileMovement->Bounciness = 0.3f;\n\n\u002F\u002F Die after 3 seconds by default\nInitialLifeSpan = 3.0f;\n","cpp",[38,311,312,321,365,385,401,426,437,443,449,481,491,507,521,534,546,561,566,572],{"__ignoreMap":40},[313,314,317],"span",{"class":315,"line":316},"line",1,[313,318,320],{"class":319},"sZdD5","\u002F\u002F Use a sphere as a simple collision representation\n",[313,322,323,327,331,334,337,340,342,345,349,352,356,358,362],{"class":315,"line":103},[313,324,326],{"class":325},"s0idv","CollisionComp ",[313,328,330],{"class":329},"sLXdl","=",[313,332,333],{"class":325}," PCIP.CreateDefaultSubobject",[313,335,336],{"class":329},"\u003C",[313,338,339],{"class":325},"USphereComponent",[313,341,178],{"class":329},[313,343,344],{"class":325},"(",[313,346,348],{"class":347},"s4Wjf","this",[313,350,351],{"class":325},", ",[313,353,355],{"class":354},"scAT4","TEXT",[313,357,344],{"class":325},[313,359,361],{"class":360},"sZnmU","\"SphereComp\"",[313,363,364],{"class":325},"));\n",[313,366,367,370,373,375,379,382],{"class":315,"line":104},[313,368,369],{"class":325},"CollisionComp->",[313,371,372],{"class":354},"InitSphereRadius",[313,374,344],{"class":325},[313,376,378],{"class":377},"stP0Q","15.0",[313,380,381],{"class":329},"f",[313,383,384],{"class":325},");\n",[313,386,388,391,394,396,399],{"class":315,"line":387},4,[313,389,390],{"class":325},"CollisionComp->BodyInstance.",[313,392,393],{"class":354},"SetCollisionProfileName",[313,395,344],{"class":325},[313,397,398],{"class":360},"\"Projectile\"",[313,400,384],{"class":325},[313,402,404,407,410,412,414,416,419,423],{"class":315,"line":403},5,[313,405,406],{"class":325},"CollisionComp->OnComponentHit.",[313,408,409],{"class":354},"AddDynamic",[313,411,344],{"class":325},[313,413,348],{"class":347},[313,415,351],{"class":325},[313,417,418],{"class":329},"&",[313,420,422],{"class":421},"sfUV7","AFPSProjectile",[313,424,425],{"class":325},"::OnHit);\n",[313,427,429,432,434],{"class":315,"line":428},6,[313,430,431],{"class":325},"RootComponent ",[313,433,330],{"class":329},[313,435,436],{"class":325}," CollisionComp;\n",[313,438,440],{"class":315,"line":439},7,[313,441,442],{"emptyLinePlaceholder":114},"\n",[313,444,446],{"class":315,"line":445},8,[313,447,448],{"class":319},"\u002F\u002F Use a ProjectileMovementComponent to govern this projectile's movement\n",[313,450,452,455,457,459,461,464,466,468,470,472,474,476,479],{"class":315,"line":451},9,[313,453,454],{"class":325},"ProjectileMovement ",[313,456,330],{"class":329},[313,458,333],{"class":325},[313,460,336],{"class":329},[313,462,463],{"class":325},"UProjectileMovementComponent",[313,465,178],{"class":329},[313,467,344],{"class":325},[313,469,348],{"class":347},[313,471,351],{"class":325},[313,473,355],{"class":354},[313,475,344],{"class":325},[313,477,478],{"class":360},"\"ProjectileComp\"",[313,480,364],{"class":325},[313,482,484,487,489],{"class":315,"line":483},10,[313,485,486],{"class":325},"ProjectileMovement->UpdatedComponent ",[313,488,330],{"class":329},[313,490,436],{"class":325},[313,492,494,497,499,502,504],{"class":315,"line":493},11,[313,495,496],{"class":325},"ProjectileMovement->InitialSpeed ",[313,498,330],{"class":329},[313,500,501],{"class":377}," 3000.",[313,503,381],{"class":329},[313,505,506],{"class":325},";\n",[313,508,510,513,515,517,519],{"class":315,"line":509},12,[313,511,512],{"class":325},"ProjectileMovement->MaxSpeed ",[313,514,330],{"class":329},[313,516,501],{"class":377},[313,518,381],{"class":329},[313,520,506],{"class":325},[313,522,524,527,529,532],{"class":315,"line":523},13,[313,525,526],{"class":325},"ProjectileMovement->bRotationFollowsVelocity ",[313,528,330],{"class":329},[313,530,531],{"class":377}," true",[313,533,506],{"class":325},[313,535,537,540,542,544],{"class":315,"line":536},14,[313,538,539],{"class":325},"ProjectileMovement->bShouldBounce ",[313,541,330],{"class":329},[313,543,531],{"class":377},[313,545,506],{"class":325},[313,547,549,552,554,557,559],{"class":315,"line":548},15,[313,550,551],{"class":325},"ProjectileMovement->Bounciness ",[313,553,330],{"class":329},[313,555,556],{"class":377}," 0.3",[313,558,381],{"class":329},[313,560,506],{"class":325},[313,562,564],{"class":315,"line":563},16,[313,565,442],{"emptyLinePlaceholder":114},[313,567,569],{"class":315,"line":568},17,[313,570,571],{"class":319},"\u002F\u002F Die after 3 seconds by default\n",[313,573,575,578,580,583,585],{"class":315,"line":574},18,[313,576,577],{"class":325},"InitialLifeSpan ",[313,579,330],{"class":329},[313,581,582],{"class":377}," 3.0",[313,584,381],{"class":329},[313,586,506],{"class":325},[11,588,589],{},"通过BluePrint继承这个类，并且在BluePrint编辑器中添加Component并附上网格，同时要关闭其碰撞。因为基类中已经有了碰撞逻辑的实现。",[11,591,592],{},"关于碰撞方面，不知为何碰撞组的管理是在ini文件中进行配置的，这个留到以后再研究。",[11,594,595],{},"子弹的发射还有一个添加瞄准准星的HUD的过程，大体过程就是绘制，没别的了。是否HUD类能够处理鼠标事件目前不明。",[21,597,598],{"id":598},"角色动画",[11,600,601],{},"角色动画通过状态机来管理，工作在BluePrint中进行。没有用到C++代码，可视化的调整状态机的逻辑，非常的方便。",[11,603,604],{},[198,605],{"alt":606,"src":607,"title":606},"image","\u002Fwp-content\u002Fuploads\u002F2014\u002F08\u002Fimage_thumb.png",[11,609,610],{},"总体而言算是大致的了解了UE4用C++的方式来搭建游戏的过程，不过详细的API的熟悉还是需要一定的时间过程。作为开头，刚好到此为止。",[612,613,614],"style",{},"html pre.shiki code .sZdD5, html code.shiki .sZdD5{--shiki-default:#66707B;--shiki-dark:#6A737D;--shiki-sepia:#88846F}html pre.shiki code .s0idv, html code.shiki .s0idv{--shiki-default:#0E1116;--shiki-dark:#E1E4E8;--shiki-sepia:#F8F8F2}html pre.shiki code .sLXdl, html code.shiki .sLXdl{--shiki-default:#A0111F;--shiki-dark:#F97583;--shiki-sepia:#F92672}html pre.shiki code .s4Wjf, html code.shiki .s4Wjf{--shiki-default:#023B95;--shiki-dark:#79B8FF;--shiki-sepia:#FD971F}html pre.shiki code .scAT4, html code.shiki .scAT4{--shiki-default:#622CBC;--shiki-dark:#B392F0;--shiki-sepia:#A6E22E}html pre.shiki code .sZnmU, html code.shiki .sZnmU{--shiki-default:#032563;--shiki-dark:#9ECBFF;--shiki-sepia:#E6DB74}html pre.shiki code .stP0Q, html code.shiki .stP0Q{--shiki-default:#023B95;--shiki-dark:#79B8FF;--shiki-sepia:#AE81FF}html pre.shiki code .sfUV7, html code.shiki .sfUV7{--shiki-default:#702C00;--shiki-default-text-decoration:inherit;--shiki-dark:#B392F0;--shiki-dark-text-decoration:inherit;--shiki-sepia:#A6E22E;--shiki-sepia-text-decoration:underline}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html .sepia .shiki span {color: var(--shiki-sepia);background: var(--shiki-sepia-bg);font-style: var(--shiki-sepia-font-style);font-weight: var(--shiki-sepia-font-weight);text-decoration: var(--shiki-sepia-text-decoration);}html.sepia .shiki span {color: var(--shiki-sepia);background: var(--shiki-sepia-bg);font-style: var(--shiki-sepia-font-style);font-weight: var(--shiki-sepia-font-weight);text-decoration: var(--shiki-sepia-text-decoration);}",{"title":40,"searchDepth":103,"depth":104,"links":616},[617,618,619,620,621,622,623,624],{"id":157,"depth":103,"text":157},{"id":190,"depth":103,"text":191},{"id":232,"depth":103,"text":232},{"id":245,"depth":103,"text":245},{"id":276,"depth":103,"text":276},{"id":292,"depth":103,"text":292},{"id":301,"depth":103,"text":301},{"id":598,"depth":103,"text":598},"2014-08-09",{"layout":112,"status":113,"published":114,"author":627,"author_login":116,"author_email":117,"author_url":118,"wordpress_id":628,"wordpress_url":629,"date_gmt":630,"excerpt":631},{"display_name":116,"login":116,"email":117,"url":118},950,"\u002F\u002F?p=950","2014-08-09 12:59:00 +0000",{"type":8,"value":632},[633],[11,634,141],{},"\u002F2014-08-09-ue4-official-fps-sample-note",{"title":136,"description":141},"_legacy\u002F2014\u002F2014-08-09-ue4%e5%ae%98%e6%96%b9fps%ef%bc%88c%ef%bc%89%e8%8c%83%e4%be%8b%e5%ae%9e%e7%8e%b0%e8%ae%b0%e5%bd%95",[130,131],"nAEOG3fwndTuulhA-Y-0puqE5TaHgKzX6coCPlzh4yQ",{"id":641,"title":642,"body":643,"date":682,"description":647,"extension":110,"meta":683,"navigation":114,"path":692,"seo":693,"stem":694,"tags":695,"__hash__":698},"blogs\u002F_legacy\u002F2014\u002F2014-08-04-xmpp%e5%ae%a2%e6%88%b7%e7%ab%afc%e5%ba%93gloox%e7%ae%80%e6%98%8e%e6%a6%82%e8%a6%81.md","XMPP客户端C++库Gloox简明概要",{"type":8,"value":644,"toc":680},[645,648,651,654,662,665,671,674,677],[11,646,647],{},"Gloox是Xmpp协议客户端的Lib，使用起来非常简单。官方自带的sample也非常的实用，功能方面恰到好处的没有提供显示之类的。对于开发xmpp的bot而言是非常的合适。",[11,649,650],{},"Xmpp协议虽然不是很流行，但是基于Xmpp的聊天服务还是有很多优点的。使用Xmpp协议来制作bot可以实现很多功能，只要不是网络游戏那样实时大量数据包传递的话，Xmpp是一个很好的避开与网络交互底层接触的解决方案。",[11,652,653],{},"Xmpp的协议详细的可以参照RFC文档，不过既然选择使用库来做的话就是懒得和协议上的东西打交道。基本功能上就是个聊天软件，想要详细接触的童鞋可以下载Pidgin尝试一下，GTalk是可以使用Xmpp协议连接的。",[11,655,656,657],{},"Gloox的设计简单易懂，基于事件驱动。官方有个详细的说明页面，这位前辈的博客上贴出了翻译：",[146,658,661],{"href":659,"rel":660},"http:\u002F\u002Fblog.csdn.net\u002Fkkaxiao\u002Farticle\u002Fdetails\u002F6702298%E3%80%82%E6%9C%89%E5%85%B4%E8%B6%A3%E8%AF%A6%E7%BB%86%E4%BA%86%E8%A7%A3%E7%9A%84%E7%AB%A5%E9%9E%8B%E5%8F%AF%E4%BB%A5%E5%8E%BB%E7%9C%8B%E7%9C%8B%E3%80%82",[150],"http:\u002F\u002Fblog.csdn.net\u002Fkkaxiao\u002Farticle\u002Fdetails\u002F6702298。有兴趣详细了解的童鞋可以去看看。",[11,663,664],{},"如果只是做简单的开发的话，基本上不会需要很深入的了解。等需要的时候再针对性的找找相关说明即可，gloox的文档里面可以找到大多数的答案。Gloox的使用可以简单的分为两个步骤：登陆账号、处理消息。",[31,666,669],{"className":667,"code":668,"language":36},[34],"#include \"gloox\u002Fclient.h\"\n#include \"gloox\u002Fmessagesessionhandler.h\"\n#include \"gloox\u002Fmessageeventhandler.h\"\n#include \"gloox\u002Fmessageeventfilter.h\"\n#include \"gloox\u002Fchatstatehandler.h\"\n#include \"gloox\u002Fchatstatefilter.h\"\n#include \"gloox\u002Fconnectionlistener.h\"\n#include \"gloox\u002Fdisco.h\"\n#include \"gloox\u002Fmessage.h\"\n#include \"gloox\u002Fgloox.h\"\n#include \"gloox\u002Flastactivity.h\"\n#include \"gloox\u002Floghandler.h\"\n#include \"gloox\u002Flogsink.h\"\n#include \"gloox\u002Fconnectiontcpclient.h\"\n#include \"gloox\u002Fconnectionsocks5proxy.h\"\n#include \"gloox\u002Fconnectionhttpproxy.h\"\n#include \"gloox\u002Fmessagehandler.h\"\nusing namespace gloox;\n\n#ifndef _WIN32\n# include \u003Cunistd.h>\n#endif\n\n#include \u003Cstdio.h>\n#include \u003Cstring>\n\n#include \u003Ccstdio> \u002F\u002F [s]print[f]\n\n#if defined( WIN32 ) || defined( _WIN32 )\n# include \u003Cwindows.h>\n#endif\n\nclass MessageTest : public MessageSessionHandler, ConnectionListener, LogHandler,\n    MessageEventHandler, MessageHandler, ChatStateHandler\n{\npublic:\n    MessageTest() : m_session( 0 ), m_messageEventFilter( 0 ), m_chatStateFilter( 0 ) {}\n\n    virtual ~MessageTest() {}\n\n    void start()\n    {\n        \u002F\u002F \u003CID和密码 \n        JID jid( \"username@gmail.com\u002Fgloox\" );  \u002F\u002F \u003C Id后面的\u002Fgloox是资源名称，并不是必须的，Xmpp支持多个客户端同时接入，可以用作区分。\n        j = new Client( jid, \"password\" );\n        \n        \u002F\u002F \u003C注册事件处理\n        j->registerConnectionListener( this );\n        j->registerMessageSessionHandler( this, 0 );\n        j->disco()->setVersion( \"messageTest\", GLOOX_VERSION, \"Win32\" );\n        j->disco()->setIdentity( \"client\", \"bot\" );\n        j->disco()->addFeature( XMLNS_CHAT_STATES );\n        StringList ca;\n        ca.push_back( \"\u002Fpath\u002Fto\u002Fcacert.crt\" );\n        j->setCACerts( ca );\n        j->logInstance().registerLogHandler( LogLevelDebug, LogAreaAll, this );\n\n\n        if( j->connect( false ) )\n        {\n            ConnectionError ce = ConnNoError;\n            while( ce == ConnNoError )\n            {\n                ce = j->recv();\n            }\n            printf( \"ce: %d\\n\", ce );\n        }\n\n        delete( j );\n    }\n\n    virtual void onConnect()\n    {\n        printf( \"connected!!!\\n\" );\n    }\n\n    virtual void onDisconnect( ConnectionError e )\n    {\n        printf( \"message_test: disconnected: %d\\n\", e );\n        if( e == ConnAuthenticationFailed )\n            printf( \"auth failed. reason: %d\\n\", j->authError() );\n    }\n\n    virtual bool onTLSConnect( const CertInfo& info )\n    {\n        time_t from( info.date_from );\n        time_t to( info.date_to );\n\n        printf( \"status: %d\\nissuer: %s\\npeer: %s\\nprotocol: %s\\nmac: %s\\ncipher: %s\\ncompression: %s\\n\"\n            \"from: %s\\nto: %s\\n\",\n            info.status, info.issuer.c_str(), info.server.c_str(),\n            info.protocol.c_str(), info.mac.c_str(), info.cipher.c_str(),\n            info.compression.c_str(), ctime( &from ), ctime( &to ) );\n        return true;\n    }\n\n    virtual void handleMessage( const Message& msg, MessageSession * \u002F*session*\u002F )\n    {\n        printf( \"type: %d, subject: %s, message: %s, thread id: %s\\n\", msg.subtype(),\n            msg.subject().c_str(), msg.body().c_str(), msg.thread().c_str() );\n\n        std::string re = \"You said:\\n> \" + msg.body() + \"\\nI like that statement.\";\n        std::string sub;\n        if( !msg.subject().empty() )\n            sub = \"Re: \" +  msg.subject();\n\n        m_messageEventFilter->raiseMessageEvent( MessageEventDisplayed );\n#if defined( WIN32 ) || defined( _WIN32 )\n        Sleep( 1000 );\n#else\n        sleep( 1 );\n#endif\n        m_messageEventFilter->raiseMessageEvent( MessageEventComposing );\n        m_chatStateFilter->setChatState( ChatStateComposing );\n#if defined( WIN32 ) || defined( _WIN32 )\n        Sleep( 2000 );\n#else\n        sleep( 2 );\n#endif\n        m_session->send( re, sub );\n\n        if( msg.body() == \"quit\" )\n            j->disconnect();\n    }\n\n    virtual void handleMessageEvent( const JID& from, MessageEventType event )\n    {\n        printf( \"received event: %d from: %s\\n\", event, from.full().c_str() );\n    }\n\n    virtual void handleChatState( const JID& from, ChatStateType state )\n    {\n        printf( \"received state: %d from: %s\\n\", state, from.full().c_str() );\n    }\n\n    virtual void handleMessageSession( MessageSession *session )\n    {\n        printf( \"got new session\\n\");\n        \u002F\u002F \u003C示例程序只处理一个Session，所以在这里释放掉前一个\n        j->disposeMessageSession( m_session );\n        m_session = session;\n        m_session->registerMessageHandler( this );\n        m_messageEventFilter = new MessageEventFilter( m_session );\n        m_messageEventFilter->registerMessageEventHandler( this );\n        m_chatStateFilter = new ChatStateFilter( m_session );\n        m_chatStateFilter->registerChatStateHandler( this );\n    }\n\n    virtual void handleLog( LogLevel level, LogArea area, const std::string& message )\n    {\n        printf(\"log: level: %d, area: %d, %s\\n\", level, area, message.c_str() );\n    }\n\nprivate:\n    Client *j;\n    MessageSession *m_session;\n    MessageEventFilter *m_messageEventFilter;\n    ChatStateFilter *m_chatStateFilter;\n};\n\nint main( int \u002F*argc*\u002F, char** \u002F*argv*\u002F )\n{\n    MessageTest *r = new MessageTest();\n    r->start();\n    delete( r );\n    getchar();getchar();\n    return 0;\n}\n\n",[38,670,668],{"__ignoreMap":40},[11,672,673],{},"以上代码来自官方的Sample，主要功能是对接到的文字进行复述。在这个基础上进行修改就可以实现常见的需求了。",[11,675,676],{},"在使用gloox的过程中有一点需要注意的是，MessageSession如果保存了其指针的话，不要自行进行Delete操作，而应该交由Client来释放。j->disposeMessageSession( m_session )这样的做法才是正确的。",[11,678,679],{},"由于不是做客户端，实际上做的工作还是比较少的。但是刚上手一个库的时候多少会有些不知所措，希望对有用到的童鞋起到帮助。",{"title":40,"searchDepth":103,"depth":104,"links":681},[],"2014-08-04",{"layout":112,"status":113,"published":114,"author":684,"author_login":116,"author_email":117,"author_url":118,"wordpress_id":685,"wordpress_url":686,"date_gmt":687,"excerpt":688},{"display_name":116,"login":116,"email":117,"url":118},936,"\u002F\u002F?p=936","2014-08-04 12:00:40 +0000",{"type":8,"value":689},[690],[11,691,647],{},"\u002F2014-08-04-xmpp客户端c库gloox简明概要",{"title":642,"description":647},"_legacy\u002F2014\u002F2014-08-04-xmpp%e5%ae%a2%e6%88%b7%e7%ab%afc%e5%ba%93gloox%e7%ae%80%e6%98%8e%e6%a6%82%e8%a6%81",[130,696,697],"XMPP","Gloox","8Pmh-CAzgjTKCb-L_s5XiwTQT1K9fmwQtV1LkzzZA8Q",{"id":700,"title":701,"body":702,"date":742,"description":706,"extension":110,"meta":743,"navigation":114,"path":752,"seo":753,"stem":754,"tags":755,"__hash__":757},"blogs\u002F_legacy\u002F2012\u002F2012-12-28-c%e4%b8%ad%e6%96%87%e5%88%86%e5%89%b2.md","C++中文分割",{"type":8,"value":703,"toc":740},[704,707,710,713,716,728,731,737],[11,705,706],{},"其实最近一直都有遇到c++内的中文字符串问题，不过一直都通过各种方法绕过了。",[11,708,709],{},"可是今天遇到了需要将字符串的中文和英文按字符分割的问题，实在是没有取巧的方法了。",[11,711,712],{},"由于从资源文件读取出来的是utf-8编码，而输出时也是用的utf-8编码。如果在中途对字符串进行转化处理的话实在是没有什么必要性。其实一直很好奇，无论是什么格式的编码，windows都是能正常识别的。最重要的是size和length返回的长度不同的话，那么内部就一定有相应的检测机制。于是，开始找字符编码相关的资料。以结论而言是这样的，UTF-8就是以8位为单元对UCS进行编码。从UCS-2到UTF-8的编码方式如下：",[11,714,715],{},"UCS-2编码(16进制) UTF-8 字节流(二进制)",[717,718,719,722,725],"blockquote",{},[11,720,721],{},"0000 - 007F 0xxxxxxx",[11,723,724],{},"0080 - 07FF 110xxxxx 10xxxxxx",[11,726,727],{},"0800 - FFFF 1110xxxx 10xxxxxx 10xxxxxx",[11,729,730],{},"至于具体编码对应字符是怎样的其实并不重要了，对于分割utf-8字符而言，只要知道编码规则就好了。于是，接下来的工作就简单了。",[31,732,735],{"className":733,"code":734,"language":36},[34],"sum = strlen(fullline);\nfor(int cur = 0;cur\u003Csum;cur++)\n{       \n                char t = fulline[cur];\n        if((t&0xE0) == 0xE0){   \u002F\u002F3byte\n                lines = lines + t + fulline[cur+1] + fulline[cur+2];\n                cur += 3;\n\n        }else if((t&0xC0) == 0xC0){\u002F\u002F2byte\n                lines = lines + t + fulline[cur+1];\n                cur += 2;\n        }else{\u002F\u002F1byte\n            lines = lines + t;\n            cur++;\n        }\n        printf(\"streaming text:%s\",lines.c_str());\n}\n",[38,736,734],{"__ignoreMap":40},[11,738,739],{},"至于GB2312编码，由于固定是双字节的，分割上就不会有什么问题了。",{"title":40,"searchDepth":103,"depth":104,"links":741},[],"2012-12-28",{"layout":112,"status":113,"published":114,"author":744,"author_login":116,"author_email":117,"author_url":118,"wordpress_id":745,"wordpress_url":746,"date_gmt":747,"excerpt":748},{"display_name":116,"login":116,"email":117,"url":118},543,"\u002F\u002F?p=543","2012-12-28 01:35:34 +0000",{"type":8,"value":749},[750],[11,751,706],{},"\u002F2012-12-28-c中文分割",{"title":701,"description":706},"_legacy\u002F2012\u002F2012-12-28-c%e4%b8%ad%e6%96%87%e5%88%86%e5%89%b2",[130,756],"字符串","PPsXuDCUhh7Y4-mLTuw-OHU0BD7oTm--uAo_WcGSsi0",{"id":759,"title":760,"body":761,"date":1404,"description":765,"extension":110,"meta":1405,"navigation":114,"path":1414,"seo":1415,"stem":1416,"tags":1417,"__hash__":1419},"blogs\u002F_legacy\u002F2012\u002F2012-05-03-c%e6%ad%a3%e6%80%81%e9%9a%8f%e6%9c%ba%e6%95%b0%e7%94%9f%e6%88%90.md","C++正态随机数生成",{"type":8,"value":762,"toc":1402},[763,766,773,1190,1199,1202,1380,1399],[11,764,765],{},"最近碰到了c++生成正态随机数的问题，在这里把查到的资料整理一下。",[11,767,768,769,772],{},"正态随机数最便捷的方法是使用libstdc++，在C++11. 26.5-1版本后标准库中已经加入了",[38,770,771],{},"\u003Crandom>","来处理对随机数的生成。下面的代码就是一个简单的生成过程：",[31,774,776],{"className":307,"code":775,"language":309,"meta":40,"style":40},"#include \u003Crandom>\n#include \u003Ctime.h>\n#include \u003Ciostream>\n\ntypedef std::ranlux64_base_01 Myeng;  \ntypedef std::normal_distribution\u003Cdouble> Mydist;\n\nint main( int argc, char* args[] )\n{\n\n  Myeng eng;  \n  eng.seed(time(NULL));\u002F\u002F将时间作为seed\n  Mydist dist(1.5, 2.0);  \n  Mydist::input_type engval = eng();  \n  Mydist::result_type distval = dist(eng); \n\n  distval = distval; \u002F\u002F 防止出现\"xxxx未使用\"的报错  \n  engval = engval;  \n\n  std::cout\u003C\u003Cd\u003C\u003Cstd::endl;\n  std::cout \u003C\u003C \"期望== \" \u003C\u003C dist.mean() \u003C\u003C std::endl;  \n  std::cout \u003C\u003C \"标准差== \" \u003C\u003C dist.sigma() \u003C\u003C std::endl;  \n\n  dist.reset(); \u002F\u002F 清除缓存值  \n  std::cout \u003C\u003C \"随机数1 == \" \u003C\u003C dist(eng) \u003C\u003C std::endl;  \n  std::cout \u003C\u003C \"随机数2 == \" \u003C\u003C dist(eng) \u003C\u003C std::endl;  \n  std::cout \u003C\u003C \"随机数3 == \" \u003C\u003C dist(eng) \u003C\u003C std::endl;  \n\n}\n",[38,777,778,786,793,800,804,815,835,839,870,875,879,887,911,932,953,972,976,989,999,1004,1027,1059,1086,1091,1106,1131,1155,1179,1184],{"__ignoreMap":40},[313,779,780,783],{"class":315,"line":316},[313,781,782],{"class":329},"#include",[313,784,785],{"class":360}," \u003Crandom>\n",[313,787,788,790],{"class":315,"line":103},[313,789,782],{"class":329},[313,791,792],{"class":360}," \u003Ctime.h>\n",[313,794,795,797],{"class":315,"line":104},[313,796,782],{"class":329},[313,798,799],{"class":360}," \u003Ciostream>\n",[313,801,802],{"class":315,"line":387},[313,803,442],{"emptyLinePlaceholder":114},[313,805,806,809,812],{"class":315,"line":403},[313,807,808],{"class":329},"typedef",[313,810,811],{"class":421}," std",[313,813,814],{"class":325},"::ranlux64_base_01 Myeng;  \n",[313,816,817,819,821,824,826,830,832],{"class":315,"line":428},[313,818,808],{"class":329},[313,820,811],{"class":421},[313,822,823],{"class":325},"::normal_distribution",[313,825,336],{"class":329},[313,827,829],{"class":828},"sGZGq","double",[313,831,178],{"class":329},[313,833,834],{"class":325}," Mydist;\n",[313,836,837],{"class":315,"line":439},[313,838,442],{"emptyLinePlaceholder":114},[313,840,841,844,847,850,852,856,858,861,864,867],{"class":315,"line":445},[313,842,843],{"class":828},"int",[313,845,846],{"class":354}," main",[313,848,849],{"class":325},"( ",[313,851,843],{"class":828},[313,853,855],{"class":854},"sbfHu"," argc",[313,857,351],{"class":325},[313,859,860],{"class":828},"char",[313,862,863],{"class":329},"*",[313,865,866],{"class":854}," args",[313,868,869],{"class":325},"[] )\n",[313,871,872],{"class":315,"line":451},[313,873,874],{"class":325},"{\n",[313,876,877],{"class":315,"line":483},[313,878,442],{"emptyLinePlaceholder":114},[313,880,881,884],{"class":315,"line":493},[313,882,883],{"class":421},"  Myeng",[313,885,886],{"class":325}," eng;  \n",[313,888,889,892,895,897,900,902,905,908],{"class":315,"line":509},[313,890,891],{"class":325},"  eng.",[313,893,894],{"class":354},"seed",[313,896,344],{"class":325},[313,898,899],{"class":354},"time",[313,901,344],{"class":325},[313,903,904],{"class":377},"NULL",[313,906,907],{"class":325},"));",[313,909,910],{"class":319},"\u002F\u002F将时间作为seed\n",[313,912,913,916,919,921,924,926,929],{"class":315,"line":523},[313,914,915],{"class":421},"  Mydist",[313,917,918],{"class":354}," dist",[313,920,344],{"class":325},[313,922,923],{"class":377},"1.5",[313,925,351],{"class":325},[313,927,928],{"class":377},"2.0",[313,930,931],{"class":325},");  \n",[313,933,934,936,939,942,945,947,950],{"class":315,"line":536},[313,935,915],{"class":421},[313,937,938],{"class":325},"::",[313,940,941],{"class":421},"input_type",[313,943,944],{"class":325}," engval ",[313,946,330],{"class":329},[313,948,949],{"class":354}," eng",[313,951,952],{"class":325},"();  \n",[313,954,955,957,959,962,965,967,969],{"class":315,"line":548},[313,956,915],{"class":421},[313,958,938],{"class":325},[313,960,961],{"class":421},"result_type",[313,963,964],{"class":325}," distval ",[313,966,330],{"class":329},[313,968,918],{"class":354},[313,970,971],{"class":325},"(eng); \n",[313,973,974],{"class":315,"line":563},[313,975,442],{"emptyLinePlaceholder":114},[313,977,978,981,983,986],{"class":315,"line":568},[313,979,980],{"class":325},"  distval ",[313,982,330],{"class":329},[313,984,985],{"class":325}," distval;",[313,987,988],{"class":319}," \u002F\u002F 防止出现\"xxxx未使用\"的报错  \n",[313,990,991,994,996],{"class":315,"line":574},[313,992,993],{"class":325},"  engval ",[313,995,330],{"class":329},[313,997,998],{"class":325}," engval;  \n",[313,1000,1002],{"class":315,"line":1001},19,[313,1003,442],{"emptyLinePlaceholder":114},[313,1005,1007,1010,1013,1016,1019,1021,1024],{"class":315,"line":1006},20,[313,1008,1009],{"class":421},"  std",[313,1011,1012],{"class":325},"::cout",[313,1014,1015],{"class":329},"\u003C\u003C",[313,1017,1018],{"class":325},"d",[313,1020,1015],{"class":329},[313,1022,1023],{"class":421},"std",[313,1025,1026],{"class":325},"::endl;\n",[313,1028,1030,1032,1035,1037,1040,1043,1046,1049,1052,1054,1056],{"class":315,"line":1029},21,[313,1031,1009],{"class":421},[313,1033,1034],{"class":325},"::cout ",[313,1036,1015],{"class":329},[313,1038,1039],{"class":360}," \"期望== \"",[313,1041,1042],{"class":329}," \u003C\u003C",[313,1044,1045],{"class":325}," dist.",[313,1047,1048],{"class":354},"mean",[313,1050,1051],{"class":325},"() ",[313,1053,1015],{"class":329},[313,1055,811],{"class":421},[313,1057,1058],{"class":325},"::endl;  \n",[313,1060,1062,1064,1066,1068,1071,1073,1075,1078,1080,1082,1084],{"class":315,"line":1061},22,[313,1063,1009],{"class":421},[313,1065,1034],{"class":325},[313,1067,1015],{"class":329},[313,1069,1070],{"class":360}," \"标准差== \"",[313,1072,1042],{"class":329},[313,1074,1045],{"class":325},[313,1076,1077],{"class":354},"sigma",[313,1079,1051],{"class":325},[313,1081,1015],{"class":329},[313,1083,811],{"class":421},[313,1085,1058],{"class":325},[313,1087,1089],{"class":315,"line":1088},23,[313,1090,442],{"emptyLinePlaceholder":114},[313,1092,1094,1097,1100,1103],{"class":315,"line":1093},24,[313,1095,1096],{"class":325},"  dist.",[313,1098,1099],{"class":354},"reset",[313,1101,1102],{"class":325},"();",[313,1104,1105],{"class":319}," \u002F\u002F 清除缓存值  \n",[313,1107,1109,1111,1113,1115,1118,1120,1122,1125,1127,1129],{"class":315,"line":1108},25,[313,1110,1009],{"class":421},[313,1112,1034],{"class":325},[313,1114,1015],{"class":329},[313,1116,1117],{"class":360}," \"随机数1 == \"",[313,1119,1042],{"class":329},[313,1121,918],{"class":354},[313,1123,1124],{"class":325},"(eng) ",[313,1126,1015],{"class":329},[313,1128,811],{"class":421},[313,1130,1058],{"class":325},[313,1132,1134,1136,1138,1140,1143,1145,1147,1149,1151,1153],{"class":315,"line":1133},26,[313,1135,1009],{"class":421},[313,1137,1034],{"class":325},[313,1139,1015],{"class":329},[313,1141,1142],{"class":360}," \"随机数2 == \"",[313,1144,1042],{"class":329},[313,1146,918],{"class":354},[313,1148,1124],{"class":325},[313,1150,1015],{"class":329},[313,1152,811],{"class":421},[313,1154,1058],{"class":325},[313,1156,1158,1160,1162,1164,1167,1169,1171,1173,1175,1177],{"class":315,"line":1157},27,[313,1159,1009],{"class":421},[313,1161,1034],{"class":325},[313,1163,1015],{"class":329},[313,1165,1166],{"class":360}," \"随机数3 == \"",[313,1168,1042],{"class":329},[313,1170,918],{"class":354},[313,1172,1124],{"class":325},[313,1174,1015],{"class":329},[313,1176,811],{"class":421},[313,1178,1058],{"class":325},[313,1180,1182],{"class":315,"line":1181},28,[313,1183,442],{"emptyLinePlaceholder":114},[313,1185,1187],{"class":315,"line":1186},29,[313,1188,1189],{"class":325},"}\n",[11,1191,1192,1193,1198],{},"关于random库的更多的内容可参照",[146,1194,1197],{"href":1195,"rel":1196},"http:\u002F\u002Fgcc.gnu.org\u002Fonlinedocs\u002Flibstdc++\u002Flibstdc++-api-4.6\u002Fa01210.html",[150],"参考文档","，文字太多了我也没仔细看，只是参照别人的代码改了下就拿来用了。",[11,1200,1201],{},"当然，如果你没有使用标准库的习惯的话（其实本人也不是很喜欢用标准库），你也可以利用rand()函数自己生成正态随机数。根据采用的数学原理不同，似乎会用很多种方法。下面的是采用由瑞利分布导出的公式为基础来生成正态随机数的。",[31,1203,1205],{"className":307,"code":1204,"language":309,"meta":40,"style":40},"double carmen_gaussian_random(double mean, double std)\n{\n  const double norm = 1.0 \u002F (RAND_MAX + 1.0);\n  double u = 1.0 - rand() * norm;                  \u002F\u002Fu不能为 0 \n  double v = rand() * norm;     \u002F\u002F由于是伪随机请自行选择seed来保证更真实的随机\n  double z = sqrt(-2.0 * log(u)) * cos(2.0 * M_PI * v);\n  return mean + std * z;\n}\n",[38,1206,1207,1230,1234,1263,1291,1311,1358,1376],{"__ignoreMap":40},[313,1208,1209,1211,1214,1216,1218,1221,1223,1225,1227],{"class":315,"line":316},[313,1210,829],{"class":828},[313,1212,1213],{"class":354}," carmen_gaussian_random",[313,1215,344],{"class":325},[313,1217,829],{"class":828},[313,1219,1220],{"class":854}," mean",[313,1222,351],{"class":325},[313,1224,829],{"class":828},[313,1226,811],{"class":854},[313,1228,1229],{"class":325},")\n",[313,1231,1232],{"class":315,"line":103},[313,1233,874],{"class":325},[313,1235,1236,1239,1242,1245,1247,1250,1253,1256,1259,1261],{"class":315,"line":104},[313,1237,1238],{"class":329},"  const",[313,1240,1241],{"class":828}," double",[313,1243,1244],{"class":325}," norm ",[313,1246,330],{"class":329},[313,1248,1249],{"class":377}," 1.0",[313,1251,1252],{"class":329}," \u002F",[313,1254,1255],{"class":325}," (RAND_MAX ",[313,1257,1258],{"class":329},"+",[313,1260,1249],{"class":377},[313,1262,384],{"class":325},[313,1264,1265,1268,1271,1273,1275,1278,1281,1283,1285,1288],{"class":315,"line":387},[313,1266,1267],{"class":828},"  double",[313,1269,1270],{"class":325}," u ",[313,1272,330],{"class":329},[313,1274,1249],{"class":377},[313,1276,1277],{"class":329}," -",[313,1279,1280],{"class":354}," rand",[313,1282,1051],{"class":325},[313,1284,863],{"class":329},[313,1286,1287],{"class":325}," norm;",[313,1289,1290],{"class":319},"                  \u002F\u002Fu不能为 0 \n",[313,1292,1293,1295,1298,1300,1302,1304,1306,1308],{"class":315,"line":403},[313,1294,1267],{"class":828},[313,1296,1297],{"class":325}," v ",[313,1299,330],{"class":329},[313,1301,1280],{"class":354},[313,1303,1051],{"class":325},[313,1305,863],{"class":329},[313,1307,1287],{"class":325},[313,1309,1310],{"class":319},"     \u002F\u002F由于是伪随机请自行选择seed来保证更真实的随机\n",[313,1312,1313,1315,1318,1320,1323,1325,1328,1330,1333,1336,1339,1341,1344,1346,1348,1350,1353,1355],{"class":315,"line":428},[313,1314,1267],{"class":828},[313,1316,1317],{"class":325}," z ",[313,1319,330],{"class":329},[313,1321,1322],{"class":354}," sqrt",[313,1324,344],{"class":325},[313,1326,1327],{"class":329},"-",[313,1329,928],{"class":377},[313,1331,1332],{"class":329}," *",[313,1334,1335],{"class":354}," log",[313,1337,1338],{"class":325},"(u)) ",[313,1340,863],{"class":329},[313,1342,1343],{"class":354}," cos",[313,1345,344],{"class":325},[313,1347,928],{"class":377},[313,1349,1332],{"class":329},[313,1351,1352],{"class":325}," M_PI ",[313,1354,863],{"class":329},[313,1356,1357],{"class":325}," v);\n",[313,1359,1360,1363,1366,1368,1371,1373],{"class":315,"line":439},[313,1361,1362],{"class":329},"  return",[313,1364,1365],{"class":325}," mean ",[313,1367,1258],{"class":329},[313,1369,1370],{"class":325}," std ",[313,1372,863],{"class":329},[313,1374,1375],{"class":325}," z;\n",[313,1377,1378],{"class":315,"line":445},[313,1379,1189],{"class":325},[11,1381,1382,1383,1387,1388,1391,1392,1395,1396,1398],{},"数学原理的描述是这样的：若x1,x2是（0，1）上的均匀分布则y1=(-2",[1384,1385,1386],"em",{},"ln(x1))^.5","cos(2",[1384,1389,1390],{},"pi","x2)和y2=(-2",[1384,1393,1394],{},"ln(x2))^.5","sin(2",[1384,1397,1390],{},"x1)都是标准正态分布的随机数。",[612,1400,1401],{},"html pre.shiki code .sLXdl, html code.shiki .sLXdl{--shiki-default:#A0111F;--shiki-dark:#F97583;--shiki-sepia:#F92672}html pre.shiki code .sZnmU, html code.shiki .sZnmU{--shiki-default:#032563;--shiki-dark:#9ECBFF;--shiki-sepia:#E6DB74}html pre.shiki code .sfUV7, html code.shiki .sfUV7{--shiki-default:#702C00;--shiki-default-text-decoration:inherit;--shiki-dark:#B392F0;--shiki-dark-text-decoration:inherit;--shiki-sepia:#A6E22E;--shiki-sepia-text-decoration:underline}html pre.shiki code .s0idv, html code.shiki .s0idv{--shiki-default:#0E1116;--shiki-dark:#E1E4E8;--shiki-sepia:#F8F8F2}html pre.shiki code .sGZGq, html code.shiki .sGZGq{--shiki-default:#A0111F;--shiki-default-font-style:inherit;--shiki-dark:#F97583;--shiki-dark-font-style:inherit;--shiki-sepia:#66D9EF;--shiki-sepia-font-style:italic}html pre.shiki code .scAT4, html code.shiki .scAT4{--shiki-default:#622CBC;--shiki-dark:#B392F0;--shiki-sepia:#A6E22E}html pre.shiki code .sbfHu, html code.shiki .sbfHu{--shiki-default:#702C00;--shiki-default-font-style:inherit;--shiki-dark:#FFAB70;--shiki-dark-font-style:inherit;--shiki-sepia:#FD971F;--shiki-sepia-font-style:italic}html pre.shiki code .stP0Q, html code.shiki .stP0Q{--shiki-default:#023B95;--shiki-dark:#79B8FF;--shiki-sepia:#AE81FF}html pre.shiki code .sZdD5, html code.shiki .sZdD5{--shiki-default:#66707B;--shiki-dark:#6A737D;--shiki-sepia:#88846F}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html .sepia .shiki span {color: var(--shiki-sepia);background: var(--shiki-sepia-bg);font-style: var(--shiki-sepia-font-style);font-weight: var(--shiki-sepia-font-weight);text-decoration: var(--shiki-sepia-text-decoration);}html.sepia .shiki span {color: var(--shiki-sepia);background: var(--shiki-sepia-bg);font-style: var(--shiki-sepia-font-style);font-weight: var(--shiki-sepia-font-weight);text-decoration: var(--shiki-sepia-text-decoration);}",{"title":40,"searchDepth":103,"depth":104,"links":1403},[],"2012-05-03",{"layout":112,"status":113,"published":114,"author":1406,"author_login":116,"author_email":117,"author_url":118,"wordpress_id":1407,"wordpress_url":1408,"date_gmt":1409,"excerpt":1410},{"display_name":116,"login":116,"email":117,"url":118},385,"\u002F\u002F?p=385","2012-05-03 14:04:40 +0000",{"type":8,"value":1411},[1412],[11,1413,765],{},"\u002F2012-05-03-c正态随机数生成",{"title":760,"description":765},"_legacy\u002F2012\u002F2012-05-03-c%e6%ad%a3%e6%80%81%e9%9a%8f%e6%9c%ba%e6%95%b0%e7%94%9f%e6%88%90",[130,1418],"正态随机","r8mcpglsX_N-G2IEbBh2R1skcjBHQTg7Ka7m8aKYxKU",1788763180518]