void RangeMarker::RenderMissileRange(GradientTriangleStripShape3* renderer, const UnitRange& unitRange) { glm::vec2 center = unitRange.center; const float thickness = 8; glm::vec4 c0 = glm::vec4(255, 64, 64, 0) / 255.0f; glm::vec4 c1 = glm::vec4(255, 64, 64, 24) / 255.0f; float angleMinOuter = unitRange.angleStart; float angleMinInner = angleMinOuter + 0.03f; float angleMaxOuter = unitRange.angleStart + unitRange.angleLength; float angleMaxInner = angleMaxOuter - 0.03f; float range = unitRange.actualRanges.front(); glm::vec2 p2 = range * vector2_from_angle(angleMinOuter); glm::vec2 p4 = range * vector2_from_angle(angleMinInner); glm::vec2 p5 = (range - thickness) * vector2_from_angle(angleMinInner); glm::vec2 p1 = unitRange.minimumRange * vector2_from_angle(angleMinOuter); glm::vec2 p3 = p1 + (p4 - p2); for (int i = 0; i <= 8; ++i) { float t = i / 8.0f; renderer->AddVertex(GetPosition(center + glm::mix(p3, p5, t)), c0); renderer->AddVertex(GetPosition(center + glm::mix(p1, p2, t)), c1); } renderer->AddVertex(GetPosition(center + p4), c1); renderer->AddVertex(GetPosition(center + p4), c1); renderer->AddVertex(GetPosition(center + p5), c0); int n = (int)unitRange.actualRanges.size(); float angleDelta = (angleMaxInner - angleMinInner) / (n - 1); for (int i = 0; i < n; ++i) { range = unitRange.actualRanges[i]; float angle = angleMinInner + i * angleDelta; renderer->AddVertex(GetPosition(center + (range - thickness) * vector2_from_angle(angle)), c0); renderer->AddVertex(GetPosition(center + range * vector2_from_angle(angle)), c1); } range = unitRange.actualRanges.back(); p2 = range * vector2_from_angle(angleMaxOuter); p4 = range * vector2_from_angle(angleMaxInner); p5 = (range - thickness) * vector2_from_angle(angleMaxInner); p1 = unitRange.minimumRange * vector2_from_angle(angleMaxOuter); p3 = p1 + (p4 - p2); renderer->AddVertex(GetPosition(center + p4), c1); for (int i = 0; i <= 8; ++i) { float t = i / 8.0f; renderer->AddVertex(GetPosition(center + glm::mix(p2, p1, t)), c1); renderer->AddVertex(GetPosition(center + glm::mix(p5, p3, t)), c0); } }
void UnitTrackingMarker::AppendFacingMarker(VertexShape_2f_2f* vertices, BattleView* battleView) { if (_path.empty()) return; TerrainViewport* terrainViewport = &battleView->GetTerrainViewport(); float facing = GetFacing(); bounds2f b = battleView->GetUnitFacingMarkerBounds(_path.back(), facing); glm::vec2 p = b.mid(); float size = b.y().size(); float direction = facing - terrainViewport->GetCameraFacing(); if (terrainViewport->GetFlip()) direction += glm::pi<float>(); glm::vec2 d1 = size * vector2_from_angle(direction - glm::half_pi<float>() / 2.0f); glm::vec2 d2 = glm::vec2(d1.y, -d1.x); glm::vec2 d3 = glm::vec2(d2.y, -d2.x); glm::vec2 d4 = glm::vec2(d3.y, -d3.x); float tx1 = 0.125f; float tx2 = 0.125f + 0.125f; float ty1 = 0.75f; float ty2 = 0.75f + 0.125f; vertices->AddVertex(Vertex_2f_2f(terrainViewport->LocalToNormalized(p + d1), glm::vec2(tx1, ty1))); vertices->AddVertex(Vertex_2f_2f(terrainViewport->LocalToNormalized(p + d2), glm::vec2(tx1, ty2))); vertices->AddVertex(Vertex_2f_2f(terrainViewport->LocalToNormalized(p + d3), glm::vec2(tx2, ty2))); vertices->AddVertex(Vertex_2f_2f(terrainViewport->LocalToNormalized(p + d3), glm::vec2(tx2, ty2))); vertices->AddVertex(Vertex_2f_2f(terrainViewport->LocalToNormalized(p + d4), glm::vec2(tx2, ty1))); vertices->AddVertex(Vertex_2f_2f(terrainViewport->LocalToNormalized(p + d1), glm::vec2(tx1, ty1))); }
float TerrainGesture::NormalizeScrollSpeed(float value) const { TerrainView* terrainView = _hotspot->GetTerrainView(); glm::vec2 screenCenter = terrainView->GetTerrainViewport().NormalizedToLocal(glm::vec2{}); glm::vec3 contentCenter = terrainView->GetTerrainPosition3(screenCenter); float angle = terrainView->GetTerrainViewport().GetCameraFacing() + 0.5f * glm::pi<float>(); glm::vec3 contentPos = contentCenter + glm::vec3{value * vector2_from_angle(angle), 0}; glm::vec2 screenPos = terrainView->ContentToScreen(contentPos); glm::ivec2 viewportSize = terrainView->GetTerrainViewport().GetViewportBounds().size(); float viewportScale = glm::max(viewportSize.x, viewportSize.y); return glm::distance(screenCenter, screenPos) / viewportScale; };
void BattleGesture::UpdateTrackingMarker() { Unit* unit = _trackingMarker->GetUnit(); glm::vec2 screenTouchPosition = _trackingTouch->GetPosition(); glm::vec2 screenMarkerPosition = screenTouchPosition + glm::vec2(0, 1) * (_offsetToMarker * GetFlipSign()); glm::vec2 touchPosition = _battleView->GetTerrainPosition3(screenTouchPosition).xy(); glm::vec2 markerPosition = _battleView->GetTerrainPosition3(screenMarkerPosition).xy(); Unit* enemyUnit = FindEnemyUnit(touchPosition, markerPosition); glm::vec2 unitCenter = unit->state.center; bool isModifierMode = _tappedModiferArea || _modifierTouch != nullptr || _trackingTouch->GetCurrentButtons().right; _trackingMarker->SetRenderOrientation(isModifierMode); if (!isModifierMode) { std::vector<glm::vec2>& path = _trackingMarker->_path; glm::vec2 currentDestination = path.size() != 0 ? *(path.end() - 1) : unit->state.center; bounds2f contentBounds = _battleView->GetContentBounds(); glm::vec2 contentCenter = contentBounds.center(); float contentRadius = contentBounds.width() / 2; glm::vec2 differenceToCenter = contentCenter - markerPosition; float distanceToCenter = glm::length(differenceToCenter); if (distanceToCenter > contentRadius) { markerPosition += differenceToCenter * (distanceToCenter - contentRadius) / distanceToCenter; } float movementLimit = -1; float delta = 1.0f / fmaxf(1, glm::length(currentDestination - markerPosition)); for (float k = delta; k < 1; k += delta) { GroundMap* groundMap = _battleView->GetSimulator()->GetGroundMap(); if (groundMap != nullptr && groundMap->IsImpassable(glm::mix(currentDestination, markerPosition, k))) { movementLimit = k; break; } } if (movementLimit >= 0) { glm::vec2 diff = markerPosition - currentDestination; markerPosition = currentDestination + diff * movementLimit; markerPosition -= glm::normalize(diff) * 10.0f; enemyUnit = nullptr; } if (enemyUnit && !_trackingMarker->GetMeleeTarget()) SoundPlayer::singleton->Play(SoundBufferCommandMod); _trackingMarker->SetMeleeTarget(enemyUnit); _trackingMarker->SetDestination(&markerPosition); if (enemyUnit != nullptr) MovementRules::UpdateMovementPath(_trackingMarker->_path, unitCenter, enemyUnit->state.center); else MovementRules::UpdateMovementPath(_trackingMarker->_path, unitCenter, markerPosition); if (enemyUnit != nullptr) { glm::vec2 destination = enemyUnit->state.center; glm::vec2 orientation = destination + glm::normalize(destination - unitCenter) * 18.0f; _trackingMarker->SetOrientation(&orientation); } else if (MovementRules::Length(_trackingMarker->_path) > KEEP_ORIENTATION_TRESHHOLD) { glm::vec2 dir = glm::normalize(markerPosition - unitCenter); if (path.size() >= 2) dir = glm::normalize(*(path.end() - 1) - *(path.end() - 2)); glm::vec2 orientation = markerPosition + dir * 18.0f; _trackingMarker->SetOrientation(&orientation); } else { glm::vec2 orientation = markerPosition + 18.0f * vector2_from_angle(unit->state.bearing); _trackingMarker->SetOrientation(&orientation); } } else { MovementRules::UpdateMovementPathStart(_trackingMarker->_path, unitCenter); bool holdFire = false; if (_trackingMarker->GetUnit()->state.unitMode == UnitMode_Standing && _trackingMarker->GetUnit()->stats.maximumRange > 0) { bounds2f unitCurrentBounds = GetUnitCurrentBounds(_trackingMarker->GetUnit()); holdFire = glm::distance(screenMarkerPosition, unitCurrentBounds.center()) <= unitCurrentBounds.x().radius(); } if (holdFire) { _trackingMarker->SetMissileTarget(_trackingMarker->GetUnit()); _trackingMarker->SetOrientation(nullptr); } else { //if (!_tappedUnitCenter) // enemyUnit = nullptr; if (!_allowTargetEnemyUnit) enemyUnit = nullptr; if (enemyUnit != nullptr && _trackingMarker->GetMissileTarget() == nullptr) SoundPlayer::singleton->Play(SoundBufferCommandMod); _trackingMarker->SetMissileTarget(enemyUnit); _trackingMarker->SetOrientation(&markerPosition); } } }
void BattleGesture::TouchBegan(Touch* touch) { if (touch->GetSurface() != _battleView->GetSurface()) return; if (touch->HasGesture()) return; if (!_battleView->GetFrame().contains(touch->GetPosition())) return; if (_battleView->GetCommander() == nullptr) return; if (_battleView->GetCommander()->GetType() != BattleCommanderType::Player) return; if (!_battleView->GetCommander()->IsActive()) return; glm::vec2 screenPosition = touch->GetPosition(); glm::vec2 terrainPosition = _battleView->GetTerrainPosition3(screenPosition).xy(); Unit* unit = FindPlayerUnit(screenPosition, terrainPosition); if (_trackingTouch == nullptr) { if (unit == nullptr) return; if (unit != nullptr && _battleView->GetTrackingMarker(unit) == nullptr) { const UnitCommand command = unit->GetCommand(); _allowTargetEnemyUnit = unit->stats.missileType != MissileType::None; _trackingMarker = _battleView->AddTrackingMarker(unit); float distanceToUnitCenter = glm::distance(GetUnitCurrentBounds(unit).center(), screenPosition); float distanceToDestination = glm::distance(GetUnitFutureBounds(unit).center(), screenPosition); float distanceToModifierArea = glm::distance(GetUnitModifierBounds(unit).center(), screenPosition); float distanceMinimum = glm::min(distanceToUnitCenter, glm::min(distanceToDestination, distanceToModifierArea)); _tappedUnitCenter = distanceToUnitCenter == distanceMinimum; _tappedDestination = distanceToDestination == distanceMinimum && !_tappedUnitCenter; _tappedModiferArea = distanceToModifierArea == distanceMinimum && !_tappedUnitCenter && !_tappedDestination; if (_tappedDestination || _tappedModiferArea) { _offsetToMarker = 0;//(_boardView->ContentToScreen(vector3(unit->movement.GetFinalDestination(), 0)).y - _boardView->ContentToScreen(vector3(terrainPosition, 0)).y) * GetFlipSign(); if (_offsetToMarker < 0) _offsetToMarker = 0; std::vector<glm::vec2>& path = _trackingMarker->_path; path.clear(); path.insert(path.begin(), command.path.begin(), command.path.end()); glm::vec2 orientation = command.GetDestination() + 18.0f * vector2_from_angle(command.bearing); _trackingMarker->SetOrientation(&orientation); } else { _offsetToMarker = 0;//(_boardView->ContentToScreen(vector3(unit->state.center, 0)).y - _boardView->ContentToScreen(vector3(terrainPosition, 0)).y) * GetFlipSign(); if (_offsetToMarker < 0) _offsetToMarker = 0; glm::vec2 orientation = unit->state.center + 18.0f * vector2_from_angle(unit->state.bearing); _trackingMarker->SetOrientation(&orientation); } if (touch->GetTapCount() > 1 && _tappedUnitCenter && !_tappedDestination) { UnitCommand command; command.ClearPathAndSetDestination(unit->state.center); _battleView->GetSimulator()->SetUnitCommand(unit, command, _battleView->GetSimulator()->GetTimerDelay()); } _trackingMarker->SetRunning(touch->GetTapCount() > 1 || (!_tappedUnitCenter && command.running)); CaptureTouch(touch); _trackingTouch = touch; } else if (_modifierTouch == nullptr) { CaptureTouch(touch); _modifierTouch = touch; } else { CaptureTouch(touch); _trackingTouch = touch; } } else if (_modifierTouch == nullptr) { if (unit != nullptr) return; if (_gestures != nullptr) { for (Gesture* g : *_gestures) { BattleGesture* gesture = dynamic_cast<BattleGesture*>(g); if (gesture != nullptr && gesture != this && gesture->_trackingTouch != nullptr) { if (glm::length(_trackingTouch->GetPosition() - touch->GetPosition()) > glm::length(gesture->_trackingTouch->GetPosition() - touch->GetPosition())) return; } } } CaptureTouch(touch); _modifierTouch = touch; } }
void BattleView::Render(const glm::mat4& transformx) { glm::mat4 containerTransform = transformx * glm::inverse(GetContentTransform()); glm::mat4 terrainTransform = GetTerrainTransform(); glm::mat4 adjustmentTransform; adjustmentTransform = glm::scale(adjustmentTransform, glm::vec3(GetSize(), 1)); adjustmentTransform = glm::scale(adjustmentTransform, glm::vec3(0.5f, 0.5f, 1)); adjustmentTransform = glm::translate(adjustmentTransform, glm::vec3(1, 1, 0)); glm::mat4 contentTransform = transformx * adjustmentTransform * terrainTransform; glm::mat4 facingTransform = transformx * glm::translate(glm::mat4(), glm::vec3(-GetFrame().min, 0)); glm::vec2 facing = vector2_from_angle(GetCameraFacing() - 2.5f * (float)M_PI_4); _lightNormal = glm::normalize(glm::vec3(facing, -1)); // Terrain Sky glDisable(GL_DEPTH_TEST); if (_smoothTerrainSky != nullptr) { _smoothTerrainSky->RenderBackgroundLinen(containerTransform, _renderers, GetFrame(), GetFlip()); _smoothTerrainSky->Render(containerTransform, _renderers, GetFrame(), GetCameraDirection().z, GetFlip()); } // Terrain Surface glEnable(GL_DEPTH_TEST); glEnable(GL_CULL_FACE); if (_smoothTerrainSurface != nullptr) _smoothTerrainSurface->Render(contentTransform, _lightNormal); if (_tiledTerrainRenderer != nullptr) _tiledTerrainRenderer->Render(contentTransform, _lightNormal); // Terrain Water glDisable(GL_CULL_FACE); if (_smoothTerrainWater != nullptr) _smoothTerrainWater->Render(contentTransform); // Fighter Weapons glDepthMask(false); _plainLineRenderer->Reset(); for (UnitCounter* marker : _unitMarkers) marker->AppendFighterWeapons(_plainLineRenderer); _plainLineRenderer->Draw(contentTransform, glm::vec4(0.4, 0.4, 0.4, 0.6)); // Color Billboards _colorBillboardRenderer->Reset(); _casualtyMarker->RenderCasualtyColorBillboards(_colorBillboardRenderer); _colorBillboardRenderer->Draw(contentTransform, GetCameraUpVector(), GetFrame().height()); // Texture Billboards _billboardModel->dynamicBillboards.clear(); _casualtyMarker->AppendCasualtyBillboards(_billboardModel); for (UnitCounter* marker : _unitMarkers) marker->AppendFighterBillboards(_billboardModel); for (SmokeCounter* marker : _smokeMarkers) marker->AppendSmokeBillboards(_billboardModel); _textureBillboardRenderer->Render(_billboardModel, contentTransform, GetCameraUpVector(), glm::degrees(GetCameraFacing()), GetFrame().height(), GetFlip()); // Range Markers for (Unit* unit : _simulator->GetUnits()) { if (unit->commander == _commander) { RangeMarker marker(_simulator, unit); _gradientTriangleStripRenderer->Reset(); marker.Render(_gradientTriangleStripRenderer); _gradientTriangleStripRenderer->Draw(contentTransform); } } // Unit Facing Markers glDisable(GL_DEPTH_TEST); _textureTriangleRenderer->Reset(); for (UnitCounter* marker : _unitMarkers) if (marker->GetUnit()->commander == _commander) marker->AppendFacingMarker(_textureTriangleRenderer, this); for (UnitMovementMarker* marker : _movementMarkers) if (marker->GetUnit()->commander == _commander) marker->AppendFacingMarker(_textureTriangleRenderer, this); for (UnitTrackingMarker* marker : _trackingMarkers) if (marker->GetUnit()->commander == _commander) marker->AppendFacingMarker(_textureTriangleRenderer, this); _textureTriangleRenderer->Draw(facingTransform, _textureUnitMarkers); // Unit Markers _textureBillboardRenderer1->Reset(); _textureBillboardRenderer2->Reset(); for (UnitCounter* marker : _unitMarkers) marker->AppendUnitMarker(_textureBillboardRenderer2, GetFlip()); for (UnitMovementMarker* marker : _movementMarkers) marker->RenderMovementMarker(_textureBillboardRenderer1); for (UnitTrackingMarker* marker : _trackingMarkers) marker->RenderTrackingMarker(_textureBillboardRenderer1); bounds1f sizeLimit = GetUnitIconSizeLimit(); _textureBillboardRenderer1->Draw(_textureUnitMarkers, contentTransform, GetCameraUpVector(), glm::degrees(GetCameraFacing()), GetFrame().height(), sizeLimit); _textureBillboardRenderer2->Draw(_textureUnitMarkers, contentTransform, GetCameraUpVector(), glm::degrees(GetCameraFacing()), GetFrame().height(), sizeLimit); // Tracking Markers glDisable(GL_DEPTH_TEST); for (UnitTrackingMarker* marker : _trackingMarkers) { _textureBillboardRenderer1->Reset(); marker->RenderTrackingShadow(_textureBillboardRenderer1); _textureBillboardRenderer1->Draw(_textureTouchMarker, contentTransform, GetCameraUpVector(), glm::degrees(GetCameraFacing()), GetFrame().height(), bounds1f(64, 64)); } // Movement Paths glEnable(GL_DEPTH_TEST); _gradientTriangleRenderer->Reset(); for (UnitMovementMarker* marker : _movementMarkers) marker->RenderMovementPath(_gradientTriangleRenderer); _gradientTriangleRenderer->Draw(contentTransform);//, glm::vec4(0.5, 0.5, 1, 0.25)); // Tracking Path glDisable(GL_DEPTH_TEST); for (UnitTrackingMarker* marker : _trackingMarkers) { _gradientTriangleRenderer->Reset(); marker->RenderTrackingPath(_gradientTriangleRenderer); marker->RenderOrientation(_gradientTriangleRenderer); _gradientTriangleRenderer->Draw(contentTransform); } // Tracking Fighters glEnable(GL_DEPTH_TEST); _colorBillboardRenderer->Reset(); for (UnitTrackingMarker* marker : _trackingMarkers) marker->RenderTrackingFighters(_colorBillboardRenderer); _colorBillboardRenderer->Draw(contentTransform, GetCameraUpVector(), GetFrame().height()); // Movement Fighters _colorBillboardRenderer->Reset(); for (UnitMovementMarker* marker : _movementMarkers) marker->RenderMovementFighters(_colorBillboardRenderer); _colorBillboardRenderer->Draw(contentTransform, GetCameraUpVector(), GetFrame().height()); // Shooting Counters _gradientLineRenderer->Reset(); for (ShootingCounter* shootingCounter : _shootingCounters) shootingCounter->Render(_gradientLineRenderer); _gradientLineRenderer->Draw(contentTransform); // Mouse Hint _plainLineRenderer->Reset(); RenderMouseHint(_plainLineRenderer); _plainLineRenderer->Draw(contentTransform, glm::vec4(0, 0, 0, 0.5f)); glDepthMask(true); glDisable(GL_DEPTH_TEST); }
void RangeMarker::RenderMissileTarget(GradientTriangleStripShape3* renderer, glm::vec2 target) { glm::vec4 c0 = glm::vec4(255, 64, 64, 0) / 255.0f; glm::vec4 c1 = glm::vec4(255, 64, 64, 24) / 255.0f; glm::vec2 left = _unit->formation.GetFrontLeft(_unit->state.center); glm::vec2 right = left + _unit->formation.towardRight * (float)_unit->formation.numberOfFiles; glm::vec2 p; const float thickness = 4; const float radius_outer = 16; const float radius_inner = radius_outer - thickness; float radius_left = glm::distance(left, target); float radius_right = glm::distance(right, target); float angle_left = angle(left - target); float angle_right = angle(right - target); if (angle_left < angle_right) angle_left += 2 * glm::pi<float>(); glm::vec2 delta = thickness * vector2_from_angle(angle_left + glm::half_pi<float>()); renderer->AddVertex(GetPosition(left + delta), c0, true); renderer->AddVertex(GetPosition(left), c1); for (int i = 7; i >= 1; --i) { float r = i / 8.0f * radius_left; if (r > radius_outer) { p = target + r * vector2_from_angle(angle_left); renderer->AddVertex(GetPosition(p + delta), c0); renderer->AddVertex(GetPosition(p), c1); } } p = target + radius_outer * vector2_from_angle(angle_left); renderer->AddVertex(GetPosition(p + delta), c0); renderer->AddVertex(GetPosition(p), c1); p = target + radius_inner * vector2_from_angle(angle_left); renderer->AddVertex(GetPosition(p + delta), c0); renderer->AddVertex(GetPosition(p), c0); for (int i = 0; i <= 24; ++i) { float a = angle_left - i * (angle_left - angle_right) / 24; renderer->AddVertex(GetPosition(target + radius_outer * vector2_from_angle(a)), c1, i == 0); renderer->AddVertex(GetPosition(target + radius_inner * vector2_from_angle(a)), c0); } delta = thickness * vector2_from_angle(angle_right - glm::half_pi<float>()); p = target + radius_inner * vector2_from_angle(angle_right); renderer->AddVertex(GetPosition(p + delta), c0); renderer->AddVertex(GetPosition(p + delta), c0); p = target + radius_outer * vector2_from_angle(angle_right); renderer->AddVertex(GetPosition(p), c1); renderer->AddVertex(GetPosition(p + delta), c0); for (int i = 1; i <= 7; ++i) { float r = i / 8.0f * radius_right; if (r > radius_outer) { p = target + r * vector2_from_angle(angle_right); renderer->AddVertex(GetPosition(p), c1); renderer->AddVertex(GetPosition(p + delta), c0); } } renderer->AddVertex(GetPosition(right), c1); renderer->AddVertex(GetPosition(right + delta), c0); }