【Visual C++】游戏编程学习笔记之九:回合制游戏demo(剑侠客VS巡游天神)
本系列文章由@二货梦想家张程 所写,转载请注明出处。
作者:ZeeCoder 微博链接:http://weibo.com/zc463717263
我的邮箱:michealfloyd@126.com 欢迎大家发邮件来和我交流编程心得
you are what you read!与大家共勉!
-------------------------------------------------分割线:ZeeCoder--------------------------------------------
本笔记借鉴了经典回合制游戏大作---梦幻西游的战斗场景和音效。
回合制游戏主要利用行为性AI,通常都依靠连续的if....else...以及switch...case...语句来判断和运算,或者利用一些数据结构的概念
一、计算机角色的思考和行为
在本游戏demo中,巡游天神(计算机)的行为主要有以下:
1.普通攻击
2.泰山压顶
3.地狱烈火
4.回血
5.逃跑
那么在游戏编程设计中,我们可以定义一个int型kind(表示攻击类型),然后通过switch...case语句来做出相应判断
if (s_monster.nHp > 200)//当怪物血量小于200时
{
if (rand()%3 != 1)
{
//普通攻击,2/3几率
}
else
{
//进行泰山压顶攻击,1/3几率
}
}
else
{
switch(rand()%5)
{
case 0://使用普通攻击
break;
case 1://使用泰山魔法攻击
break;
case 2://使用地狱烈火
break;
case 3://回血
break;
case 4://逃跑
break;
}
}
二、玩家角色攻击和行为
本游戏中玩家为剑侠客,他主要有两个技能加一个暴击:
1、剑击
2、雷电诀
3、暴击(十分之一概率)
判断剑侠客释放哪个技能主要通过鼠标左键单击。
case WM_LBUTTONDOWN:
if (!attack_1 && !attack_2) //当没有按下攻击按钮
{
x = LOWORD(lParam);//获取游戏鼠标坐标
y = HIWORD(lParam);
if ( x >= 80 && y >= 150 && x <= 113 && y <= 183 )//判断是否按下了剑击按钮
{
attack_1 = true ;
attack_2 = false ;
}
if ( x >= 80 && y >= 200 && x <= 113 && y <= 233 )//判断是否按下了雷神诀按钮
{
attack_1 = false ;
attack_2 = true ;
}
}
玩家按下技能按钮后,需要判断行为。
if (attack_1 && !attack_2) //释放剑击技能
{
//添加行为
}
else if (!attack_1 && attack_2)//释放雷击技能
{
//添加行为
}
if ( frame ==10)//第十个画面统计怪物收到的伤害值并显示
{
if ( 4 == rand()%10)//百分之十几率释放暴击技能
{
//添加行为
}
else
{
if (!attack_1 && attack_2) //释放雷击技能
{
//添加行为
}
else if (attack_1 && !attack_2)//释放剑击技能
{
//添加行为
}
}
}
三、下面来看整个demo的完整代码。
1、为了偷懒使用了TransparentBlt进行透明贴图,效果感觉和bitblt差不多。可能是我P图没P好的原因吧。
2、本demo利用msi类,添加了战斗音效。效果还是很酷炫的,代码也不叫简单。
#include "stdafx.h"
#include "GameDemo.h"
#define MAX_LOADSTRING 100
#pragma comment (lib , "msimg32.lib")
#include <Mmsystem.h>
#pragma comment(lib, "Winmm.lib")
//定义结构
struct state
{
int nHp; //目前生命值
int mHp; //最大生命值
int lv; //怪物等级
int Weight; //加权值
int kind; //怪物的行为代号
};
//全局变量
HINSTANCE hInst;
HBITMAP bg , h_monster , h_player , skill1 , skill2 , sword , thunder, stick ,hill ,blaze ,recover,gameover,baoji;
HDC hdc , mdc , bufdc;
HWND hWnd;
DWORD tNow , tPre;
state s_player , s_monster;
bool attack_1,attack_2 , over ;
TCHAR text[5][100];
int pNum , mNum ,frame , textNum;
//函数声明
ATOM MyRegisterClass(HINSTANCE hInstance);
BOOL InitInstance(HINSTANCE, int);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM);
void GameRun(HDC hdc);
void MsgInsert(TCHAR* str);
void CheckDie(int hp , bool player);
//***************************WinMain主函数**********************************
int APIENTRY _tWinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPTSTR lpCmdLine,
int nCmdShow)
{
MSG msg;
//调用窗口类函数
MyRegisterClass(hInstance);
//初始化
if (!InitInstance (hInstance, nCmdShow))
{
return FALSE;
}
//消息循环
GetMessage(&msg,NULL,NULL,NULL); //初始化msg
while (msg.message != WM_QUIT)
{
if ( PeekMessage( &msg , NULL ,0 ,0 ,PM_REMOVE))//PM_REMOVE消息从队列里除掉
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else
{
tNow = GetTickCount();//获取当前时间
if (tNow - tPre >= 100)//实现游戏循环
{
GameRun(hdc);//循环贴图
}
}
}
return (int) msg.wParam;
}
//***************************窗口类函数**********************************
ATOM MyRegisterClass(HINSTANCE hInstance)
{
WNDCLASSEX wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
wcex.lpfnWndProc = WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = NULL;
wcex.hCursor = NULL;
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName = MAKEINTRESOURCE(IDC_GAMEDEMO);
wcex.lpszClassName = _T("Game");
wcex.hIconSm = NULL;
return RegisterClassEx(&wcex);
}
//***************************初始化函数**********************************
//实现功能:加载位图并给各变量设定初始值
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
HBITMAP bmp;
hInst = hInstance; // Store instance handle in our global variable
hWnd = CreateWindow(_T("Game"), _T("致经典--梦幻西游"), WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);
if (!hWnd)
{
return FALSE;
}
MoveWindow(hWnd , 10 , 10 , 640 ,480 ,true);
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
hdc = GetDC(hWnd);
mdc = CreateCompatibleDC(hdc);
bufdc = CreateCompatibleDC(hdc);
bmp = CreateCompatibleBitmap(hdc , 640 , 480);
SelectObject(mdc , bmp);
//载入位图
bg = (HBITMAP)LoadImage(NULL , _T("Res\\bg.bmp") , IMAGE_BITMAP , 640 ,480 , LR_LOADFROMFILE);//背景图
h_monster = (HBITMAP)LoadImage(NULL , _T("Res\\monster.bmp") , IMAGE_BITMAP , 640 , 144 , LR_LOADFROMFILE);//怪物图
h_player = (HBITMAP)LoadImage(NULL , _T("Res\\player.bmp") , IMAGE_BITMAP , 448 , 91 , LR_LOADFROMFILE);//玩家图
skill1 = (HBITMAP)LoadImage(NULL , _T("Res\\skill1.bmp") , IMAGE_BITMAP , 33 ,33 , LR_LOADFROMFILE);//技能1
skill2 = (HBITMAP)LoadImage(NULL , _T("Res\\skill2.bmp") , IMAGE_BITMAP , 33 ,33 , LR_LOADFROMFILE);//技能2
baoji = (HBITMAP)LoadImage(NULL , _T("Res\\baoji.bmp") , IMAGE_BITMAP , 160 ,84 , LR_LOADFROMFILE);//暴击
sword = (HBITMAP)LoadImage(NULL , _T("Res\\sword.bmp") , IMAGE_BITMAP , 200 ,102 , LR_LOADFROMFILE);//玩家使用剑击
thunder = (HBITMAP)LoadImage(NULL , _T("Res\\thunder.bmp") , IMAGE_BITMAP , 160 ,210 , LR_LOADFROMFILE);//雷击效果图
stick = (HBITMAP)LoadImage(NULL , _T("Res\\stick.bmp") , IMAGE_BITMAP , 1100 ,720 , LR_LOADFROMFILE);//巡游棍击
blaze = (HBITMAP)LoadImage(NULL , _T("Res\\blaze.bmp") , IMAGE_BITMAP , 88 ,79 , LR_LOADFROMFILE);//火焰效果图
hill = (HBITMAP)LoadImage(NULL , _T("Res\\hill.bmp") , IMAGE_BITMAP , 80 ,64 , LR_LOADFROMFILE);//泰山压顶
//recover = (HBITMAP)LoadImage(NULL , _T("Res\\recover.bmp") , IMAGE_BITMAP , 1100 ,720 , LR_LOADFROMFILE);//回血效果图
gameover = (HBITMAP)LoadImage(NULL , _T("Res\\gameover.bmp") , IMAGE_BITMAP , 400 ,100 , LR_LOADFROMFILE);//游戏结束
s_player.nHp = s_player.mHp = 130;
s_player.lv = 3 ;
s_player.Weight = 5 ;
s_monster.nHp = s_monster.mHp = 400;
s_monster.lv = 1;
s_monster.Weight = 1;
textNum = 0 ;
SetBkMode(mdc , TRANSPARENT); //设置TextOut背景透明
GameRun(hdc);
return TRUE;
}
//***************************消息响应函数**********************************
// 判断玩家是否使用攻击命令
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
int x , y ;
switch (message)
{
case WM_KEYDOWN:
if (wParam == VK_ESCAPE)//【Esc】退出游戏
PostQuitMessage(0);
break;
case WM_LBUTTONDOWN:
if (!attack_1 && !attack_2) //当没有按下攻击按钮
{
x = LOWORD(lParam);
y = HIWORD(lParam);
if ( x >= 80 && y >= 150 && x <= 113 && y <= 183 )//判断是否按下了剑击按钮
{
attack_1 = true ;
attack_2 = false ;
mciSendString(L"open Audio\\sword.mp3 alias sword", NULL, 0, NULL);
mciSendString(L"play sword ", NULL, 0, NULL);
}
if ( x >= 80 && y >= 200 && x <= 113 && y <= 233 )//判断是否按下了雷击按钮
{
attack_1 = false ;
attack_2 = true ;
mciSendString(L"open Audio\\thunder.mp3 alias thunder", NULL, 0, NULL);
mciSendString(L"play thunder ", NULL, 0, NULL);
}
}
break;
case WM_DESTROY:
DeleteDC(mdc);
DeleteDC(bufdc);
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
//********************************自定义游戏回合开始函数***********************
//实现功能:
//1.贴战斗实时战况消息
//2.怪物及玩家行为判断及血量等各项数据的计算
void GameRun(HDC hdc)
{
TCHAR str[100] ;
memset(str , 0 ,sizeof(TCHAR)*100);
int i , damage;
//播放背景音乐
mciSendString(L"open Audio\\bgm.mp3 alias bgm", NULL, 0, NULL);
mciSendString(L"play bgm repeat", NULL, 0, NULL);
//贴上背景图
SelectObject(bufdc , bg);
BitBlt(mdc , 0 , 0 , 640 , 480 , bufdc , 0 , 0 ,SRCCOPY);
//显示战况消息
for (i = 0 ; i < 6 ; i++)
{
TextOut(mdc , 0 , 300 + i*18, text[i] , _tcslen(text[i]));
}
//贴上怪物图
if (s_monster.nHp > 0)//如果怪物没死
{
SelectObject(bufdc , h_monster);
// BitBlt(mdc,700,250,78,94,bufdc,mNum*78,94,SRCAND);
// BitBlt(mdc,700,250,78,94,bufdc,mNum*78,0,SRCPAINT);
TransparentBlt(mdc , 400 , 100 ,160 , 144 , bufdc , mNum*160 , 0 ,160 , 144 , RGB(62,91,167));
_stprintf_s(str , TEXT("%d / %d") , s_monster.nHp , s_monster.mHp);
SetTextColor(mdc , RGB(0,135,0));
TextOut(mdc , 430 , 90 , str , _tcslen(str));
}
//贴上玩家图
if (s_player.nHp > 0)
{
SelectObject(bufdc , h_player);
// BitBlt(mdc,200,200,53,137,bufdc,pNum*53,137,SRCAND);
// BitBlt(mdc,200,200,53,137,bufdc,pNum*53,0,SRCPAINT);
TransparentBlt(mdc , 130 , 135 , 56 , 91 , bufdc , pNum*56 , 0 ,56 , 91 , RGB(62,91,167));//透明贴图
_stprintf_s(str , TEXT("%d / %d") , s_player.nHp , s_player.mHp);
TextOut(mdc , 130 , 120 , str , _tcslen(str));
}
//贴上游戏结束图画
if (over)
{
SelectObject(bufdc , gameover);
TransparentBlt(mdc , 120 , 130 , 400 , 100 , bufdc , 0 , 0 ,400 , 100 , RGB(255,255,255));//透明贴图
}
//贴上技能图
else if (!attack_1 && !attack_2)//没有攻击命令
{
SelectObject(bufdc , skill1);
BitBlt(mdc , 80 , 150 , 33 , 33 , bufdc , 0 , 0 , SRCCOPY);
SelectObject(bufdc , skill2);
BitBlt(mdc , 80 , 200 , 33 , 33 , bufdc , 0 , 0 , SRCCOPY);
}
else
{
frame++;
//第五到十个画面显示玩家攻击状态
if ( frame >=5 && frame <= 10)
{
if (attack_1 && !attack_2) //释放剑击技能
{
SelectObject(bufdc , sword);
mciSendString(L"close sword ", NULL, 0, NULL);
//剑击效果图
TransparentBlt(mdc , 200 , 130 , 200 , 102 , bufdc , 0 , 0 ,200 , 102 , RGB(255,0,0));//透明贴图
}
else if (!attack_1 && attack_2)//释放雷击技能
{
SelectObject(bufdc , thunder);
mciSendString(L"close thunder ", NULL, 0, NULL);
//雷击效果图
TransparentBlt(mdc , 400 , 80 , 160 , 210 , bufdc , 0 , 0 ,160 , 210 , RGB(255,255,255));//透明贴图
}
if ( frame ==10)//第十个画面统计怪物收到的伤害值并显示
{
if ( 4 == rand()%10)//百分之十几率释放暴击技能
{
damage = 4*(rand()%10 + s_player.lv * s_player.Weight);
s_monster.nHp -= (int)damage;
//贴上暴击效果图
_stprintf_s(str , TEXT("剑侠客使出浑身力气,4倍暴击。。。!!巡游天兵血量瞬间下降%d") , damage);
}
else
{
if (!attack_1 && attack_2) //释放雷击技能
{
damage = 1.5*(rand()%10 + s_player.lv * s_player.Weight);
s_monster.nHp -= (int)damage;
_stprintf_s(str , TEXT("剑侠客释放雷击技能,巡游天兵被从天而降的雷劈掉了%d伤害") , damage);
}
else if (attack_1 && !attack_2)//释放剑击技能
{
damage = rand()%10 + s_player.lv * s_player.Weight;
s_monster.nHp -= (int)damage;
_stprintf_s(str , TEXT("剑侠客一剑刺向巡游天兵,巡游天兵躲闪不及,生命值减少%d") , damage);
}
}
MsgInsert(str);
CheckDie(s_monster.nHp , false);
}
}
srand(tPre);//使得每次产生的随机数不一样
//第十五个画面判断怪物进行哪项动作
if (frame == 15)
{
if (s_monster.nHp > 200)
{
if (rand()%3 != 1)
{
s_monster.kind = 0; //普通攻击,2/3
mciSendString(L"open Audio\\stick.mp3 alias stick", NULL, 0, NULL);//播放音效
mciSendString(L"play stick ", NULL, 0, NULL);
}
else
{
s_monster.kind = 1;//进行泰山压顶攻击,1/3
mciSendString(L"open Audio\\hill.mp3 alias hill", NULL, 0, NULL);//播放音效
mciSendString(L"play hill ", NULL, 0, NULL);
}
}
else
{
switch(rand()%5)
{
case 0://使用普通攻击
s_monster.kind = 0 ;
break;
case 1://使用泰山魔法攻击
s_monster.kind = 1 ;
break;
case 2://使用地狱烈火
mciSendString(L"open Audio\\blaze.mp3 alias blaze", NULL, 0, NULL);//播放音效
mciSendString(L"play blaze ", NULL, 0, NULL);
s_monster.kind = 2 ;
break;
case 3://回血
s_monster.kind = 3 ;
break;
case 4://逃跑
s_monster.kind = 4 ;
break;
}
}
}
if ( frame >= 26 && frame <= 30)//第26~30个画面显示巡游攻击状态动画
{
switch (s_monster.kind)
{
case 0://使用普通攻击
SelectObject(bufdc , stick);
mciSendString(L"close stick ", NULL, 0, NULL);
//第30个画面时计算玩家受到的伤害程序并显示消息
if (frame == 30)
{
damage = rand()%10 + s_monster.lv*s_monster.Weight;
s_player.nHp -= (int)damage;
_stprintf_s(str , TEXT("巡游一棍打向剑侠客,正中额头,伤害-%d") , damage);
MsgInsert(str);
CheckDie(s_player.nHp , true);
}
break;
case 1://使用泰山压顶攻击
SelectObject(bufdc , hill);
mciSendString(L"close hill ", NULL, 0, NULL);
TransparentBlt(mdc , 120 , 135 , 80 , 64 , bufdc , 0 , 0 ,80 , 64 , RGB(0,0,0));//透明贴图
//第30个画面时计算玩家受到的伤害程序并显示消息
if (frame == 30)
{
damage = 1.5*(rand()%10 + s_monster.lv*s_monster.Weight);
s_player.nHp -= (int)damage;
_stprintf_s(str , TEXT("巡游怒喝一声,泰山压顶!!呀哈哈哈!,剑侠客血量-%d") , damage);
MsgInsert(str);
CheckDie(s_player.nHp , true);
}
break;
case 2://使用地狱烈火
SelectObject(bufdc , blaze);
mciSendString(L"close blaze ", NULL, 0, NULL);
TransparentBlt(mdc , 120 , 135 , 88 , 79 , bufdc , 0 , 0 ,88 , 79 , RGB(0,0,0));//透明贴图
//第30个画面时计算玩家受到的伤害程序并显示消息
if (frame == 30)
{
damage = 3*(rand()%10 + s_monster.lv*s_monster.Weight);
s_player.nHp -= (int)damage;
_stprintf_s(str , TEXT("巡游口里念着咒语,地狱烈火!剑侠客在熊熊烈火中痛不欲生,伤害-%d") , damage);
MsgInsert(str);
CheckDie(s_player.nHp , true);
}
break;
case 3://回血
// SelectObject(bufdc , recover);
//第30个画面时计算玩家受到的伤害程序并显示消息
if (frame == 30)
{
s_monster.nHp += 50;
_stprintf_s(str , TEXT("普渡众生,巡游回复了50点生命值") );
MsgInsert(str);
}
break;
case 4://逃跑
//第30个画面时计算玩家受到的伤害程序并显示消息
if (frame == 30)
{
if (1 == rand()%3)
{
over = true;
s_monster.nHp = 0;
_stprintf_s(str , TEXT("巡游落荒而逃....逃跑成功") );
MsgInsert(str);
}
else
{
_stprintf_s(str , TEXT("巡游落荒而逃....逃跑失败") );
MsgInsert(str);
}
}
break;
}
}
if (frame == 30)//第30个画面回合结束
{
attack_1 = attack_2 = false;
frame = 0;
}
}
BitBlt(hdc , 0 ,0 ,640 ,480 ,mdc , 0 , 0 ,SRCCOPY);
tPre = GetTickCount();
//动画循环变量
pNum++;
mNum++;
if(pNum == 8)
pNum = 0;
if (mNum == 4)
mNum = 0;
}
//对战消息显示函数
void MsgInsert(TCHAR* str)
{
if (textNum < 5)
{
_stprintf_s(text[textNum] , str);
textNum ++;
}
else
{
for (int i = 0 ; i < textNum ; i++)
{
_stprintf_s(text[i],text[i+1]);
}
_stprintf_s(text[4] , str);
}
}
void CheckDie(int hp , bool player)
{
TCHAR str[100] ;
memset(str , 0 ,sizeof(TCHAR)*100);
if (hp <= 0)
{
over = true;
if (player)
{
_stprintf_s(str,TEXT("胜败乃兵家常事,少侠请重新来过....."));
MsgInsert(str);
}
else
{
_stprintf_s(str,TEXT("恭喜少侠,你赢了,巡游被你打死了...."));
MsgInsert(str);
}
}
}
四、效果图
笔记九over~~这个游戏demo算是比较完整的梦幻西游一个回合的再现,包括:游戏音效,战斗动画,战斗情况显示等。搜集素材比较费力,做一个游戏还真是不容易啊。~希望在游戏编程上奋斗的人能够耐得住性子,尽量把自己的游戏做得完美~与大家共勉~!!
---end
本笔记配套代码已上传,希望大家能够下载下来,运行,音效和动画还是挺好的。
【Visual C++】游戏编程学习笔记之九:回合制游戏demo(剑侠客VS巡游天神)的更多相关文章
- 【Visual C++】游戏编程学习笔记之四:透明动画实现
本系列文章由@二货梦想家张程 所写,转载请注明出处. 本文章链接:http://blog.csdn.net/terence1212/article/details/44224963 作者:ZeeCod ...
- 【Visual C++】游戏编程学习笔记之八:鼠标输入消息(小demo)
本系列文章由@二货梦想家张程 所写,转载请注明出处. 作者:ZeeCoder 微博链接:http://weibo.com/zc463717263 我的邮箱:michealfloyd@126.c ...
- 【Visual C++】游戏编程学习笔记之七:键盘输入消息
本系列文章由@二货梦想家张程 所写,转载请注明出处. 作者:ZeeCoder 微博链接:http://weibo.com/zc463717263 我的邮箱:michealfloyd@126.c ...
- 【Visual C++】游戏编程学习笔记之六:多背景循环动画
本系列文章由@二货梦想家张程 所写,转载请注明出处. 本文章链接:http://blog.csdn.net/terence1212/article/details/44264153 作者:ZeeCod ...
- DirectX 11游戏编程学习笔记之8: 第6章Drawing in Direct3D(在Direct3D中绘制)(习题解答)
本文由哈利_蜘蛛侠原创,转载请注明出处.有问题欢迎联系2024958085@qq.com 注:我给的电子版是700多页,而实体书是800多页,所以我在提到相关概念的时候 ...
- DirectX 11游戏编程学习笔记之6: 第5章The Rendering Pipeline(渲染管线)
本文由哈利_蜘蛛侠原创,转载请注明出处.有问题欢迎联系2024958085@qq.com 注:我给的电子版是700多页,而实体书是800多页,所以我在提到相关概念的时候 ...
- 【Visual C++】游戏编程学习笔记之五:单一背景滚动
本系列文章由@二货梦想家张程 所写,转载请注明出处. 本文章链接:http://blog.csdn.net/terence1212/article/details/44224963 作者:ZeeCod ...
- 【Visual C++】游戏编程学习笔记之三:游戏循环的使用
本系列文章由@二货梦想家张程 所写,转载请注明出处. 本文章链接:http://blog.csdn.net/terence1212/article/details/44208419 作者:Zee ...
- 【Visual C++】游戏编程学习笔记之二:定时器的使用
本系列文章由@二货梦想家张程所写,转载请注明出处. 本文章链接:http://blog.csdn.net/terence1212/article/details/44195831 作者:ZeeCode ...
随机推荐
- RunLoop总结:RunLoop的应用场景(三)
今天要讲的RunLoop的应用场景可能太简单了,所以东西比较少.因为跟UITableView.UICollectionView等的滑动优化有关,就顺便总结一下会影响UITableView.UIColl ...
- iOS 中隐藏UITableView最后一条分隔线
如何优雅的隐藏UITableView中最后一条分割线? 这个问题是很常见,却又不太容易解决的. 可能通常的做法都是隐藏UITableView的分割线,自定义一条. 最近在使用弹出菜单的时候,同样遇到了 ...
- Android 在 SElinux下 如何获得对一个内核节点的访问权限
点击打开链接 Android 5.0下,因为采取了SEAndroid/SElinux的安全机制,即使拥有root权限,或者对某内核节点设置为777的权限,仍然无法在JNI层访问. 本文将以用户自定义的 ...
- SQL Server 索引维护(1)——如何获取索引使用情况
前言: 在前面一文中,已经提到了三类常见的索引问题,那么问题来了,当系统出现这些问题时,该如何应对? 简单而言,需要分析现有系统的行为,然后针对性地对索引进行处理: 对于索引不足的情况:检查缺少索引的 ...
- Android简易实战教程--第二十一话《内容观察者监听数据库变化》
当数据库的数据发生改变,我们又想知道具体改变的情况时,就需要对数据库的变化情况做一个监控.这个任务,就由内容观察者来完成.下面这个案例,为短信数据库注册内容观察者,来监控短信的变化情况,当短信数据库发 ...
- Retrofit2.0 ,OkHttp3完美同步持久Cookie实现免登录(二)
原文出自csdn: http://blog.csdn.net/sk719887916/article/details/51700659: 通过对Retrofit2.0的<Retrofit 2.0 ...
- NV12和NV21转rgb
void NV21_T_RGB(unsigned int width , unsigned int height , unsigned char *yuyv , unsigned char *rgb) ...
- Android首选项SharedPreference-android学习之旅(六)
SharedPrefenence采用的键值对的方式来进行存储,采用内部存储的方式. 实例 public class MainActivity extends Activity { private Sh ...
- HashMap方法介绍
1. Map的遍历方式 (1) for each map.entrySet() Map<String, String> map = new HashMap<String, Strin ...
- inline内联函数
demo //带参数的宏 #define MYFUNC(a, b) ((a) < (b) ? (a) : (b)) inline int myfunc(int a, int b) { retur ...