📄 cracecar.cpp
字号:
// RACE X
//
// Written by Mauricio Teichmann Ritter
//
// Copyright (C) 2002, Brazil. All rights reserved.
//
//
#include "stdafx.h"
#include "RaceX.h"
#include "cRaceCar.h"
#include ".\applib\ckeyboard.h"
#include <math.h>
#include <stdio.h>
#include "cRaceTrack.h"
#define CARBOUND_POINTS 4
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
cRaceCar::cRaceCar()
{
m_iMaxSpeed = 270;
m_iSpeed = 0;
m_fDirectionY = -9;
m_fDirectionX = 0;
m_fIncrementY = 1;
m_fIncrementX = 1;
m_fBackupIncrementX = 1;
m_fBackupIncrementY = 1;
m_iBackupDistanceToNextCheckPoint = 0;
m_fBackupDirectionY = -9;
m_fBackupDirectionX = 0;
m_iBackupAngle = 0;
m_iAngle = 0;
m_iCheckPoint = -1;
m_iLaps = 0;
m_pBound = (POINT*) malloc(sizeof(POINT) * CARBOUND_POINTS);
m_lLastTurn = 0;
m_lLastSpeedIncr = 0;
m_iCarState = CARSTATE_OK;
POINT tmpPoints[] = { {12,4}, {26,4}, {26,29}, {12,29}};
m_pBound =(POINT*) memcpy((void*) m_pBound,(void*) &tmpPoints, sizeof(POINT)* CARBOUND_POINTS);
m_hcRaceCar.CreatePolygonBound(m_pBound, CARBOUND_POINTS);
}
cRaceCar::~cRaceCar()
{
free(m_pBound);
m_hcRaceCar.Destroy();
}
void cRaceCar::SetPos(int iX, int iY)
{
m_fPosX = (float)iX;
m_fPosY = (float)iY;
}
void cRaceCar::Create(int iColor)
{
m_sprCar.Create(GetMainApp()->m_hInst, iColor, 360, 160, RGB(0,0,0), 40, 40);
m_hcRaceCar.CreateRectBound(40,40);
iCrashTime = 0;
m_iColor = iColor;
m_pSound.Create(MAKEINTRESOURCE(IDR_ENGINE), DSBCAPS_CTRL3D | DSBCAPS_CTRLFREQUENCY, DS3DALG_HRTF_LIGHT);
m_pSound.m_pSoundBuffer->SetCurrentPosition( 0 );
m_pCrashSound.Create(MAKEINTRESOURCE(IDR_EXPLODE), DSBCAPS_CTRL3D, DS3DALG_HRTF_LIGHT);
m_pCrashSound.m_pSoundBuffer->SetCurrentPosition( 0 );
m_lCurrentTime = 0;
m_bRemoteKeyboardStatus = 0;
m_bLastSent_Speed = -1;
m_bLastSent_Position = -1;
m_bLastSent_CarState = -1;
m_bLastSent_Laps = -1;
m_bLastSent_Angle = -1;
m_dwLastSent_LastLapTime = -1;
m_nLastSent_PosX = -1;
m_nLastSent_PosY = -1;
}
void cRaceCar::Destroy()
{
m_sprCar.Destroy();
m_hcRaceCar.Destroy();
m_sprCarExplode_0.Destroy();
m_sprCarExplode_135.Destroy();
m_sprCarExplode_180.Destroy();
m_sprCarExplode_225.Destroy();
m_sprCarExplode_270.Destroy();
m_sprCarExplode_315.Destroy();
m_sprCarExplode_45.Destroy();
m_sprCarExplode_90.Destroy();
m_pSound.Destroy();
m_pCrashSound.Destroy();
}
void cRaceCar::Draw(int iViewX, int iViewY)
{
// Draw the car based on the current position in the map
int iClipX = 0, iClipY = 0;
int iClipWidth = 40, iClipHeight = 40;
int iX = (int)m_fPosX - iViewX;
int iY = (int) m_fPosY - iViewY;
if((int)m_fPosX - iViewX > 640)
return;
if((int)m_fPosX - iViewX + 40 < 0)
return;
if((int) m_fPosY - iViewY > 460)
return;
if((int) m_fPosY - iViewY +40 < 0)
return;
if((int) m_fPosY - iViewY + 40 > 460)
iClipHeight = 40-((int) m_fPosY - iViewY + 40 - 460);
if((int) m_fPosX - iViewX + 40 > 640)
iClipWidth = 40-((int) m_fPosX - iViewX + 40 - 640);
if((int)m_fPosX - iViewX < 0)
{
iClipX = abs((int)m_fPosX - iViewX);
iClipWidth -= iClipX;
iX = 0;
}
if((int)m_fPosY - iViewY < 0)
{
iClipY = abs((int)m_fPosY - iViewY);
iClipHeight -= iClipY;
iY = 0;
}
if(m_iCarState == CARSTATE_CRASHED_WALL)
{
// If we crashed, play the explosion sprite
if(m_iAngle == 0)
m_sprCarExplode_0.Draw(GetMainApp()->m_pBackBuffer, iX, iY,m_sprCarExplode_0.IsEnd() ? FALSE : TRUE, iClipX, iClipY, iClipWidth, iClipHeight);
if(m_iAngle > 0 && m_iAngle < 90)
m_sprCarExplode_45.Draw(GetMainApp()->m_pBackBuffer, iX, iY,m_sprCarExplode_45.IsEnd() ? FALSE : TRUE, iClipX, iClipY, iClipWidth, iClipHeight);
if(m_iAngle == 90)
m_sprCarExplode_90.Draw(GetMainApp()->m_pBackBuffer, iX, iY,m_sprCarExplode_90.IsEnd() ? FALSE : TRUE, iClipX, iClipY, iClipWidth, iClipHeight);
if(m_iAngle > 90 && m_iAngle < 180)
m_sprCarExplode_135.Draw(GetMainApp()->m_pBackBuffer, iX, iY,m_sprCarExplode_135.IsEnd() ? FALSE : TRUE, iClipX, iClipY, iClipWidth, iClipHeight);
if(m_iAngle == 180)
m_sprCarExplode_180.Draw(GetMainApp()->m_pBackBuffer, iX, iY,m_sprCarExplode_180.IsEnd() ? FALSE : TRUE, iClipX, iClipY, iClipWidth, iClipHeight);
if(m_iAngle > 180 && m_iAngle < 270)
m_sprCarExplode_225.Draw(GetMainApp()->m_pBackBuffer, iX, iY,m_sprCarExplode_225.IsEnd() ? FALSE : TRUE, iClipX, iClipY, iClipWidth, iClipHeight);
if(m_iAngle == 270)
m_sprCarExplode_270.Draw(GetMainApp()->m_pBackBuffer, iX, iY,m_sprCarExplode_270.IsEnd() ? FALSE : TRUE, iClipX, iClipY, iClipWidth, iClipHeight);
if(m_iAngle > 270 && m_iAngle < 360)
m_sprCarExplode_315.Draw(GetMainApp()->m_pBackBuffer, iX, iY,m_sprCarExplode_315.IsEnd() ? FALSE : TRUE, iClipX, iClipY, iClipWidth, iClipHeight);
}
else
{
// otherwise, blit the normal car, in its current angle
m_sprCar.Draw(GetMainApp()->m_pBackBuffer, iX, iY, FALSE, iClipX, iClipY, iClipWidth, iClipHeight);
}
// If you want to see the car bounding rect, uncomment this
/*HDC hdc;
GetMainApp()->m_pBackBuffer->GetDC(&hdc);
OffsetRgn(m_hcRaceCar.hBoundingPoly, (int)m_fPosX - iViewX, (int) m_fPosY - iViewY);
FillRgn(hdc, m_hcRaceCar.hBoundingPoly, (HBRUSH) GetStockObject(BLACK_BRUSH));
OffsetRgn(m_hcRaceCar.hBoundingPoly, -1*((int)m_fPosX - iViewX), -1*((int) m_fPosY - iViewY));
GetMainApp()->m_pBackBuffer->ReleaseDC(hdc);
*/
}
void cRaceCar::Process(void* pTrack)
{
#define SPEEDXTURN 70
#define TURN_TIME 45
#define RAISESPEED_TIME 85
#define MAX_SPEED_FOR_CURVE 180
#define MAX_SPEED_FOR_IDLE 200
//升高速度量从而降低游戏速度
//降低速度量从而使游戏更快速
#define _SPEED_FACTOR_ 17
int iX, iY;
static long lLastMessage;
//iTurnCar = TURN_RIGHT;
cRaceTrack* theTrack = (cRaceTrack*)pTrack;
cKeyboard pKeyboard;
//如果赛车不在正常状态
if(m_iCarState != CARSTATE_OK)
{
//赛车发生碰撞,需要调入爆炸的声音
if(iCrashTime == 0)
{
iCrashTime = GetTickCount();
if(m_iCarState != CARSTATE_RACECOMPLETED)
m_pCrashSound.Play();
}
//爆炸
Crashed();
if(m_iCarState == CARSTATE_RACECOMPLETED)
{
}
else
{
if(GetTickCount() - iCrashTime > 2500)
{
// Crash time elapse, return the car to the backuped position
m_sprCarExplode_0.Destroy();
m_sprCarExplode_135.Destroy();
m_sprCarExplode_180.Destroy();
m_sprCarExplode_225.Destroy();
m_sprCarExplode_270.Destroy();
m_sprCarExplode_315.Destroy();
m_sprCarExplode_45.Destroy();
m_sprCarExplode_90.Destroy();
if( (GetRaceXApp()->m_bIsMultiplayer == TRUE && GetRaceXApp()->GetMultiplayer()->IsHosting()) ||
GetRaceXApp()->m_bIsMultiplayer == FALSE)
{
m_fDirectionX = m_fBackupDirectionX;
m_fDirectionY = m_fBackupDirectionY;
m_fIncrementX = m_fBackupIncrementX;
m_fIncrementY = m_fBackupIncrementY;
m_iDistanceToNextCheckPoint = m_iBackupDistanceToNextCheckPoint;
iTurnCar = iBackupTurnCar;
m_iAngle = m_iBackupAngle;
m_fPosX = m_fBackupPosX;
m_fPosY = m_fBackupPosY;
m_sprCar.m_iAbsolutePosition = m_iBackupSprite;
if(theTrack->GetRoadType((int)m_fPosX+10, (int)m_fPosY+10) == ID_ROADTYPE_ROADQ2 ||
theTrack->GetRoadType((int)m_fPosX+10, (int)m_fPosY+10) == ID_ROADTYPE_MEDIUMCURVEQ0P3 ||
theTrack->GetRoadType((int)m_fPosX+10, (int)m_fPosY+10) == ID_ROADTYPE_MEDIUMCURVEQ0P2)
{
m_fPosY+=10;
}
if(theTrack->GetRoadType((int)m_fPosX+10, (int)m_fPosY+10) == ID_ROADTYPE_ROADQ3||
theTrack->GetRoadType((int)m_fPosX+10, (int)m_fPosY+10) == ID_ROADTYPE_MEDIUMCURVEQ2P3 ||
theTrack->GetRoadType((int)m_fPosX+10, (int)m_fPosY+10) == ID_ROADTYPE_MEDIUMCURVEQ2P2)
{
m_fPosY-=10;
}
if(theTrack->GetRoadType((int)m_fPosX+10, (int)m_fPosY+10) == ID_ROADTYPE_ROADQ0 ||
theTrack->GetRoadType((int)m_fPosX+10, (int)m_fPosY+10) == ID_ROADTYPE_MEDIUMCURVEQ2P1 ||
theTrack->GetRoadType((int)m_fPosX+10, (int)m_fPosY+10) == ID_ROADTYPE_MEDIUMCURVEQ2P2)
{
m_fPosX+=10;
}
if(theTrack->GetRoadType((int)m_fPosX+10,(int) m_fPosY+10) == ID_ROADTYPE_ROADQ1 ||
theTrack->GetRoadType((int)m_fPosX+10, (int)m_fPosY+10) == ID_ROADTYPE_MEDIUMCURVEQ3P1 ||
theTrack->GetRoadType((int)m_fPosX+10, (int)m_fPosY+10) == ID_ROADTYPE_MEDIUMCURVEQ3P2)
{
m_fPosX-=10;
}
RotateBound(m_iAngle);
iX = 0;
iY = 0;
m_iDistanceToNextCheckPoint = 999999999;
do
{
iX = iX / 40;
iY = iY / 40;
theTrack->GetCheckPointPosition(&iX, &iY, m_iCheckPoint+1);
if(m_iDistanceToNextCheckPoint > (int) sqrt( ((m_fPosX - iX)*(m_fPosX - iX)) + ((m_fPosY - iY)*(m_fPosY - iY)) ))
{
m_iDistanceToNextCheckPoint = (int) sqrt( ((m_fPosX - iX)*(m_fPosX - iX)) + ((m_fPosY - iY)*(m_fPosY - iY)));
}
if(iX != -1)
iX += 40;
}while(iX>0);
for(int i=0;i<theTrack->GetNumberOfCars();i++)
{
if(m_bID != theTrack->m_pRaceCars[i]->GetID())
{
int iSrcX, iSrcY;
theTrack->m_pRaceCars[i]->GetPos(&iSrcX, &iSrcY);
if(m_hcRaceCar.HaveHitted(&theTrack->m_pRaceCars[i]->m_hcRaceCar, m_fPosX, m_fPosY, iSrcX, iSrcY) == FALSE)
{
m_iCarState = CARSTATE_OK;
iCrashTime = 0;
}
}
}
}
}
}
}
else
{
int i;
iCrashTime = 0;
//如果赛车由人控制,则读取键盘值,判断用户意图
if(m_iControlType == CTRL_USER)
{
if(pKeyboard.CheckKey(DIK_RIGHT))
{
TurnCarRight();
}
if(pKeyboard.CheckKey(DIK_LEFT))
{
TurnCarLeft();
}
if(pKeyboard.CheckKey(DIK_DOWN))
{
BreakCar();
}
if(pKeyboard.CheckKey(DIK_UP))
{
Accelerate();
}
else
{
Idle();
}
}/*USER CONTROL*/
//远端用户,发送键盘消息到主机
if(m_iControlType == CTRL_NETWORK_REMOTE &&
GetRaceXApp()->m_bIsMultiplayer == TRUE &&
GetRaceXApp()->GetMultiplayer()->IsHosting() )
{
// 键盘状态是一个字节变量,设置某些位从而判断哪个键被按下
if(m_bRemoteKeyboardStatus & 0x01)
{
TurnCarRight();
}
if(m_bRemoteKeyboardStatus & 0x02)
{
TurnCarLeft();
}
if(m_bRemoteKeyboardStatus & 0x04)
{
BreakCar();
}
if(m_bRemoteKeyboardStatus & 0x08)
{
Accelerate();
}
else
{
Idle();
}
}
//电脑控制的赛车
if(m_iControlType == CTRL_COMPUTER)
{
BOOL bCanBrake = FALSE;
//如果当前地图中贴片的角度和当前赛车的行进角度不一样,则需调整赛车的行进角度
if(m_iAngle != theTrack->GetAngle(m_fPosX+20, m_fPosY+20) &&
theTrack->GetAngle(m_fPosX+20, m_fPosY+20) != 370)
{
int iValue1 = (360-m_iAngle)+theTrack->GetAngle(m_fPosX+20, m_fPosY+20);
if(iValue1 > 360)
{
iValue1 = iValue1 % 360;
}
int iValue2 = (m_iAngle-theTrack->GetAngle(m_fPosX+20, m_fPosY+20));
if(iValue2 < 0)
{
iValue2+=360;
}
if(iValue1 < iValue2)
{
TurnCarRight();
bCanBrake = TRUE;
}
else
{
TurnCarLeft();
bCanBrake = TRUE;
}
}
//如果速度过快,则刹车
if(m_iSpeed > 270)
{
if(theTrack->CarHittedRoad(this, (int) m_fPosX+20+(m_iSpeed * (m_fDirectionX/9.0f)), (int) m_fPosY+20+ (m_iSpeed * (m_fDirectionY/9.0f))) == TRUE)
BreakCar();
}
if(bCanBrake == TRUE)
{
for(i=m_iSpeed-30;i>=0;i-=40)
{
if(theTrack->CarHittedRoad(this,(int)m_fPosX+20+(i*(m_fDirectionX/9.0f)),(int)m_fPosY+20+ (i * (m_fDirectionY/9.0f))) == TRUE)
{
BreakCar();
}
}
}
Accelerate();
}/*COMPUTER CONTROL*/
}
//如果赛车被一个远端用户控制
if(m_iControlType == CTRL_NETWORK_LOCAL &&
GetRaceXApp()->m_bIsMultiplayer == TRUE &&
!GetRaceXApp()->GetMultiplayer()->IsHosting() )
{
m_bRemoteKeyboardStatus = 0;
//从远端读取键盘状态值
if(pKeyboard.CheckKey(DIK_RIGHT))
{
m_bRemoteKeyboardStatus |= 0x01;
}
if(pKeyboard.CheckKey(DIK_LEFT))
{
m_bRemoteKeyboardStatus |= 0x02;
}
if(pKeyboard.CheckKey(DIK_DOWN))
{
m_bRemoteKeyboardStatus |= 0x04;
}
if(pKeyboard.CheckKey(DIK_UP))
{
m_bRemoteKeyboardStatus |= 0x08;
}
if(GetRaceXApp()->m_bSendKeyboard == TRUE || GetTickCount()-lLastMessage > 100)
{
GetRaceXApp()->GetMultiplayer()->SendTo(GetRaceXApp()->GetMultiplayer()->GetHost(), MSG_KEYBOARD_STATUS, &m_bRemoteKeyboardStatus, 1, 0/*DPNSEND_SYNC*/);
GetRaceXApp()->m_bSendKeyboard = FALSE;
lLastMessage = GetTickCount();
}
}
if((GetRaceXApp()->m_bIsMultiplayer==TRUE&&GetRaceXApp()->GetMultiplayer()->IsHosting())||
GetRaceXApp()->m_bIsMultiplayer == FALSE)
{
//处理完用户/电脑/网络输入后,重新定位赛车位置
m_fPosY = m_fPosY + ((float)m_fDirectionY / 9.0f) * ((float)m_iSpeed / _SPEED_FACTOR_);
m_fPosX = m_fPosX + ((float)m_fDirectionX / 9.0f) * ((float)m_iSpeed / _SPEED_FACTOR_);
// Track control goes here
// Check if we are passing throught a checkpoint or how far we are from thw
// next check point
if(m_iCarState == CARSTATE_OK)
{
if(m_iCheckPoint == -1)
{
if(theTrack->GetCheckPoint((int)m_fPosX+10,(int) m_fPosY+18) == 1)
{
m_iCheckPoint = 1;
m_lCurrentTime = GetTickCount();
iX = 0;
iY = 0;
m_iDistanceToNextCheckPoint = 999999999;
do
{
iX = iX / 40;
iY = iY / 40;
theTrack->GetCheckPointPosition(&iX, &iY, m_iCheckPoint+1);
if(m_iDistanceToNextCheckPoint > (int) sqrt( ((m_fPosX - iX)*(m_fPosX - iX)) + ((m_fPosY - iY)*(m_fPosY - iY)) ))
{
m_iDistanceToNextCheckPoint = (int) sqrt( ((m_fPosX - iX)*(m_fPosX - iX)) + ((m_fPosY - iY)*(m_fPosY - iY)));
}
if(iX != -1)
iX += 40;
}while(iX>0);
}
}
else
{
if(theTrack->GetCheckPoint((int)m_fPosX+10, (int)m_fPosY+18) <= m_iCheckPoint)
{
if(theTrack->GetCheckPoint((int)m_fPosX+10, (int)m_fPosY+18) == 1 &&
m_iCheckPoint == theTrack->GetMaxCheckPoint())
{
m_vcLapTimes.push_back(GetTickCount()-m_lCurrentTime);
m_lCurrentTime = GetTickCount();
m_iCheckPoint = 1;
iX = 0;
iY = 0;
m_iDistanceToNextCheckPoint = 999999999;
do
{
iX = iX / 40;
iY = iY / 40;
theTrack->GetCheckPointPosition(&iX, &iY, m_iCheckPoint+1);
if(m_iDistanceToNextCheckPoint > (int) sqrt( ((m_fPosX - iX)*(m_fPosX - iX)) + ((m_fPosY - iY)*(m_fPosY - iY)) ))
{
m_iDistanceToNextCheckPoint = (int) sqrt( ((m_fPosX - iX)*(m_fPosX - iX)) + ((m_fPosY - iY)*(m_fPosY - iY)));
}
if(iX != -1)
iX += 40;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -