⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ttank.cpp

📁 一个另类的坦克大战源程序
💻 CPP
字号:
// TTank.cpp: implementation of the TTank class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"

#include "TankWar.h"
#include "TTank.h"
#include "TWorld.h"
#include "TExplode.h"
#include "TBonus.h"
#include "TBullet.h"

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////
// TEnemyTank
///////////////////////////////////////////////////////////////////
EPG TEnemyTank::m_epg[3];

////////////////////////////////////////////////
//敌军坦克移动
void TEnemyTank::Move()
{
	if(!IsMyTime())
		return ;

	//防护小于0,还不死吗
	if(m_nShield < 0)
	{
		Dead();

		//玩家增加经验值
		g_world.Player(0)->m_nExper += 10 + m_nType * 10;

		//加点爆炸效果
		g_world.ExplodeLink().Add(NEW TExplode(m_nX,m_nY,EXPLODE_TANK));
	}

	/////////////////////////////////////////////////////
	//疯子要行动了,怎么动呢?用随机数来决定吧

	//玩家没进入范围,什么也不做
	if(ABS(m_nX-g_world.Player(0)->GetX())>500 ||
		ABS(m_nY-g_world.Player(0)->GetY())>500)
		return ;

	//产生0到100之间的随机数状态
	int status=Rand(0,100);

	//保存现在的位置坐标
	int x=m_nX,y=m_nY;

	//根据产生的状态行动
	if(status<2){
		//状态小于2,改变一下方向(概率是... 计算一下好像是: 2/100即0.02)
		m_dir =(DIRECTION) Rand(0,4);
	}else if(status <3)
	{
		//状态小于3,开火(概率是... 计算一下好像是: (3-2)/100即0.01)
		switch(m_nType)
		{
		case FIRE_TANK:
			//火弹:射程100,威力20
			g_world.BulletLink().Add(NEW TBullet(m_nX,m_nY,m_dir,FIRE,20,100));
			break;
		case DOUBLE_MISSILE_TANK:
			//火弹:射程250,威力15
			g_world.BulletLink().Add(NEW TBullet(m_nX,m_nY,m_dir,DMISSILE,15,250));
			break;
		case SINGLE_MISSILE_TANK:
			//火弹:射程250,威力10
			g_world.BulletLink().Add(NEW TBullet(m_nX,m_nY,m_dir,SMISSILE,10,250));
			break;
		}
	}else
	{
		//其它的状态值就表示运行吧(概率是... 计算一下好像是: 100-3/100即0.97)
		//生命在于运动嘛:)
		m_nX+=g_nDirXY[m_dir][0];
		m_nY+=g_nDirXY[m_dir][1];
	}


	/////////////////////////////////////////////////////
	//计算一下上面的移动是否有效

	//先假设移动有效
	BOOL canMove=TRUE;

	//取得自己的边框
	RECT rc;
	GetRect(rc);

	////////////////////////////////////////////////////
	//根据方向来计算是否与障碍地图上的障碍物碰撞
	if(m_dir==DIR_UP){
		//方向向上,只检查左上角及右上角坐标是否碰到障碍
		if(g_world.ObstacleMap(rc.left/OBSTACLE_WIDTH,rc.top/OBSTACLE_HEIGHT))
			canMove = FALSE;
		else if(g_world.ObstacleMap(rc.right/OBSTACLE_WIDTH,rc.top/OBSTACLE_HEIGHT))
			canMove = FALSE;
	}else if(m_dir==DIR_DOWN){
		//方向向下,只检查左下角及右下角坐标是否碰到障碍
		if(g_world.ObstacleMap(rc.left/OBSTACLE_WIDTH,rc.bottom/OBSTACLE_HEIGHT))
			canMove = FALSE;
		else if(g_world.ObstacleMap(rc.right/OBSTACLE_WIDTH,rc.bottom/OBSTACLE_HEIGHT))
			canMove = FALSE;
	}else if(m_dir==DIR_RIGHT){
		//方向向右,只检查右下角及右上角坐标是否碰到障碍
		if(g_world.ObstacleMap(rc.right/OBSTACLE_WIDTH,rc.top/OBSTACLE_HEIGHT))
			canMove = FALSE;
		else if(g_world.ObstacleMap(rc.right/OBSTACLE_WIDTH,rc.bottom/OBSTACLE_HEIGHT))
			canMove = FALSE;
	}else if(m_dir==DIR_LEFT){
		//方向向左,只检查左上角及左上角坐标是否碰到障碍
		if(g_world.ObstacleMap(rc.left/OBSTACLE_WIDTH,rc.top/OBSTACLE_HEIGHT))
			canMove = FALSE;
		else if(g_world.ObstacleMap(rc.left/OBSTACLE_WIDTH,rc.bottom/OBSTACLE_HEIGHT))
			canMove = FALSE;
	}

	//总不能移到世界范围以外吧
	if(m_nY>g_world.GetHeight()-OBSTACLE_HEIGHT ||
		m_nX>g_world.GetWidth()-OBSTACLE_WIDTH ||
		m_nX<0 || m_nY<0)
		canMove = FALSE;

	//有没有碰到其它的NC坦克?不过要记住排除与自己相撞的情况
	//疯子也不会疯到这种程度吧
	if(g_world.EnemyTankLink().HitTestAll(this))
		//停下来,打个招呼
		canMove = FALSE;

	//撞到了其它障碍物(木箱、邪恶之源)了吗?
	if(g_world.ObstacleLink().HitTestAll(this))
		canMove = FALSE;

	//碰到玩家坦克了吗?
	if(g_world.Player(0)->HitTest(this))
		//当然不能动了
		canMove = FALSE;

	//移动无效,恢复原值
	if(canMove==FALSE)
		m_nX = x,m_nY=y;

	//////////////////////////
	//计算当前动画帧
	m_nCurrentFrame=m_dir;

}

