minimap.cpp
来自「这是整套横扫千军3D版游戏的源码」· C++ 代码 · 共 1,537 行 · 第 1/3 页
CPP
1,537 行
ProxyMouseRelease(x, y, button);
proxyMode = false;
return;
}
if (selecting) {
SelectUnits(x, y);
selecting = false;
return;
}
if (button == SDL_BUTTON_LEFT) {
if (showButtons && maximizeBox.Inside(x, y)) {
ToggleMaximized(!!keys[SDLK_LSHIFT]);
return;
}
if (showButtons && minimizeBox.Inside(x, y)) {
minimized = true;
return;
}
}
}
void CMiniMap::SetGeometry(int px, int py, int sx, int sy)
{
xpos = px;
ypos = py;
width = sx;
height = sy;
UpdateGeometry();
}
void CMiniMap::UpdateGeometry()
{
// keep the same distance to the top
ypos -= (lastWindowSizeY - gu->viewSizeY);
if (gu->dualScreenMode) {
width = gu->viewSizeX;
height = gu->viewSizeY;
xpos = (gu->viewSizeX - gu->viewPosX);
ypos = 0;
}
else if (maximized) {
SetMaximizedGeometry();
}
else {
width = max(1, min(width, gu->viewSizeX));
height = max(1, min(height, gu->viewSizeY));
ypos = max(slaveDrawMode ? 0 : buttonSize, ypos);
ypos = min(gu->viewSizeY - height, ypos);
xpos = max(0, min(gu->viewSizeX - width, xpos));
}
lastWindowSizeX = gu->viewSizeX;
lastWindowSizeY = gu->viewSizeY;
// setup the unit scaling
const float w = float(width);
const float h = float(height);
const float mapx = float(gs->mapx * SQUARE_SIZE);
const float mapy = float(gs->mapy * SQUARE_SIZE);
const float ref = unitBaseSize / powf((200.f * 200.0f), unitExponent);
const float dpr = ref * powf((w * h), unitExponent);
unitSizeX = dpr * (mapx / w);
unitSizeY = dpr * (mapy / h);
unitSelectRadius = sqrtf(unitSizeX * unitSizeY);
// in mouse coordinates
mapBox.xmin = xpos;
mapBox.xmax = mapBox.xmin + width - 1;
mapBox.ymin = gu->viewSizeY - (ypos + height);
mapBox.ymax = mapBox.ymin + height - 1;
if (!maximized) {
// right to left
resizeBox.xmax = mapBox.xmax;
resizeBox.xmin = resizeBox.xmax - (buttonSize - 1);
moveBox.xmax = resizeBox.xmax - buttonSize;
moveBox.xmin = resizeBox.xmin - buttonSize;
maximizeBox.xmax = moveBox.xmax - buttonSize;
maximizeBox.xmin = moveBox.xmin - buttonSize;
minimizeBox.xmax = maximizeBox.xmax - buttonSize;
minimizeBox.xmin = maximizeBox.xmin - buttonSize;
const int ymin = (mapBox.ymax + 1) + 3; // 3 for the white|black|white
const int ymax = ymin + (buttonSize - 1);
resizeBox.ymin = moveBox.ymin = maximizeBox.ymin = minimizeBox.ymin = ymin;
resizeBox.ymax = moveBox.ymax = maximizeBox.ymax = minimizeBox.ymax = ymax;
buttonBox.xmin = minimizeBox.xmin;
buttonBox.xmax = mapBox.xmax;
buttonBox.ymin = ymin - 3;
buttonBox.ymax = ymax;
} else {
// left to right
minimizeBox.xmin = mapBox.xmin;
minimizeBox.xmax = minimizeBox.xmin + (buttonSize - 1);
maximizeBox.xmin = minimizeBox.xmin + buttonSize;
maximizeBox.xmax = minimizeBox.xmax + buttonSize;
// dead buttons
resizeBox.xmin = resizeBox.ymin = moveBox.xmin = moveBox.ymin = 0;
resizeBox.xmax = resizeBox.ymax = moveBox.xmax = moveBox.ymax = -1;
const int ymin = mapBox.ymin;
const int ymax = ymin + (buttonSize - 1);
maximizeBox.ymin = minimizeBox.ymin = ymin;
maximizeBox.ymax = minimizeBox.ymax = ymax;
buttonBox.xmin = minimizeBox.xmin;
buttonBox.xmax = maximizeBox.xmax;
buttonBox.ymin = ymin - 3;
buttonBox.ymax = ymax;
}
}
/******************************************************************************/
void CMiniMap::MoveView(int x, int y)
{
const float3& pos = camera->pos;
const float3& dir = camera->forward;
float dist = ground->LineGroundCol(pos, pos + (dir * gu->viewRange * 1.4f));
float3 dif(0,0,0);
if (dist > 0) {
dif = dir * dist;
}
float3 clickPos;
clickPos.x = (float(x - xpos)) / width * gs->mapx * 8;
clickPos.z = (float(y - (gu->viewSizeY - ypos - height))) / height * gs->mapy * 8;
camCtrl->SetPos(clickPos);
unitTracker.Disable();
}
void CMiniMap::SelectUnits(int x, int y) const
{
if (!keys[SDLK_LSHIFT] && !keys[SDLK_LCTRL]) {
selectedUnits.ClearSelected();
}
CMouseHandler::ButtonPress& bp = mouse->buttons[SDL_BUTTON_LEFT];
if (fullProxy && (bp.movement > 4)) {
// use a selection box
const float3 newPos = GetMapPosition(x, y);
const float3 oldPos = GetMapPosition(bp.x, bp.y);
const float xmin = min(oldPos.x, newPos.x);
const float xmax = max(oldPos.x, newPos.x);
const float zmin = min(oldPos.z, newPos.z);
const float zmax = max(oldPos.z, newPos.z);
CUnitSet::iterator ui;
CUnitSet& selection = selectedUnits.selectedUnits;
CUnit* unit = NULL;
int addedunits = 0;
int team, lastTeam;
if (gu->spectatingFullSelect) {
team = 0;
lastTeam = gs->activeTeams - 1;
} else {
team = gu->myTeam;
lastTeam = gu->myTeam;
}
for (; team <= lastTeam; team++) {
CUnitSet& teamUnits = gs->Team(team)->units;
for (ui = teamUnits.begin(); ui != teamUnits.end(); ++ui) {
const float3& midPos = (*ui)->midPos;
if ((midPos.x > xmin) && (midPos.x < xmax) &&
(midPos.z > zmin) && (midPos.z < zmax)) {
if (keys[SDLK_LCTRL] && (selection.find(*ui) != selection.end())) {
selectedUnits.RemoveUnit(*ui);
} else {
selectedUnits.AddUnit(*ui);
unit = *ui;
addedunits++;
}
}
}
}
if (addedunits >= 2) {
sound->PlaySample(mouse->soundMultiselID);
}
else if (addedunits == 1) {
int soundIdx = unit->unitDef->sounds.select.getRandomIdx();
if (soundIdx >= 0) {
sound->PlayUnitReply(
unit->unitDef->sounds.select.getID(soundIdx), unit,
unit->unitDef->sounds.select.getVolume(soundIdx));
}
}
}
else {
// Single unit
const float size = unitSelectRadius;
const float3 pos = GetMapPosition(x, y);
CUnit* unit;
if (gu->spectatingFullSelect) {
unit = helper->GetClosestUnit(pos, size);
} else {
unit = helper->GetClosestFriendlyUnit(pos, size, gu->myAllyTeam);
}
CUnitSet::iterator ui;
CUnitSet& selection = selectedUnits.selectedUnits;
if (unit && ((unit->team == gu->myTeam) || gu->spectatingFullSelect)) {
if (bp.lastRelease < (gu->gameTime - mouse->doubleClickTime)) {
if (keys[SDLK_LCTRL] && (selection.find(unit) != selection.end())) {
selectedUnits.RemoveUnit(unit);
} else {
selectedUnits.AddUnit(unit);
}
} else {
//double click
if (unit->group && !keys[SDLK_LCTRL]) {
//select the current units group if it has one
selectedUnits.SelectGroup(unit->group->id);
} else {
//select all units of same type
int team, lastTeam;
if (gu->spectatingFullSelect) {
team = 0;
lastTeam = gs->activeTeams - 1;
} else {
team = gu->myTeam;
lastTeam = gu->myTeam;
}
for (; team <= lastTeam; team++) {
CUnitSet& myUnits = gs->Team(team)->units;
for (ui = myUnits.begin(); ui != myUnits.end(); ++ui) {
if ((*ui)->aihint == unit->aihint) {
selectedUnits.AddUnit(*ui);
}
}
}
}
}
bp.lastRelease = gu->gameTime;
int soundIdx = unit->unitDef->sounds.select.getRandomIdx();
if (soundIdx >= 0) {
sound->PlayUnitReply(
unit->unitDef->sounds.select.getID(soundIdx), unit,
unit->unitDef->sounds.select.getVolume(soundIdx));
}
}
}
}
/******************************************************************************/
CUnit* CMiniMap::GetSelectUnit(const float3& pos) const
{
CUnit* unit = helper->GetClosestUnit(pos, unitSelectRadius);
if (unit != NULL) {
const int losMask = (LOS_INLOS | LOS_INRADAR);
if ((unit->losStatus[gu->myAllyTeam] & losMask) || gu->spectatingFullView) {
return unit;
} else {
return NULL;
}
}
return unit;
}
float3 CMiniMap::GetMapPosition(int x, int y) const
{
const float mapHeight = readmap->maxheight + 1000.0f;
const float mapX = gs->mapx * SQUARE_SIZE;
const float mapY = gs->mapy * SQUARE_SIZE;
const float3 pos(mapX * float(x - xpos) / width, mapHeight,
mapY * float(y - (gu->viewSizeY - ypos - height)) / height);
return pos;
}
void CMiniMap::ProxyMousePress(int x, int y, int button)
{
float3 mapPos = GetMapPosition(x, y);
const CUnit* unit = GetSelectUnit(mapPos);
if (unit) {
if (gu->spectatingFullView) {
mapPos = unit->midPos;
} else {
mapPos = helper->GetUnitErrorPos(unit, gu->myAllyTeam);
mapPos.y = readmap->maxheight + 1000.0f;
}
}
CMouseHandler::ButtonPress& bp = mouse->buttons[button];
bp.camPos = mapPos;
bp.dir = float3(0.0f, -1.0f, 0.0f);
guihandler->MousePress(x, y, -button);
}
void CMiniMap::ProxyMouseRelease(int x, int y, int button)
{
// is this really needed?
CCamera *c = camera;
camera = new CCamera(*c);
const float3 tmpMouseDir = mouse->dir;
float3 mapPos = GetMapPosition(x, y);
const CUnit* unit = GetSelectUnit(mapPos);
if (unit) {
if (gu->spectatingFullView) {
mapPos = unit->midPos;
} else {
mapPos = helper->GetUnitErrorPos(unit, gu->myAllyTeam);
mapPos.y = readmap->maxheight + 1000.0f;
}
}
mouse->dir = float3(0.0f, -1.0f, 0.0f);
camera->pos = mapPos;
camera->forward = mouse->dir;
guihandler->MouseRelease(x, y, -button);
mouse->dir = tmpMouseDir;
delete camera;
camera = c;
}
/******************************************************************************/
bool CMiniMap::IsAbove(int x, int y)
{
if (minimized) {
if ((x < buttonSize) && (y < buttonSize)) {
return true;
} else {
return false;
}
}
else if (mapBox.Inside(x, y)) {
return true;
}
else if (showButtons && buttonBox.Inside(x, y)) {
return true;
}
return false;
}
std::string CMiniMap::GetTooltip(int x, int y)
{
if (minimized) {
return "Unminimize map";
}
if (buttonBox.Inside(x, y)) {
if (resizeBox.Inside(x, y)) {
return "Resize map\n(SHIFT to maintain aspect ratio)";
}
if (moveBox.Inside(x, y)) {
return "Move map";
}
if (maximizeBox.Inside(x, y)) {
if (!maximized) {
return "Maximize map\n(SHIFT to maintain aspect ratio)";
} else {
return "Unmaximize map";
}
}
if (minimizeBox.Inside(x, y)) {
return "Minimize map";
}
}
const string buildTip = guihandler->GetBuildTooltip();
if (!buildTip.empty()) {
return buildTip;
}
const CUnit* unit = GetSelectUnit(GetMapPosition(x, y));
if (unit) {
return CTooltipConsole::MakeUnitString(unit);
}
const string selTip = selectedUnits.GetTooltip();
if (selTip != "") {
return selTip;
}
const float3 pos(float(x-xpos)/width*gs->mapx*SQUARE_SIZE, 500,
float(y-(gu->viewSizeY-ypos-height))/height*gs->mapx*SQUARE_SIZE);
return CTooltipConsole::MakeGroundString(pos);
}
void CMiniMap::AddNotification(float3 pos, float3 color, float alpha)
{
Notification n;
n.pos = pos;
n.color[0] = color.x;
n.color[1] = color.y;
n.color[2] = color.z;
n.color[3] = alpha;
n.creationTime = gu->gameTime;
notes.push_back(n);
}
/******************************************************************************/
inline void DrawInMap2D(float x, float z)
{
glVertex2f(x, z);
}
void CMiniMap::DrawCircle(const float3& pos, float radius)
{
glPushMatrix();
glTranslatef(pos.x, pos.y, pos.z);
glScalef(radius, 1.0f, radius);
const float xPixels = radius * float(width) / float(gs->mapx * SQUARE_SIZE);
const float yPixels = radius * float(height) / float(gs->mapy * SQUARE_SIZE);
const int lod = (int)(0.25 * log2(1.0f + (xPixels * yPixels)));
const int lodClamp = max(0, min(circleListsCount - 1, lod));
glCallList(circleLists + lodClamp);
glPopMatrix();
}
void CMiniMap::DrawSurfaceCircle(const float3& pos, float radius, unsigned int)
{
minimap->DrawCircle(pos, radius);
}
void CMiniMap::Draw()
{
if (!slaveDrawMode) {
DrawForReal();
}
}
void CMiniMap::DrawForReal()
{
SCOPED_TIMER("Draw minimap");
glEnable(GL_BLEND);
glDepthFunc(GL_LEQUAL);
setSurfaceCircleFunc(DrawSurfaceCircle);
cursorIcons.Enable(false);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
if (minimized) {
if (!slaveDrawMode) {
DrawMinimizedButton();
}
cursorIcons.Enable(true);
setSurfaceCircleFunc(NULL);
return;
}
glViewport(xpos, ypos, width, height);
glLoadIdentity();
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0.0, 1.0, 0.0, 1.0, -1.0e6, +1.0e6);
glMatrixMode(GL_MODELVIEW);
glColor4f(0.6f, 0.6f, 0.6f, 1.0f);
// draw the map
glDisable(GL_BLEND);
readmap->DrawMinimap();
glEnable(GL_BLEND);
// move some of the transform to the GPU
glTranslatef(0.0f, +1.0f, 0.0f);
glScalef(+1.0f / (gs->mapx * SQUARE_SIZE), -1.0f / (gs->mapy * SQUARE_SIZE), 1.0);
// draw the units
list<CUnit*>::iterator ui;
for(ui=uh->activeUnits.begin();ui!=uh->activeUnits.end();ui++){
DrawUnit(*ui);
}
// highlight the selected unit
CUnit* unit = GetSelectUnit(GetMapPosition(mouse->lastx, mouse->lasty));
if (unit != NULL) {
DrawUnitHighlight(unit);
}
glDisable(GL_TEXTURE_2D);
left.clear();
// add restraints for camera sides
GetFrustumSide(cam2->bottom);
GetFrustumSide(cam2->top);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?