本系列文章由zhmxy555编写,转载请注明出处。 文章链接  http://blog.csdn.net/zhmxy555/article/details/7447864

作者:毛星云    邮箱: happylifemxy@qq.com    欢迎邮件交流编程心得

这节笔记的主要内容是介绍一个完整的回合制游戏demo,而这个demo里面主要突出了游戏里AI的各种思考与行为的方式.这样的通过计算机角色本身的判断思考,然后产生对应行为的AI称作行为型游戏AI。

如果对AI基础不太了解的朋友,请移步:

【Visual C++】游戏开发笔记十五 游戏人工智能(一) 运动型游戏AI

首先,我们来了解这种行为型AI的设计方法。

游戏程序中计算机角色的思考与行为,实际上是对各种不同事件进行分析思考,然后根据不同的情况作出相应的反应。但如何对发生的条件进行判断,并作出相应的反应呢?

对,我们可以利用“if-else”条件句以及“switch-case”语句这类的判断式来完成。

通常情况下,设计此类AI,会涉及到连串的条件判断句,简单数学运算,及一些数据结构的知识。

下面我们就来具体讲解这个demo涉及到的一些知识点:

一、AI怪物攻击与思考方式设计

例如今天我们要展示的这个回合制游戏demo里的AI,就有如下几种行为:

(1)利爪攻击

(2)闪电链攻击

(3)致命一击

(4)使用梅肯斯姆回复生命值

(5)逃跑

那么我们可以根据以上设计的怪物行为,设计以下一段算法,用来模拟怪物对战时的思考与行为的方式:

if(monster.nHp > 20)     //生命值大于20
{
if(rand()%5!= 1)           //进行利爪攻击概率4/5
else//进行闪电链攻击概率1/5
}
else     //生命值小于20
{
switch(rand()%5)
{
case 0:  //利爪攻击
break;
case 1:  //释放闪电链
break;
case 2:  //致命一击
break;
case 3:  //使用梅肯斯姆回复  ;
break;
case 4:  //逃跑
if(1== rand()%3 )     //逃跑成功几率1/3
//逃跑成功
else
//逃跑失败
break;
}
}

这段代码中,利用if-else判断式判断怪物生命值,然后怪物有4/5的几率释放普通的利爪攻击,有1/5的几率释放闪电链魔法攻击,当怪物重伤生命值小于20点时,也有一定的几率逃跑。

以上的利用“if-else”、“switch”语句,使计算机角色进行事件情况判断,然后写出相应的动作实现代码,这就是行为型游戏AI

设计的核心精神。

二,玩家角色攻击方式设计

然后我们再来设计一下玩家的攻击技能。

今天放出的这个demo里我给人物设定了两个技能,一个主动的普通攻击技能“无敌斩”,伤害计算公式为damage = rand()%10 + player.lv*player.w(player.lv为角色等级,player.w为攻击系数)。

而被动技能为可以有一定几率打出4倍暴击伤害的“恩赐解脱”,这个技能是Dota里面幻影刺客的大招(呵呵,浅墨玩dota时可是超级幻刺控~~)。

其实暴击的实现方式很简单,就是用if条件句进行概率的判断(浅墨在这里利用4==rand( )%5来设定暴击概率为20%),如果判断成功就将“倍率x普通攻击”作为damage的值。

(哈哈,浅墨专门找到了Dota里面这两个技能的图标以及用到了这个demo里面,具体效果图在下面)

下面贴出代码人物技能的代码:

if (4==rand()%5)                   // 20%几率触发幻影刺客的大招,恩赐解脱,4倍暴击伤害
{
damage = 4*(rand()%10 + player.lv*player.w);
monster.nHp -= (int)damage;
sprintf(str,"恩赐解脱触发,这下牛逼了,4倍暴击...对怪物照成了%d点伤害",damage);
}
else
{
damage = rand()%10 + player.lv*player.w;
monster.nHp -= (int)damage;
sprintf(str,"玩家使用了无敌斩,伤害一般般...对怪物照成了%d点伤害",damage);
}

三、完整的回合制游戏源代码

基础部分就讲解完了,下面就贴出注释详细的,完整的回合制游戏demo的代码吧:

#include "stdafx.h"
#include <stdio.h>
//定义一个结构体
struct chr
{
int  nHp;
int  fHp;
int  lv;
int  w;
int  kind;
};
//全局变量声明
HINSTANCE hInst;
HBITMAP bg,sheep,girl,skill,skillult,slash,magic,recover,game;
HDC  hdc,mdc,bufdc;
HWND    hWnd;
DWORD   tPre,tNow;
int  pNum,f,txtNum;
bool    attack,over;
chr  player,monster;
char    text[5][100];
//全局函数声明
ATOM     MyRegisterClass(HINSTANCE hInstance);
BOOL     InitInstance(HINSTANCE, int);
LRESULT CALLBACK    WndProc(HWND, UINT, WPARAM, LPARAM);
void     MyPaint(HDC hdc);
void     MsgInsert(char*);
void     CheckDie(int hp,bool player);
//****WinMain函数,程序入口点函数**************************************
int APIENTRY WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR     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) ){TranslateMessage( &msg );DispatchMessage( &msg );}
else
{
tNow = GetTickCount();
if(tNow-tPre >= 40)
MyPaint(hdc);
}}
return msg.wParam;
}
//***设计一个窗口类,类似填空题,使用窗口结构体*************************
ATOM MyRegisterClass(HINSTANCE hInstance)
{
WNDCLASSEX wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style   = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
wcex.lpfnWndProc    = (WNDPROC)WndProc;
wcex.cbClsExtra  = 0;
wcex.cbWndExtra  = 0;
wcex.hInstance   = hInstance;
wcex.hIcon   = NULL;
wcex.hCursor     = NULL;
wcex.hCursor     = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground  = (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName   = NULL;
wcex.lpszClassName  = "canvas";
wcex.hIconSm     = NULL;
return RegisterClassEx(&wcex);
}
//****初始化函数************************************
//加载位图并设定各种初始值
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
HBITMAP bmp;
hInst = hInstance;
hWnd = CreateWindow("canvas", "浅墨的绘图窗口" , WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);
if (!hWnd)
{
return FALSE;
}
MoveWindow(hWnd,10,10,640,510,true);
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
hdc = GetDC(hWnd);
mdc = CreateCompatibleDC(hdc);
bufdc = CreateCompatibleDC(hdc);
bmp = CreateCompatibleBitmap(hdc,640,510);
SelectObject(mdc,bmp);
bg = (HBITMAP)LoadImage(NULL,"bg.bmp",IMAGE_BITMAP,640,510,LR_LOADFROMFILE);
sheep = (HBITMAP)LoadImage(NULL,"sheep.bmp",IMAGE_BITMAP,133,220,LR_LOADFROMFILE);
girl = (HBITMAP)LoadImage(NULL,"girl.bmp",IMAGE_BITMAP,480,148,LR_LOADFROMFILE);
skill = (HBITMAP)LoadImage(NULL,"skill.bmp",IMAGE_BITMAP,50,50,LR_LOADFROMFILE);
skillult = (HBITMAP)LoadImage(NULL,"skillult.bmp",IMAGE_BITMAP,50,50,LR_LOADFROMFILE);
slash = (HBITMAP)LoadImage(NULL,"slash.bmp",IMAGE_BITMAP,196,162,LR_LOADFROMFILE);
magic = (HBITMAP)LoadImage(NULL,"magic.bmp",IMAGE_BITMAP,200,100,LR_LOADFROMFILE);
recover = (HBITMAP)LoadImage(NULL,"recover.bmp",IMAGE_BITMAP,300,150,LR_LOADFROMFILE);
game = (HBITMAP)LoadImage(NULL,"over.bmp",IMAGE_BITMAP,289,74,LR_LOADFROMFILE);
player.nHp = player.fHp = 50; //设定玩家角色声明值及上限
player.lv = 2;  //设定玩家角色等级
player.w  = 4;  //设定攻击伤害加权值
monster.nHp = monster.fHp = 120;  //设定怪物角色生命值及上限
monster.lv = 1;     //设定怪物角色等级
monster.w = 1;  //设定攻击伤害加权值
txtNum = 0;     //显示消息数目
SetBkMode(mdc, TRANSPARENT);    //设置TextOut背景透明
MyPaint(hdc);
return TRUE;
}
//****自定义绘图函数*********************************
// 1.画面贴图与对战消息显示
// 2.怪物行为判断及各项数据处理与计算
void MyPaint(HDC hdc)
{
char str[100];
int i,damage;
//贴上背景图
SelectObject(bufdc,bg);
BitBlt(mdc,0,0,640,510,bufdc,0,0,SRCCOPY);
//显示对战消息
for(i=0;i<txtNum;i++)
TextOut(mdc,0,360+i*18,text[i],strlen(text[i]));
//贴上怪物图
if(monster.nHp>0)
{
SelectObject(bufdc,sheep);
BitBlt(mdc,70,180,133,110,bufdc,0,110,SRCAND);
BitBlt(mdc,70,180,133,110,bufdc,0,0,SRCPAINT);
sprintf(str,"%d / %d",monster.nHp,monster.fHp);
TextOut(mdc,100,320,str,strlen(str));
}
//贴上玩家图
if(player.nHp>0)
{
SelectObject(bufdc,girl);
BitBlt(mdc,500,200,60,74,bufdc,pNum*60,74,SRCAND);
BitBlt(mdc,500,200,60,74,bufdc,pNum*60,0,SRCPAINT);
sprintf(str,"%d / %d",player.nHp,player.fHp);
TextOut(mdc,510,320,str,strlen(str));
}
if(over)     //贴上游戏结束图画
{
SelectObject(bufdc,game);
BitBlt(mdc,200,200,289,37,bufdc,0,37,SRCAND);
BitBlt(mdc,200,200,289,37,bufdc,0,0,SRCPAINT);
}
else if(!attack)     //贴上攻击命令图画
{
SelectObject(bufdc,skill);
BitBlt(mdc,500,350,50,50,bufdc,0,0,SRCCOPY);
SelectObject(bufdc,skillult);
BitBlt(mdc,430,350,50,50,bufdc,0,0,SRCCOPY);
//BitBlt(mdc,500,350,74,30,bufdc,0,30,SRCAND);
//BitBlt(mdc,500,350,74,30,bufdc,0,0,SRCPAINT);
}
else
{
f++;
//第5~10个画面时显示玩家攻击图标
if(f>=5 && f<=10)
{
SelectObject(bufdc,slash);
BitBlt(mdc,100,160,98,162,bufdc,98,0,SRCAND);
BitBlt(mdc,100,160,98,162,bufdc,0,0,SRCPAINT);
//第10个画面时计算怪物受伤害程度并加入显示消息
if(f == 10)
{
if (4==rand()%5)                   // 20%几率触发幻影刺客的大招,恩赐解脱,4倍暴击伤害
{
damage = 4*(rand()%10 + player.lv*player.w);
monster.nHp -= (int)damage;
sprintf(str,"恩赐解脱触发,这下牛逼了,4倍暴击...对怪物照成了%d点伤害",damage);
}
else
{
damage = rand()%10 + player.lv*player.w;
monster.nHp -= (int)damage;
sprintf(str,"玩家使用了无敌斩,伤害一般般...对怪物照成了%d点伤害",damage);
}
MsgInsert(str);
CheckDie(monster.nHp,false);
}
}
srand(tPre);
//第15个画面时判断怪物进行哪项动作
if(f == 15)
{
if(monster.nHp > 20)  //生命值大于20
{
if(rand()%5 != 1)          //进行利爪攻击概率4/5
monster.kind = 0;
else                       //进行闪电链攻击概率1/5
monster.kind = 1;
}
else     //生命值小于20
{
switch(rand()%5)
{
case 0:  //利爪攻击
monster.kind = 0;
break;
case 1:  //释放闪电链
monster.kind = 1;
break;
case 2:  //致命一击
monster.kind = 2;
break;
case 3:  //使用梅肯斯姆回复
monster.kind = 3;
break;
case 4:  //逃跑
monster.kind = 4;
break;
}
}
}
//第26~30个画面时显示玩家攻击图标
if(f>=26  && f<=30)
{
switch(monster.kind)
{
case 0:  //利爪攻击
SelectObject(bufdc,slash);
BitBlt(mdc,480,150,98,162,bufdc,98,0,SRCAND);
BitBlt(mdc,480,150,98,162,bufdc,0,0,SRCPAINT);
//第30个画面时计算玩家受伤害程度并加入显示消息
if(f == 30)
{
damage = rand()%10 + monster.lv*monster.w;
player.nHp -= (int)damage;
sprintf(str,"怪物利爪攻击...对玩家照成 %d 点伤害",damage);
MsgInsert(str);
CheckDie(player.nHp,true);
}
break;
case 1:  //释放闪电链
SelectObject(bufdc,magic);
BitBlt(mdc,480,190,100,100,bufdc,100,0,SRCAND);
BitBlt(mdc,480,190,100,100,bufdc,0,0,SRCPAINT);
//第30个画面时计算玩家受伤害程度并加入显示消息
if(f == 30)
{
damage = rand()%10 + 3*monster.w;
player.nHp -= (int)damage;
sprintf(str,"怪物释放闪电链...对玩家照成 %d 点伤害",damage);
MsgInsert(str);
CheckDie(player.nHp,true);
}
break;
case 2:  //致命一击
SelectObject(bufdc,slash);
BitBlt(mdc,480,150,98,162,bufdc,98,0,SRCAND);
BitBlt(mdc,480,150,98,162,bufdc,0,0,SRCPAINT);
//第30个画面时计算玩家受伤害程度并加入显示消息
if(f == 30)
{
damage = rand()%10 + monster.lv*monster.w*5;
player.nHp -= (int)damage;
sprintf(str,"怪物致命一击...对玩家照成 %d 点伤害.",damage);
MsgInsert(str);
CheckDie(player.nHp,true);
}
break;
case 3:  //使用梅肯斯姆补血
SelectObject(bufdc,recover);
BitBlt(mdc,60,160,150,150,bufdc,150,0,SRCAND);
BitBlt(mdc,60,160,150,150,bufdc,0,0,SRCPAINT);
//第30个画面时怪物回复生命值并加入显示消息
if(f == 30)
{
monster.nHp += 30;
sprintf(str,"怪物使用梅肯斯姆...恢复了30点生命值",damage);
MsgInsert(str);
}
break;
case 4:
//在第30个画面时判断怪物是否逃跑成功
if(f == 30)
{
if(1== rand()%3 ) //逃跑几率1/3
{
over = true;
monster.nHp = 0;
sprintf(str,"怪物逃跑中...逃跑成功");
MsgInsert(str);
}
else
{
sprintf(str,"怪物逃跑中...逃跑失败");
MsgInsert(str);
}
}
break;
}
}
if(f == 30)    //回合结束
{
attack = false;
f = 0;
}
}
BitBlt(hdc,0,0,640,510,mdc,0,0,SRCCOPY);
tPre = GetTickCount();
pNum++;
if(pNum == 8)
pNum = 0;
}
//****新增的对战消息函数********************************
void MsgInsert(char* str)
{
if(txtNum < 5)
{
sprintf(text[txtNum],str);
txtNum++;
}
else
{
for(int i=0;i<txtNum;i++)
sprintf(text[i],text[i+1]);
sprintf(text[4],str);
}
}
//****生命值判断函数*************************
void CheckDie(int hp,bool player)
{
char str[100];
if(hp <= 0)
{
over = true;
if(player)
{
sprintf(str,"胜败乃兵家常事,大侠请重新来过......");
MsgInsert(str);
}
else
{
sprintf(str,"少年,你赢了,有两下子啊~~~~~!!!!");
MsgInsert(str);
}
}
}
//****消息处理函数***********************************
//
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)
{
x = LOWORD(lParam);     //X坐标
y = HIWORD(lParam);     //Y坐标
if(x >= 500 && x <= 550 && y >= 350 && y <= 400)
attack = true;
}
break;
case WM_DESTROY:     //窗口结束消息
DeleteDC(mdc);
DeleteDC(bufdc);
DeleteObject(bg);
DeleteObject(sheep);
DeleteObject(girl);
DeleteObject(skill);
DeleteObject(skillult);
DeleteObject(slash);
DeleteObject(magic);
DeleteObject(recover);
DeleteObject(game);
ReleaseDC(hWnd,hdc);
PostQuitMessage(0);
break;
default:     //默认消息
return DefWindowProc(hWnd, message, wParam, lParam);}return 0;
}