//////////////////////////////////////////////////
//画坦克
void TEnemyTank::Draw()
{
	POINT p;
	p.x = m_nX;
	p.y = m_nY;
	g_world.LPToDP(p);
	WGE_Surface.Blt(m_epg[m_nType],
		m_nCurrentFrame,
		p.x,p.y );
}

/////////////////////////////////////////
//取边框
void TEnemyTank::GetRect(RECT& rc)
{
	rc.left = m_nX - m_epg[m_nType].GetFrame(m_nCurrentFrame)->m_nKeyX;
	rc.top = m_nY - m_epg[m_nType].GetFrame(m_nCurrentFrame)->m_nKeyY;
	rc.bottom = rc.top + m_epg[m_nType].GetFrame(m_nCurrentFrame)->m_dwHeight ;
	rc.right = rc.left + m_epg[m_nType].GetFrame(m_nCurrentFrame)->m_dwWidth ;
}

///////////////////////////////////////////////
//
TEnemyTank::TEnemyTank(int x, int y, int nType)
:TSprite(x,y,100,0,CLASS_TENEMYTANK),m_nType(nType)
{
	switch(nType)
	{
	case FIRE_TANK:
		//防护力100,速度1/(50/1000)
		m_nShield = 100;
		SetDelayTimer(50);
		break;
	case DOUBLE_MISSILE_TANK:
		//防护力150,速度1/(70/1000)
		m_nShield = 150;
		SetDelayTimer(70);
		break;
	case SINGLE_MISSILE_TANK:
		//防护力100,速度1/(30/1000)
		m_nShield = 200;
		SetDelayTimer(30);
		break;
	}
}

/////////////////////////////////////////////////////////
//碰撞是否有效
BOOL TEnemyTank::HitBy(TObject * pObj)
{
	////////////////////////////////////////////
	//与参数对象碰撞
	if(HitTest(pObj))
	{
		//////////////////////////////////////////
		//参数对象是一个子弹
		if(pObj->ClassType()==CLASS_TBULLET)
		{
			//转变为子弹对象
			TBullet * pBullet = (TBullet*)pObj;
			if(pBullet->m_nType == LIGHT)
			{
				//是光弹,防护减去光弹的力量
				m_nShield -= pBullet->m_nShield ;
				return TRUE;
			}
		}
	}
	return FALSE;
}

///////////////////////////////////////////////////////////////////////
// TPlayerTank
///////////////////////////////////////////////////////////////////

EPG TPlayerTank::m_epg[3];

TPlayerTank::TPlayerTank(int x, int y, int nType)
:TSprite(x,y,100,0,CLASS_TPLAYERTANK),m_nType(nType),
m_nExper(0),m_nMoney(0),m_nMaxShield(100)
{
	SetDelayTimer(40);
}

/////////////////////////////////////////////////
//碰撞是否有效
BOOL TPlayerTank::HitBy(TObject * pObj)
{
	///////////////////////////////////////////
	//是否与参数对象碰撞
	if(HitTest(pObj))
	{
		if(pObj->ClassType()==CLASS_TBULLET)
		{
			//参数对象炮弹
			TBullet * pBullet = (TBullet*)pObj;
			if(pBullet->m_nType == FIRE||pBullet->m_nType == DMISSILE||pBullet->m_nType == SMISSILE)
			{
				//被火弹,双导弹,单导弹(都是敌方的炮弹)击中,减防护力
				m_nShield -= pBullet->m_nShield ;
				return TRUE;
			}
		}else if(pObj->ClassType()==CLASS_TBONUS)
		{
			//参数对象是奖励
			TBonus * pBonus = (TBonus*)pObj;
			switch(pBonus->m_nBonusType)
			{
			case BONUS_RECOVER:	//恢复物品
				m_nShield += 20;	//恢复20点
				m_nShield = MIN(m_nShield+20,m_nMaxShield);
				break;
			case BONUS_EXPER:	//经验物品
				//m_nExper += 10;	//经验值加10
				m_nType = MIN((m_nExper/1000),2);			//第1000点升一级
				m_nMaxShield = 100 + m_nExper/100;			//调整最大防护
				m_dwDelayTimer -= m_dwDelayTimer*10/100;	//速度提高10%
				break;
			case BONUS_MONEY:	
				m_nMoney += 100;	//得到100元
			}
			return TRUE;
		}
	}
	return FALSE;
}


