★「C++游戏」幻影之战 BattleOfPhantom:一款集合多种人机对战以及联机对战的战斗游戏

(原创)
目前正在不断更新!

★ 一款超级有趣的大乱斗游戏,包含多种游戏模式,支持双人联机。
离线情况下也可以与多个(或一群)机器玩家进行疯狂的对战
直接上图
标题画面

使用C++ with EGE图形库编写
有一定数量的BUG,请谅解。

双人离线模式下的一张截图
[ 双人离线的一张截图 ]

操作说明

A,W,S,D | 主玩家移动
1/2/3/4 | 主玩家选择武器或道具
J | 主玩家向面前方向攻击
Backspace退格 | 主玩家删除当前武器或道具(注意:装备是靠刷新更好的,不能删)
鼠标左键 | 向鼠标方向攻击(非常方便),将被识别成八个方向之一(双人离线为了平等不能使用)

↑←↓→ | 双人离线时玩家2的移动
小键盘1/2/3/4 | 双人离线时玩家2选择武器或道具
小键盘0 | 双人离线时玩家2向面前方向攻击(原先是5,但因为不太好操作于是改了)
小键盘减号 | 双人离线时玩家2删除当前武器或道具

F2 | 立即窗口截图,存入Screenshots文件夹中
Esc | 退出战斗

基本玩法

比如说人机离线对战模式(是可以使用鼠标攻击的),
开局就先随机获得两把武器,两个道具,没有装备。
你可以通过右侧的对方方位与距离锁定敌人的位置进行有效攻击。
机器玩家的算法还说得过去,有时真难弄死它。
人机对战的一张截图
[↑ 人机对战的一张截图 ]
普通模式下一般都是300滴血,只有比较容易死的模式会1000血甚至5000血。(自己探索)
有些武器带效果的,要注意防护与使用:
效果数据
有些剑是带剑气的;
有些弹药是会反弹/爆炸/分裂/追踪(分为3种等级)/穿墙的。
实体属性(局部)
武器千奇百怪,战斗场面琳琅满目:
混战模式的一张截图
[↑ 混战模式的一张截图 ——那个血量不是正常的血量,请忽视 ]
群殴模式是很难挺过去的,你可以尝试一下!!
群殴模式的一张截图
群殴模式会给你1000血加上长时间的矫捷效果与永久的穿人特权。就算这样也能死得很惨。
诀窍是不断逃跑,让他们自己误伤。逃跑的时候注意安全。

  • 离线团战一定要把对方所有人消灭,但自己死了就算失败了。
  • 作为队伍头领,一定要学会保护自己!
    团战的一张截图
  • 队伍颜色是随机的
  • 右侧将会有显示真实水平的击杀榜、队伍剩余人数、最近敌人等数据。

★ 新版本加了一个叫等级与经验的机制(如上图左上角),击杀、伤害敌人,拾取物资都会获取经验,经验达到一定水平后等级+1.等级的高低将决定所抽武器道具装甲的好坏!!(等级最高10级)

最后关于联机:

  • 在线模式下服务端开启后,客户端依次输入服务端IP地址和端口号即可
    (若无外网则必须同一局域网下)
    配置外网时映射的IP需要是服务端开启后显示的IP(也就是服务端电脑第一个能用的IP)
    服务端

  • 端口号一律填8888.
    使用外网时,在输入IP地址界面不得输入域名。
    客户端输入的端口号是映射后的端口号(一般是五位数而不是8888)
    需要使用IP地址。获取其IP地址可以通过ping命令获得:
    Win+R打开运行,输入cmd
    ping命令获取外网IP地址

  • 联机的时候经常会崩溃,应该是这个TCP连接太差劲的缘故,也么有办法,因此我尽量减少机器玩家的数量。凑合着玩吧。不要使用频率极高的武器,因为更容易致使崩溃。

这款游戏已经写了一年左右了,祝愿大家玩得愉快
源码真的很长(一万多行了!)真的想要的话(也不给 XD )
无源码的游戏链接: https://download.csdn.net/download/cjz2005/86287023

★★★

为了造福广大苍生,我决定放一点源码给大家看看!
这是机器玩家的AI算法,原创,还行,有兴趣的同志可以好好研究一下。

//Dir Modes
#define DIR_NONE 0x00
#define DIR_4 0x01
#define DIR_8 0x02

//AI Modes
#define AAM_STILL 0		//静止
#define AAM_WANDER 1	//多逛
#define AAM_CHASE 2		//多追
#define AAM_FLEE 3		//多逃

//Constants
#define AA_CHANGE_MODE_RATE 25			//模式更改机率
#define AA_CHANGE_MODE_MIN_T 1000*6	//模式更改最小周期
#define AA_CHANGE_WEAPON_RATE 32			//武器切换概率
#define AA_CHANGE_WEAPON_MIN_T 1000*8	//武器切换最小周期
#define AA_LEVEL_UP_T 1000*43		//等级提升周期
#define AA_DRINK_POTION_RATE 8		//喝药水概率
#define AA_DODGE_BASE_RATE 13	//基础闪避概率
#define AA_DODGE_RATE_MAX 60	//闪避概率最大值
#define AA_DODGE_UP_RATIO 0.5	//闪避提升率
#define AA_DODGE_T 1000*0.9		//闪避周期
#define AA_EXTRA_DODGE_RATE_T 1000*65	//闪避概率微调周期
#define AA_CHANGE_TARGET_MIN_T 11000	//目标切换最小周期 
#define AA_CHANGE_TARGET_RATE 8		//目标切换概率 
#define AA_REVENGE_RATE 40		//复仇概率

class AIControl {	//AI控制玩家算法
public:
	bool enabled;	//是否启用 
	
	int my_index;		//附着玩家下标 
	int target_index;	//目标玩家下标(可变) 
	int team_index;		//队伍下标
	
	clock_t lastModeChanged;	//上一次切换模式 
	clock_t lastWeaponChanged;	//上一次切换武器 
	clock_t lastChangeTarget;	//上一次切换攻击目标 
	clock_t lastUp;				
	clock_t lastDodge;			//上一次闪避 
	clock_t lastExtraRateChanged;	//上一次改变额外躲闪率 
	int extraDodgeRate;		//额外躲闪率 
	int mode;		//AI模式 
	int xp;		//经验值
	BYTE extraMode;		//作弊额外模式 
	float adjust;
	const vector<int> mode_prob = { 0, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3 };	//带比重
	const vector<int> curw_prob = { 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 3 };	//带比重

	AIControl()
	{
		target_index = 0;	//默认主角为目标
		team_index = 0;
		adjust = 0;
		enabled = false;
		Init();
	}
	void Init()	//initialize
	{
		my_index = 1;	//<!>
		target_index = 0;	//默认主角为目标
		extraDodgeRate = 0;
		extraMode = AAE_NONE;
		mode = AAM_CHASE;
		lastModeChanged = clock() + 5000;
		lastWeaponChanged = clock();
		lastExtraRateChanged = clock();
		lastChangeTarget = clock();
		lastUp = clock();
		lastDodge = clock();
		xp = 0;
		adjust = (GetPlayerCount() * 5 + 10101 + RandomRange(0, 100, true, false)) % 100 / 100.0;
	}
	void Close()	//关闭 
	{
		enabled = false;
		mode = AAM_STILL;
		xp = 0;
		target_index = 0;
	}
	void Update()	//更新
	{
		if (!enabled || !IsPlayerAlive(my_index))	//未启用状态或死亡状态直接退出 
			return;

		CheckLevelUp();
		int r;
		//离线模式下,玩家2成为AI玩家
		//在线模式下,自己成为AI玩家(自动攻击)
		r = RandomRange(0, 100, true, false);	//percent
		if (r > 100 - AA_CHANGE_MODE_RATE - adjust*6 && (clock() - lastModeChanged > AA_CHANGE_MODE_MIN_T))
		{
			mode = mode_prob.at(RandomRange(0, mode_prob.size() - 1, true, true));
			lastModeChanged = clock();
		}
		if (clock() - lastExtraRateChanged > AA_EXTRA_DODGE_RATE_T)
		{
			extraDodgeRate = Varience(0, 5+adjust*6);
			lastExtraRateChanged = clock();
		}
		Move();		//根据模式进行移动
		if (clock() - lastDodge > AA_DODGE_T + adjust * 3)
		{
			TryToDodge();	//checking inside
		}
		if (g_bIdt != IDT_OFFLINE)
		{
			if(GetDirMode(GetPlayerCurWeapon(my_index)) == DIR_8)
				GetPlayerFace(my_index) = FaceDir8(target_index);
			else
				GetPlayerFace(my_index) = FaceDir4(target_index);
		}
		
#ifndef AI_CONCENTRATE
		if(g_mode != 0 && g_mode != 1 && g_mode != 2 	//就两个玩家时无需切换 
			&& g_mode != 3	//离线群殴始终只有一个目标
		&& (!IsPlayerAlive(target_index)	//目标死了就赶紧换目标 没有CD和概率要求
			|| (
		RandomRange(0,100,true,false) < AA_CHANGE_TARGET_RATE + adjust * 9	//还有概率 
		&& clock() - lastChangeTarget >= AA_CHANGE_TARGET_MIN_T)))
		{	//切换目标 
			int new_target_index = this->target_index;
			int min_dist = 9999;
			for(int i = 0; i < GetPlayerCount(); ++i)
			{
				if (!IsPlayerAlive(i) || i == my_index)
					continue;
				if ((g_mode == 5 || g_mode == 9)
					&& GetPlayerTeam(i) == team_index)
				{	//团战时 放过队友
					continue;
				}
				if ((g_mode == 6 || g_mode == 7) && i != 0 && i != 1)
					continue;	//在线群殴只能以人为目标
				auto _dist = Distance(GetX(),GetY(),GetPlayerX(i),GetPlayerY(i));
				if(_dist < min_dist)
				{
					new_target_index = i;
					min_dist = _dist;
				}
			}
			this->target_index = new_target_index;
			/*if(mode != AAM_CHASE && RandomRange(0,100,true,false) < AA_CHANGE_MODE_RATE + adjust * 8)
			{	//追赶加强
				this->mode = AAM_CHASE;
			}*/
		}
#endif
		if (RandomRange(0, 100, true, false) < 20 + adjust * 10)
			this->mode = AAM_CHASE;
		Attack();	//根据模式进行攻击
	}
	void CheckLevelUp()
	{
		if (clock() - lastUp > AA_LEVEL_UP_T)
		{
			int upv = 1;	//升级默认1级
			if (GetPlayerHp(my_index) > 1 && GetPlayerHp(target_index) > GetPlayerHp(my_index) * 1.8)
				upv = 2;	//当血量差得太远的时候,升级加速
			xp += upv; 
			lastUp = clock();
		}
	}
	void OnHurt(int hurt_by)	//受伤时调用
	{
		if(!enabled)
		    return;
		lastUp += 1000 * RandomRange(0,3,true,true);	//经验有增长的趋势
		if(mode == AAM_STILL || mode == AAM_WANDER)		//迅速进入正常状态
			lastModeChanged += 1000 * 4 + adjust * 100;
		if (PlayerHasAffect(my_index,3) || PlayerHasAffect(my_index,7) || PlayerHasAffect(my_index,11) || PlayerHasAffect(my_index,12))
		{
			extraDodgeRate += RandomRange(5, 9 + adjust * 2, true, false);	//躲闪率微调
		}
		else {
			extraDodgeRate += RandomRange(4, 7 + adjust * 2, true, false);	//躲闪率微调
		}

		if (hurt_by != my_index && hurt_by != target_index	//非我非你
			&& (g_mode == 5 || g_mode == 9) || (GetPlayerTeam(hurt_by) != team_index)	//异队
			&& g_mode != 3 //<!>离线群殴没有复仇;在线群殴还是有复仇的
			)
		{
			if (RandomRange(0, 100, true, false) < AA_REVENGE_RATE)
			{	//复仇
				target_index = hurt_by;
			}
		}
	}
	DIR FaceDir8(int i) const
	{
		POINT et{GetPlayerX(i),GetPlayerY(i)};
		if (IsOuttaField(POINT2(et.x, et.y)))
			return 0;
		int x = GetX();
		int y = GetY();
		int ex = GetPlayerX(target_index); 
		int ey = GetPlayerY(target_index); 
		if (x < ex)
		{
			if (y > ey)	return RIGHTUP;
			else if (y < ey)	return RIGHTDOWN;
			else	return RIGHT;
		}
		else if (x > ex)
		{
			if (y > ey)	return LEFTUP;
			else if (y < ey)	return LEFTDOWN;
			else	return LEFT;
		}
		else {
			if (y > ey)	return UP;
			else	return DOWN;
		}
	}
	DIR FaceDir4(int i) const
	{
		POINT et{GetPlayerX(i),GetPlayerY(i)};
		if (IsOuttaField(POINT2(et.x, et.y)))
			return 0;
		int x = GetX();
		int y = GetY();
		int ex = GetPlayerX(target_index); 
		int ey = GetPlayerY(target_index); 
		if (ex > x)
		{
			if (ey > y)
				return (abs(ex - x) > abs(ey - y) ? (RandomRange(1, 10) > 7 ? RIGHT : DOWN) : (RandomRange(1, 10) > 7 ? DOWN : RIGHT));
			else if (ey < y)
				return (abs(ex - x) > abs(ey - y) ? (RandomRange(1, 10) > 7 ? RIGHT : UP) : (RandomRange(1, 10) > 7 ? UP : RIGHT));
			else
				return RIGHT;
		}
		else if (ex < x)
		{
			if (ey > y)
				return (abs(ex - x) > abs(ey - y) ? (RandomRange(1, 10) > 7 ? LEFT : DOWN) : (RandomRange(1, 10) > 7 ? DOWN : LEFT));
			else if (ey < y)
				return (abs(ex - x) > abs(ey - y) ? (RandomRange(1, 10) > 7 ? LEFT : UP) : (RandomRange(1, 10) > 7 ? UP : LEFT));
			else
				return LEFT;
		}
		else {
			if (ey > y)
				return DOWN;
			else
				return UP;
		}
	}
	UINT GetI() const {			//获取下标
		/*if (enabled == false)
			return 2;	//无
		else if (g_bIdt == IDT_OFFLINE)
			return 1;
		else
			return g_p_i;*/
		return my_index;
	}
	UINT GetOppoI() const {
		return target_index;	
	}
	int GetX() const
	{
		return GetPlayerX(GetI());
	}
	int GetY() const
	{
		return GetPlayerY(GetI());
	}
	void _Tag(string text) const
	{
		setcolor(WHITE);
		setbkmode(OPAQUE);
		setfont(20, 0, "微软雅黑");
		xyprintf(20, 500, "TAG:%s", text.c_str());
	}
	void Move()
	{
		EXCEPTION_L
		//debug _Tag("Move");

		/*if (mode == AAM_STILL)
		{
			return;
		}
		else */
		if (mode == AAM_WANDER)
		{
			if (!PlayerTimeToMove(my_index))
				return;
			DIR dir;
			int x, y;
		_retry:
			dir = 2 * RandomRange(1, 4, true, true) - 1;
			x = GetX();
			y = GetY();
			if (PlayerHasAffect(GetI(), 12))
				dir = OppoDir(dir);
			DirOffsetPos(x, y, dir, "AIControl::Move");
			if (IsOuttaField(POINT2(x,y)) || 
				IsBarrier(bk(x, y, "AIControl::Move")))
			{
				goto _retry;
			}
			//Move
			GetPlayerX(my_index) = x;
			GetPlayerY(my_index) = y;
			bool sendMsg = (g_bIdt != IDT_OFFLINE);
			if (sendMsg)
				SendTCP(UM_SETPOS, x, y, GetI());
//			p[GetI()].lastMove = clock();
			LastMove(my_index);
		}
		else if (mode == AAM_CHASE || mode == AAM_FLEE 
			|| mode == AAM_STILL)
		{
			if (!PlayerTimeToMove(my_index))
				return;
			int x = GetX();
			int y = GetY();
			int ex = GetPlayerX(target_index);
			int ey = GetPlayerY(target_index);
			DIR xd, yd;

			if (ex > x)
				xd = RIGHT;
			else if (ex < x)
				xd = LEFT;
			else
				xd = 0;
			if (ey > y)
				yd = DOWN;
			else if (ey < y)
				yd = UP;
			else
				yd = 0;

			int r = RandomRange(0, 1, true, true);
			DIR dir;	//final dir
			if (xd == RIGHT)
			{
				if (yd == 0)
					dir = RIGHT;
				else {
					dir = (r ? RIGHT : yd);
				}
			}
			else if (xd == LEFT)
			{
				if (yd == 0)
					dir = LEFT;
				else {
					dir = (r ? LEFT : yd);
				}
			}
			else {
				dir = yd;
			}
			if (mode == AAM_FLEE)	//相反逃离
				dir = OppoDir(dir);
			if (PlayerHasAffect(GetI(), 12))
				dir = OppoDir(dir);	//混沌效果 直接再反
			
			//Move(CHASE)
			DirOffsetPos(x, y, dir,"AIControl::Move");
			if (!IsOuttaField(POINT2(x, y)) &&
				!IsBarrier(bk(x,y,"AIControl::Move")) && 
				//!(x == ex && y == ey)	&&	//不能与对方重叠
				!HasPlayerTouch(my_index,dir)	//不能与别的玩家重叠
				)	
			{
				if (mode != AAM_STILL)
				{
					bool sendMsg = (g_bIdt != IDT_OFFLINE);
					GetPlayerX(my_index) = x;
					GetPlayerY(my_index) = y;
					if (sendMsg)
						SendTCP(UM_SETPOS, x, y, GetI());
				}
				GetPlayerFace(my_index) = dir;
//				p[GetI()].lastMove = clock();
				LastMove(my_index);
				//return;
			}else
				LastMove(my_index);
		}
		else {

		}

		EXCEPTION_R_TITLED("BOP AIControl::Move EXCEPTION")
	}
	DIR GetComingDir(const Entity& et) const
	{
		if (IsOuttaField(POINT2(et.x, et.y)))
			return 0;
		int x = GetX();
		int y = GetY();
		int ex = GetPlayerX(target_index);
		int ey = GetPlayerY(target_index);
		DIR eface = et.face;
		if (eface == RIGHT && y == ey && x > ex)
			return LEFT;
		else if (eface == LEFT && y == ey && x < ex)
			return RIGHT;
		else if (eface == DOWN && x == ex && y > ey)
			return UP;
		else if (eface == UP && x == ex && y < ey)
			return DOWN;
		else if (eface == LEFTDOWN && (x - ex < 0) && (x - ex) / float(y - ey) == -1.0f)
			return RIGHTUP;
		else if (eface == LEFTUP && (x - ex < 0) && (x - ex) / float(y - ey) == 1.0f)
			return RIGHTDOWN;
		else if (eface == RIGHTDOWN && (x - ex > 0) && (x - ex) / float(y - ey) == 1.0f)
			return LEFTUP;
		else if (eface == RIGHTUP && (x - ex > 0) && (x - ex) / float(y - ey) == -1.0f)
			return LEFTDOWN;
		else
			return 0;
	}
	void TryToDodge()
	{	//尝试躲闪 
		if (entities.empty())
			return;

		int x = GetX();
		int y = GetY();
		int dp;
		int r;
		dp = Varience(AA_DODGE_BASE_RATE,4)	//基础也在变动
			+ xp * AA_DODGE_UP_RATIO 
			+ adjust * 3
			+ extraDodgeRate;
		//各种效果对其的影响
		if (PlayerHasAffect(my_index, 6))
			dp -= 4;
		if (PlayerHasAffect(my_index, 7))
			dp -= 3;
		if (PlayerHasAffect(my_index, 9))
			dp -= 6;
		if (PlayerHasAffect(my_index, 11))
			dp -= 10;
		else if (PlayerHasAffect(my_index, 12))
			dp -= 9;
		if (PlayerHasAffect(my_index, 1))
			dp -= 2;
		if (PlayerHasAffect(my_index, 14))
			dp -= 8;	//隐身的时候得削弱一下,否则太难玩了

		ClampA(dp, AA_DODGE_BASE_RATE-5, AA_DODGE_RATE_MAX);	//限制

		if (PlayerHasAffect(my_index, 4))	//矫捷
			dp += 3 + adjust * 1;

		  //debug _Tag(ToString(dp));

		for (int i = 0; i < entities.size(); i++)
		{
			double dist = Distance(x, y, entities.at(i).x, entities.at(i).y);
			DIR aimdir=0;
			if (aimdir = GetComingDir(entities.at(i)))
			{
				int dextra_rate = 0;	//根据距离决定的 额外 补充/扣除 概率
				if (dist < 2.1f)
					dextra_rate = 4;
				else if (dist < 4.4f)
					dextra_rate = 0;
				else if (dist < 6.3f)
					dextra_rate = -4;
				else if (dist < 10.5f)
					dextra_rate = -8;
				else {
					dextra_rate = -16;
				}

				r = RandomRange(0, 100, true, false);
				if (r < dp + dextra_rate)
				{
					Dodge(aimdir);	//尽力闪避
				}
				//continue;
				break;
			}
		}//end of for
	}
	bool FaceBarrier(int _x, int _y, DIR face)
	{
		int nx = _x, ny = _y;
		DirOffsetPos(nx, ny, face, "FaceBarrier");
		if (IsBarrier(bk(nx, ny, string(__func__))) || IsOuttaField(POINT2(nx, ny)))
			return true;
		return false;
	}
	bool Dodge(DIR aimdir)
	{	//调用此函数时,必须尽力闪避
		if (aimdir == 0)
			return false;
		if (PlayerHasAffect(my_index, 2) || PlayerHasAffect(my_index, 10))	//不能动的效果一定要中止,否则会被视为作弊
			return false;
		const vector<DIR> _choices{1,3,5,7};	//四向
		vector<DIR> choices{};
		DIR oppdir = 0;	//最终选择
		for (int i = 0; i < _choices.size(); i++)
		{
			if (_choices.at(i) != aimdir && _choices.at(i) != OppoDir(aimdir))
			{
				choices.push_back(_choices.at(i));
			}
			else if (_choices.at(i) == OppoDir(aimdir))
			{
				oppdir = _choices.at(i);
			}
		}
		if (oppdir != 0)
		{
			choices.push_back(oppdir);	//最后选择
		}
		bool sendMsg = (g_bIdt != IDT_OFFLINE);
		for (int k = 0; k < choices.size(); k++)
		{
			if (!HasPlayerTouch(GetI(),choices.at(k))		//不碰玩家
			&&  !FaceBarrier(GetX(),GetY(),choices.at(k))	//不碰壁,不出图
				)
			{
				int x = GetX(), y = GetY();
				DirOffsetPos(x, y, choices.at(k), "Dodge");
				SetPlayerPos(GetI(), x, y);		//闪避
				if (sendMsg)
					SendTCP(UM_SETPOS, x, y, GetI());
				return true;					//成功
			}
		}
		return false;	//闪避失败
	}
#define AA_CANREACH_RANGE_MAX 30
	bool CanReach(int x, int y, DIR face, int ex, int ey) const
	{	//能否打得到
		if (face == 0)
			return false;
		int _x = x, _y = y;
		int i = 0;
		if (face == RIGHT || face == LEFT)
		{
			if (y != ey)
				return false;
			while (!IsOuttaField(POINT2(_x, _y)) && !IsBarrier(bk(_x, _y, "AIControl::CanReach")) && i < AA_CANREACH_RANGE_MAX)
			{
				if (_x == ex && _y == ey)
					return true;
				DirOffsetPos(_x, _y, face, "AIControl::CanReach");
				i++;
				//DebugLog(ToString(i),false);
			}
			return false;
		}else if (face == DOWN || face == UP)
		{
			if (x != ex)
				return false;
			while (!IsOuttaField(POINT2(_x, _y)) && !IsBarrier(bk(_x, _y, "AIControl::CanReach")) && i < AA_CANREACH_RANGE_MAX)
			{
				if (_x == ex && _y == ey)
					return true;
				DirOffsetPos(_x, _y, face, "AIControl::CanReach");
				i++;
				//DebugLog(ToString(i), false);
			}
			return false;
		}
		else {
			if (x == ex || y == ey)
				return false;
			while (!IsOuttaField(POINT2(_x, _y)) && !IsBarrier(bk(_x, _y, "AIControl::CanReach")) && i < AA_CANREACH_RANGE_MAX)
			{
				if (_x == ex && _y == ey)
					return true;
				DirOffsetPos(_x, _y, face, "AIControl::CanReach");
				i++;
				//DebugLog(ToString(i), false);
			}
			return false;
		}
	}
	double GetTargetDistance()	const
	{	//获取目标距离 
		return Distance(GetPlayerX(my_index),GetPlayerY(my_index),GetPlayerX(target_index),GetPlayerY(target_index));
	}
	void Attack()
	{
		EXCEPTION_L
		//_Tag("Attack");

		int r = RandomRange(0, 100, true, false);
		if (r > 100 - AA_CHANGE_WEAPON_RATE && (clock() - lastWeaponChanged) > AA_CHANGE_WEAPON_MIN_T)
		{
			do {
				GetPlayerCurWeaponIndex(my_index) = curw_prob.at(RandomRange(0, curw_prob.size() - 1, true, true));
			} while (GetPlayerCurWeaponIndex(my_index) == 0);	//不能选空的格子

			lastWeaponChanged = clock();
		}
//		double distance = GetOppoDistance();
		double distance = GetTargetDistance();
		UINT type = GetItemType(GetPlayerCurWeapon(my_index));
		int x = GetX();
		int y = GetY();
		int ex = GetPlayerX(target_index);
		int ey = GetPlayerY(target_index);

		DIR face = GetPlayerFace(my_index);
		UINT ptype;
		ITEM_ID id = GetPlayerCurWeapon(my_index);

		if(type == ITT_PROP)
			ptype = GetItemPropType(GetPlayerCurWeapon(my_index));
		if (type == ITT_BOW || type == ITT_GUN
			|| (type == ITT_PROP && ptype == ITPT_THROWABLE))	//远程武器
		{
			bool reach = CanReach(x, y, face, ex, ey);
			r = RandomRange(0, 100, true, false);

			int blind_prob = 10;
			if (mode == AAM_FLEE)
				blind_prob = 2;
			else if (type == ITT_PROP && ptype == ITPT_THROWABLE)
				blind_prob = 1;
			else
				blind_prob = 11;
			if(reach && r > (mode == AAM_CHASE ? 49 : 62) || r < blind_prob)
//				p[GetI()].TryToAttack(GetI(), (g_bIdt != IDT_OFFLINE));	//checking is inside
				PlayerTryToAttack(my_index, (g_bIdt != IDT_OFFLINE));	//checking is inside
		}
		else if (type == ITT_CLOSE_WEAPON)	//近战武器
		{	
			bool reach = distance < 3.3;
			r = RandomRange(0, 100, true, false);
			if(reach && r > (mode == AAM_CHASE ? 43 : 45) || r > (mode == AAM_FLEE ? 86 : 97))
				PlayerTryToAttack(my_index, (g_bIdt != IDT_OFFLINE));	//checking is inside
		}
		else if (type == ITT_PROP)	//道具
		{
			if (ptype == ITPT_PUT)	//放置类
			{
				if (id == 33)	//地雷
				{
					int prob = 5;
					if (distance < 6.0)
					{
						if (mode == AAM_FLEE)
						{	//逃亡中布地雷对方很容易中招
							prob = 40;
						}
						else if (mode == AAM_CHASE)
						{	//追的时候就不一定了
							prob = 12;
						}
						else if (mode == AAM_STILL)
						{	//判断对手是否朝自己方向来
							bool come = false;
							int delta_x, delta_y;
							DIR eface = GetPlayerFace(target_index);
							delta_x = ex - x;
							delta_y = ey - y;
							if (delta_x > 0 && eface == LEFT
								|| delta_x < 0 && eface == RIGHT
								|| delta_y > 0 && eface == UP
								|| delta_y < 0 && eface == DOWN)
								come = true;
							prob = (come?76:33);
							
						}
					}
					else {
						prob = 11;
					}
					r = RandomRange(0, 100, true, false);
					if (r < prob)
					{	//布地雷
						PlayerTryToAttack(my_index, (g_bIdt != IDT_OFFLINE));	//checking is inside
					}
				}
				else {
					//<!>other PUTs...
				}
			}
			else if (ptype == ITPT_POTION)	//药水类,好的药水
			{
				r = RandomRange(0, 100, true, false);
				float t = AA_DRINK_POTION_RATE;	//概率
				if (id >= 71 && id <= 73)
				{
					if (GetPlayerHp(my_index) < GetPlayerMaxHp(my_index) * 0.10)
						t *= 5.0;
					else if (GetPlayerHp(my_index) < GetPlayerMaxHp(my_index) * 0.25)
						t *= 3.0;
					else if (GetPlayerHp(my_index) < GetPlayerMaxHp(my_index) * 0.45)
						t *= 1.6;
				}
				if (r < t)
				{	//喝药水
//					p[GetI()].TryToAttack(GetI(), (g_bIdt != IDT_OFFLINE));
					PlayerTryToAttack(my_index, (g_bIdt != IDT_OFFLINE));
				}
			}
			else {
				//other ITPTs...
			}
		}
		else {
			return;
		}

		EXCEPTION_R_TITLED("BOP AIControl::Attack EXCEPTION")
	}
};
//AIControl g_aic;
AIControl& GetPlayerAI(int index);

大致就包括自动移动、攻击、躲闪、喝药、埋地雷等,特别是那个躲闪很有意思,经验值越高躲闪越容易成功。
以后打算搞个游击模式算法。。等更新吧

下载: https://download.csdn.net/download/cjz2005/86287023

喜欢的朋友别忘了点赞关注!!

  • 8
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
好的,下面是一个基本的五子棋游戏的 C++ 代码,包含人人对人机。请注意,这只是一个基本的示例代码,您可以根据需要进行修改和优化。 ``` #include <iostream> #include <vector> #include <ctime> #include <cstdlib> using namespace std; const int BOARD_SIZE = 15; // 棋盘大小 const int EMPTY = 0; // 空棋子 const int BLACK = 1; // 黑棋 const int WHITE = -1; // 白棋 // 棋盘类 class Board { public: Board() { for(int i = 0; i < BOARD_SIZE; i++) { vector<int> row(BOARD_SIZE, EMPTY); board.push_back(row); } } // 判断当前位置是否越界 bool is_valid(int x, int y) const { return x >= 0 && x < BOARD_SIZE && y >= 0 && y < BOARD_SIZE; } // 判断当前位置是否为空 bool is_empty(int x, int y) const { return board[x][y] == EMPTY; } // 在当前位置落子 void move(int x, int y, int player) { board[x][y] = player; } // 检查是否有五子连珠 bool check_win(int x, int y) const { int player = board[x][y]; int dx[4] = {-1, 0, 1, 1}; // 横向、纵向、正斜线、反斜线四个方向 int dy[4] = {0, 1, 1, -1}; for(int i = 0; i < 4; i++) { int count = 1; int nx = x + dx[i]; int ny = y + dy[i]; while(is_valid(nx, ny) && board[nx][ny] == player) { count++; nx += dx[i]; ny += dy[i]; } nx = x - dx[i]; ny = y - dy[i]; while(is_valid(nx, ny) && board[nx][ny] == player) { count++; nx -= dx[i]; ny -= dy[i]; } if(count >= 5) { return true; } } return false; } // 打印棋盘 void print() const { cout << " "; for(int i = 0; i < BOARD_SIZE; i++) { cout << i << " "; } cout << endl; for(int i = 0; i < BOARD_SIZE; i++) { cout << i << " "; for(int j = 0; j < BOARD_SIZE; j++) { if(board[i][j] == EMPTY) { cout << "+ "; } else if(board[i][j] == BLACK) { cout << "X "; } else { cout << "O "; } } cout << endl; } } private: vector<vector<int>> board; // 存储棋盘上每个位置的棋子 }; // 人人对 void play_with_human() { Board board; int player = BLACK; while(true) { cout << "Player " << player << "'s turn:" << endl; board.print(); int x, y; while(true) { cout << "Enter the row and column of your move: "; cin >> x >> y; if(board.is_valid(x, y) && board.is_empty(x, y)) { break; } else { cout << "Invalid move, please try again." << endl; } } board.move(x, y, player); if(board.check_win(x, y)) { cout << "Player " << player << " wins!" << endl; board.print(); break; } player = -player; } } // 人机 void play_with_AI() { Board board; int player = BLACK; while(true) { cout << "Player " << player << "'s turn:" << endl; board.print(); if(player == BLACK) { int x, y; while(true) { cout << "Enter the row and column of your move: "; cin >> x >> y; if(board.is_valid(x, y) && board.is_empty(x, y)) { break; } else { cout << "Invalid move, please try again." << endl; } } board.move(x, y, player); } else { int x, y; srand(time(NULL)); while(true) { x = rand() % BOARD_SIZE; y = rand() % BOARD_SIZE; if(board.is_empty(x, y)) { break; } } board.move(x, y, player); cout << "The AI plays at (" << x << ", " << y << ")." << endl; } if(board.check_win(x, y)) { if(player == BLACK) { cout << "You win!" << endl; } else { cout << "The AI wins!" << endl; } board.print(); break; } player = -player; } } int main() { cout << "Welcome to the game of Gobang!" << endl; cout << "Please choose a mode:" << endl; cout << "1. Play with human" << endl; cout << "2. Play with AI" << endl; int mode; cin >> mode; if(mode == 1) { play_with_human(); } else if(mode == 2) { play_with_AI(); } else { cout << "Invalid mode, please try again." << endl; } return 0; } ``` 希望这个例子能对您有所帮助。如果您有任何问题,请随时提出。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值