每一回合开始的时候,我们点击画面上“无敌斩”的技能图标,就可以进行攻击,对怪物造成伤害,人品好的话,还可以触发强力被动技能“恩赐解脱”,对怪物造成4倍暴击伤害,这里我们设定的暴击概率为20%

浅墨在截图的时候,人品挺好的,恩赐解脱的暴击概率为20%,但是浅墨的4次攻击里,有3次都打出了“恩赐解脱”的暴击效果,直接果断地把这只小绵羊带走了,呵呵。

下面就是游戏运行的截图:

游戏开始

第一刀就出暴击了,48点伤害

运气不错,又一刀暴击,68点伤害

最后一刀又出了暴击,小绵羊被“秒杀”,游戏结束

我们还可以调节怪物等级,怪物攻击加权值,怪物血量上限以及玩家角色等级,玩家角色攻击加权值,玩家角色血量上限来让游戏更具挑战性。

当然,我们也可以增加更多的代码,来使怪物的思考与行动方式更具真实性和多样性,来使玩家的技能更加丰富。

这个回合制游戏demo可以说是目前市场上回合制游戏的本体,《仙剑奇侠传》(三代以前的,三代及以后的仙剑都是进度条模式了),《梦幻西游》《问道》等经典的回合制游戏,无非就是在这种风格的demo基础上,写更多的代码,丰富内容而已,或为游戏引擎的核心代码。

最后浅墨再提一点,以结束这篇笔记,其实就是为了给大家提供一些实现思路:

可以在这个demo的基础上,增加剧情,世界观,游戏地图,等级系统,经验值系统,宠物系统,道具系统,符文系统,五行相克系

统,天气系统等,让这个回合制游戏更加有趣更加吸引人。

而这些系统,我在以后的笔记里面会尽量全部涵盖进行讲解的,希望大家继续关注我的博客。

本节笔记到这里就结束了。

本节笔记的源代码请点击这里下载:  【Visual C++】Note_Code_16

感谢一直支持【Visual C++】游戏开发笔记系列专栏的朋友们,也请大家继续关注我的专栏,我一有时间就会把自己的学习心得,觉得比较好的知识点写出来和大家一起分享。

精通游戏开发的路还很长很长,非常希望能和大家一起交流,共同学习,共同进步。

大家看过后觉得值得一看的话,可以顶一下这篇文章,你们的支持是我继续写下去的动力~

如果文章中有什么疏漏的地方,也请大家指正。也希望大家可以多留言来和我探讨编程相关的问题。

最后,谢谢你们一直的支持~~~

——————————浅墨于2012年4月10日

作者:zhmxy555 发表于2012-4-11 3:10:45 原文链接
阅读:7242 评论:96 查看评论

转载于:https://www.cnblogs.com/mixer/archive/2012/04/11/2448450.html

[原]【Visual C++】游戏开发笔记十六 讲解一个完整的回合制游戏demo相关推荐

  1. 【Visual C++】游戏开发笔记十六 讲解一个完整的回合制游戏demo

    本系列文章由zhmxy555编写,转载请注明出处. 文章链接  http://blog.csdn.net/zhmxy555/article/details/7447864 作者:毛星云    邮箱:  ...

  2. 【Visual C 】游戏开发笔记十六 讲解一个完整的回合制游戏demo

    分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.csdn.net/jiangjunshow 也欢迎大家转载本篇文章.分享知识,造福人民,实现我们中华民族伟大复兴! 本系列文 ...

  3. 【Visual C++】游戏开发笔记十六 讲解一个完整的回合制游戏demo

    本系列文章由zhmxy555编写,转载请注明出处. 文章链接  http://blog.csdn.net/zhmxy555/article/details/7447864 作者:毛星云    邮箱:  ...

  4. 游戏开发笔记十六 讲解一个完整的回合制游戏demo

    首先,我们来了解这种行为型AI的设计方法. 游戏程序中计算机角色的思考与行为,实际上是对各种不同事件进行分析思考,然后根据不同的情况作出相应的反应.但如何对发生的条件进行判断,并作出相应的反应呢? 对 ...

  5. [原]【Visual C++】游戏开发笔记十五 游戏人工智能(一) 运动型游戏AI

    本系列文章由zhmxy555编写,转载请注明出处.  http://blog.csdn.net/zhmxy555/article/details/7434317 作者:毛星云    邮箱: happy ...

  6. 【Visual C++】游戏开发笔记十五 游戏人工智能(一) 运动型游戏AI

    分享一下我老师大神的人工智能教程.零基础!通俗易懂!风趣幽默!还带黄段子!希望你也加入到我们人工智能的队伍中来!https://blog.csdn.net/jiangjunshow 本系列文章由zhm ...

  7. 【转】【Visual C++】游戏开发笔记十五 游戏人工智能(一) 运动型游戏AI

    原文连接:http://www.cnblogs.com/dyllove98/archive/2012/04/07/2461865.html#commentform 我们常常听闻AI(Artificia ...

  8. 【Visual C++】游戏开发笔记十五 游戏人工智能(一) 运动型游戏AI .

    本系列文章由zhmxy555编写,转载请注明出处.  http://blog.csdn.net/zhmxy555/article/details/7434317 作者:毛星云    邮箱: happy ...

  9. 游戏开发笔记十五 游戏人工智能(一) 运动型游戏AI

    我们常常听闻AI(Artificial Intelligence人工智能)这个名词,比如Dota里面的AI地图.写这篇文章的时候,最新版的Dota AI是6.72f,估计过几天6.73的AI也要出来了 ...

最新文章

  1. OpenSceneGraph 3.2 版本修改点
  2. 数据库系统中数据抽象的三级结构
  3. charles源码分析
  4. linux挑战:历史命令_博客挑战:分享您关于社区运作方式的知识
  5. linux 内存使用很大,在32位和64位Linux上,为什么同一进程的pmap的内存使用量会有很大差异?...
  6. 荣耀赵明 “Diss” 5G 手机;甲骨文创始人埃里森:Uber 一文不值;Chrome 77 发布 | 极客头条...
  7. 【原创】MySQL Proxy - 协议(部分摘录)
  8. 基于深度卷积神经网络的玉米病害识别
  9. mysql免费框架_MySQL(ORM框架)
  10. ASP.NET Web Pages 和 WebMatrix (Razor Syntax、Forms、Data、Grid、Chart、Files、Images、Video)的学习资源...
  11. DSP学习笔记(三)——TMS320F28335硬件结构
  12. 2021全国大学生电子设计竞赛论文(智能送药小车(F题))(电赛论文模板)
  13. java毕业论文范文3_java毕业论文范文3篇
  14. 服务器返回状态码说明,关于服务器返回的十四种常见HTTP状态码详解
  15. 查询oracle所有回收站,oracle 回收站
  16. 使用table标签制作常用的html表格
  17. c ref java_使用JNA将C数组返回给Java
  18. Oracle日期型函数详解
  19. 源码学习之Vector
  20. CET-4 week7 融会贯通

热门文章

  1. 计算机桌面托盘变竖了 怎样恢复,右键没有NVIDIA控制面板怎么恢复?ATI显卡右键控制面板如何还原?...
  2. 通灵学院|游戏设计研习8:游戏空间设计★(800字)
  3. 计算各位数字的平方和:
  4. python---打印函数print延时且不按顺序输出
  5. “拼多多”惊爆重大 Bug!程序员的眼泪,羊毛党的狂欢
  6. 微信小程序上传体验版并邀请其他人测试体验(小程序的发布上线)
  7. MySQL运维篇之分库分表
  8. 基于AGS JS开发自定义贴图图层
  9. python pyramid基础学习二
  10. 计算机系高考激励的句子,最新暖心激励高考生的励志句子40句