/////////////////////////////////////////////////////
//玩家坦克移动
void TPlayerTank::Move()
{
	if(!IsMyTime())
		return ;

	if(m_nShield<0)
	{
		Dead();
		g_world.ExplodeLink().Add(NEW TExplode(m_nX,m_nY,EXPLODE_PLAYER));
		return;
	}

	///////////////////////////////////////////////////
	//响应键盘事件,移动坦克

	//保存原坐标
	int x=m_nX,y=m_nY;

	//处理按键
	if(WGE_Input.Key()[DIK_UP]){
		if(m_nY>0)	m_nY -- ;
		m_dir = DIR_UP;
	}else
	if(WGE_Input.Key()[DIK_DOWN]){
		if(m_nY<g_world.GetHeight()-OBSTACLE_HEIGHT)
			m_nY += 1;
		m_dir = DIR_DOWN;
	}else 
	if(WGE_Input.Key()[DIK_LEFT]){
		if(m_nX>0) m_nX -= 1;
		m_dir = DIR_LEFT;
	}else
	if(WGE_Input.Key()[DIK_RIGHT]){
		if(m_nX<g_world.GetWidth()-OBSTACLE_WIDTH)
			m_nX += 1;
		m_dir = DIR_RIGHT;
	}
	
	/////////////////////////////////////////////////////////
	//计算上面的移动是否有效

	BOOL canMove=TRUE;	//假设有效先

	RECT rc;
	GetRect(rc);

	//是否碰撞地形障碍?方法和敌人坦克一样
	if(m_dir==DIR_UP){
		if(g_world.ObstacleMap(rc.left/OBSTACLE_WIDTH,rc.top/OBSTACLE_HEIGHT))
			canMove = FALSE;
		else if(g_world.ObstacleMap(rc.right/OBSTACLE_WIDTH,rc.top/OBSTACLE_HEIGHT))
			canMove = FALSE;
	}else
	if(m_dir==DIR_DOWN){
		if(g_world.ObstacleMap(rc.left/OBSTACLE_WIDTH,rc.bottom/OBSTACLE_HEIGHT))
			canMove = FALSE;
		else if(g_world.ObstacleMap(rc.right/OBSTACLE_WIDTH,rc.bottom/OBSTACLE_HEIGHT))
			canMove = FALSE;
	}else
	if(m_dir==DIR_RIGHT){
		if(g_world.ObstacleMap(rc.right/OBSTACLE_WIDTH,rc.top/OBSTACLE_HEIGHT))
			canMove = FALSE;
		else if(g_world.ObstacleMap(rc.right/OBSTACLE_WIDTH,rc.bottom/OBSTACLE_HEIGHT))
			canMove = FALSE;
	}else
	if(m_dir==DIR_LEFT){
		if(g_world.ObstacleMap(rc.left/OBSTACLE_WIDTH,rc.top/OBSTACLE_HEIGHT))
			canMove = FALSE;
		else if(g_world.ObstacleMap(rc.left/OBSTACLE_WIDTH,rc.bottom/OBSTACLE_HEIGHT))
			canMove = FALSE;
	}

	//碰到了敌人的坦克没有?
	if(g_world.EnemyTankLink().HitTestAll(this))
		canMove = FALSE;

	//是否碰到了障碍物(木箱或邪恶源)
	if(g_world.ObstacleLink().HitTestAll(this))
		canMove = FALSE;

	//移动无效,恢复原坐标
	if(canMove==FALSE)
		m_nX = x,m_nY=y;

	//计算当前动画帧	
	m_nCurrentFrame=m_dir;

	//按左CTRL键开火,不过每100ms才能开一次,加弹总要花点时间吧:)
	static DWORD dwFireTick=GetTickCount();
	if(GetTickCount()-dwFireTick>100)
	{
		if(WGE_Input.Key()[DIK_LCONTROL]){
			g_world.BulletLink().Add(NEW TBullet(m_nX,m_nY,m_dir,LIGHT,10+m_nMoney/300,100+m_nType*25));
		}
		dwFireTick=GetTickCount();
	}
	
	//让玩家坦克处于可视区的中央
	g_world.GetViewportRect(rc);
	int height= rc.bottom - rc.top - OBSTACLE_HEIGHT;
	int width= rc.right - rc.left - OBSTACLE_WIDTH;
	g_world.SetViewport(m_nX-width/2,m_nY-height/2);
}

//////////////////////////////////////////////////////
//画玩家坦克
void TPlayerTank::Draw()
{
	POINT p;
	p.x = m_nX;
	p.y = m_nY;
	g_world.LPToDP(p);
	WGE_Surface.Blt(m_epg[m_nType],
		m_nCurrentFrame,
		p.x,p.y );
}

///////////////////////////////////////////////
//返回坦克的边框
void TPlayerTank::GetRect(RECT& rc)
{
	rc.left = m_nX - m_epg[m_nType].GetFrame(m_nCurrentFrame)->m_nKeyX;
	rc.top = m_nY - m_epg[m_nType].GetFrame(m_nCurrentFrame)->m_nKeyY;
	rc.bottom = rc.top + m_epg[m_nType].GetFrame(m_nCurrentFrame)->m_dwHeight ;
	rc.right = rc.left + m_epg[m_nType].GetFrame(m_nCurrentFrame)->m_dwWidth ;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -