/** * @brief Performs box traces against the world and all inline models, gives the hit position back * @param[in] mapTiles List of tiles the current (RMA-)map is composed of * @param[in] traceLine The start/stop position of the trace. * @param[in] traceBox The minimum/maximum extents of the collision box that is projected. * @param[in] levelmask A mask of the game levels to trace against. Mask 0x100 filters clips. * @param[in] brushmask Any brush detected must at least have one of these contents. * @param[in] brushreject Any brush detected with any of these contents will be ignored. * @param[in] list The local models list (a local model has a name starting with * followed by the model number) * @return a trace_t with the information of the closest brush intersected. * @sa CM_CompleteBoxTrace * @sa CM_HintedTransformedBoxTrace */ trace_t CM_EntCompleteBoxTrace (mapTiles_t* mapTiles, const Line& traceLine, const AABB* traceBox, int levelmask, int brushmask, int brushreject, const char** list) { AABB lineBox(*traceBox); lineBox.shift(traceLine.start); /* the traceBox in starting position */ AABB lineBoxTemp(*traceBox); lineBoxTemp.shift(traceLine.stop); /* in end position */ lineBox.add(lineBoxTemp); /* bounding box for the whole trace */ /* Now lineBox specifies the whole volume to be traced through. */ /* reconstruct a levelmask */ const vec_t minZ = lineBox.getMinZ(); const vec_t maxZ = lineBox.getMaxZ(); int newLevelMask = 0; if (levelmask & TL_FLAG_ACTORCLIP) /* if the passed levelmask contains the bit for the cliplevels, */ newLevelMask = TL_FLAG_ACTORCLIP; /* preserve it */ for (int i = 0; i < PATHFINDING_HEIGHT; i++) { const vec_t lower = i * UNIT_HEIGHT; /* the height bounds of the level */ const vec_t upper = (i + 1) * UNIT_HEIGHT; if (minZ > upper || maxZ < lower) continue; newLevelMask |= (1 << i); } /* trace against world first */ const trace_t tr = CM_CompleteBoxTrace(mapTiles, traceLine, *traceBox, newLevelMask, brushmask, brushreject); if (!list || tr.fraction == 0.0) return tr; trace_t trace = tr; for (const char** name = list; *name; name++) { /* check whether this is really an inline model */ if (*name[0] != '*') Com_Error(ERR_DROP, "name in the inlineList is no inline model: '%s'", *name); const cBspModel_t* model = CM_InlineModel(mapTiles, *name); assert(model); if (model->headnode >= mapTiles->mapTiles[model->tile].numnodes + 6) continue; AABB modelBox; /* Quickly calculate the bounds of this model to see if they can overlap. */ CM_CalculateWidestBoundingBox(model, modelBox); /* If the bounds of the extents box and the line do not overlap, then skip tracing this model. */ if (!lineBox.doesIntersect(modelBox)) continue; const trace_t newtr = CM_HintedTransformedBoxTrace(mapTiles->mapTiles[model->tile], traceLine, *traceBox, model->headnode, brushmask, brushreject, model->origin, model->angles, model->shift, trace.fraction); /* memorize the trace with the minimal fraction */ if (newtr.fraction == 0.0) return newtr; if (newtr.fraction < trace.fraction) trace = newtr; } return trace; }
bool PolyQtAnnotation::contains(const QPointF & point) const { if (shape().controlPointRect().contains(point)) { QPointF imgPoint = this->mapToScene(point) / _scale; double curSelectionSensitivity = (_selectionSensitivity * _lineAnnotationSelectedThickness / _currentLoD); double curSelectionSensitivitySquared = curSelectionSensitivity * curSelectionSensitivity; double imgX = imgPoint.x(); double imgY = imgPoint.y(); std::vector<Point> coords = _annotation->getCoordinates(); double minDist = std::numeric_limits<double>::max(); _lastClickedFirstCoordinateIndex = -1; _lastClickedSecondCoordinateIndex = -1; // Quickly check if a seed point was hit for (unsigned int i = 0; i < coords.size(); ++i) { Point pt1 = coords[i]; double coord1X = pt1.getX(); double coord1Y = pt1.getY(); double distSquared = pow(imgX - coord1X, 2) + pow(imgY - coord1Y, 2); if (distSquared < curSelectionSensitivitySquared && distSquared < minDist) { _lastClickedFirstCoordinateIndex = i; _lastClickedSecondCoordinateIndex = -1; _lastClickedLinePoint = QPointF(); minDist = distSquared; } } if (_lastClickedFirstCoordinateIndex >= 0) { return true; } minDist = std::numeric_limits<double>::max(); // If not, check if a line was hit std::vector<QPointF> polyInImgCoords; unsigned int polyIndex = 0; if (_type == "spline") { for (QPolygonF::const_iterator it = _polys.begin(); it != _polys.end(); ++it) { polyInImgCoords.push_back(this->mapToScene(*it) / _scale); } } for (unsigned int i = 0; i < coords.size(); ++i) { Point pt1 = coords[i]; Point pt2 = i == coords.size() -1 ? coords[0] : coords[i + 1]; double coord1X = pt1.getX(); double coord1Y = pt1.getY(); double coord2X = pt2.getX(); double coord2Y = pt2.getY(); QRectF hitbox(imgX - curSelectionSensitivity / 2., imgY - curSelectionSensitivity / 2., curSelectionSensitivity * 2., curSelectionSensitivity * 2.); QRectF lineBox(QPointF(std::min(coord1X, coord2X), std::max(coord1Y, coord2Y)), QPointF(std::max(coord1X, coord2X), std::min(coord1Y, coord2Y))); if (hitbox.intersects(lineBox)) { if (_type == "spline") { for (unsigned int j = 0; j < polyInImgCoords.size(); ++j) { QPointF polyPt1 = polyInImgCoords[polyIndex]; QPointF polyPt2 = polyIndex == polyInImgCoords.size() - 1 ? polyInImgCoords[0] : polyInImgCoords[polyIndex + 1]; if (QPoint(polyPt1.x(), polyPt1.y()) == QPoint(coord2X, coord2Y)) { break; } double polyCoord1X = polyPt1.x(); double polyCoord1Y = polyPt1.y(); double polyCoord2X = polyPt2.x(); double polyCoord2Y = polyPt2.y(); QRectF polyBox(QPointF(std::min(polyCoord1X, polyCoord2X), std::max(polyCoord1Y, polyCoord2Y)), QPointF(std::max(polyCoord1X, polyCoord2X), std::min(polyCoord1Y, polyCoord2Y))); if (hitbox.intersects(polyBox)) { double lineLengthSquared = pow(polyCoord1X - polyCoord2X, 2) + pow(polyCoord1Y - polyCoord2Y, 2); double t = ((imgX - polyCoord2X) * (polyCoord1X - polyCoord2X) + (imgY - polyCoord2Y) * (polyCoord1Y - polyCoord2Y)) / lineLengthSquared; double projX = polyCoord2X + t * (polyCoord1X - polyCoord2X); double projY = polyCoord2Y + t * (polyCoord1Y - polyCoord2Y); double distSquared = pow(imgX - projX, 2) + pow(imgY - projY, 2); if (distSquared < curSelectionSensitivitySquared && distSquared < minDist) { _lastClickedFirstCoordinateIndex = i; _lastClickedSecondCoordinateIndex = i + 1 == coords.size() ? 0 : i + 1; _lastClickedLinePoint = QPointF(projX, projY); } } ++polyIndex; } } else { double lineLengthSquared = pow(coord1X - coord2X, 2) + pow(coord1Y - coord2Y, 2); double t = ((imgX - coord2X) * (coord1X - coord2X) + (imgY - coord2Y) * (coord1Y - coord2Y)) / lineLengthSquared; double projX = coord2X + t * (coord1X - coord2X); double projY = coord2Y + t * (coord1Y - coord2Y); double distSquared = pow(imgX - projX, 2) + pow(imgY - projY, 2); if (distSquared < curSelectionSensitivitySquared && distSquared < minDist) { _lastClickedFirstCoordinateIndex = i; _lastClickedSecondCoordinateIndex = i + 1 == coords.size() ? 0 : i + 1; _lastClickedLinePoint = QPointF(projX, projY); } } } } if (_lastClickedFirstCoordinateIndex < 0) { return false; } else { return true; } } return false; }
void EnemyList::checkCollisions(PlayerProjectiles& playerProjectiles) { for (unsigned int i = 0; i < enemyList.size(); i++) { Point enemy(enemyList[i].getCompX(), enemyList[i].getCompY()); for (unsigned int j = 0; j < playerProjectiles.getSize(); j++) { Bullet* b = playerProjectiles.getBullet(j); Point bulPoint(b->getX(), b->getY()); if (enemyList[i].enemyType == 0 && Collision().checkCollision(playerProjectiles.getVector()[j].box, enemy, 0.97)) { b->destroy(); enemyList[i].enemyHP--; Explosion explosion; if (enemyList[i].enemyHP <= 0) { enemyList[i].destroyed = true; if (enemyList[i].enemyType == 0) { explosion = Explosion(enemyList[i].compX, enemyList[i].compY, 1, explosionTextureID); } else { explosion = Explosion(enemyList[i].compX, enemyList[i].compY, 2, explosionTextureID); } explosionList.addExplosion(explosion); } } else if (enemyList[i].enemyType == 1 && Collision().isIntersect(enemyList[i].box, enemy, b->box, bulPoint, 28, minTransDist)) { b->destroy(); enemyList[i].enemyHP--; if (enemyList[i].enemyHP <= 0) { enemyList[i].destroyed = true; Explosion explosion(enemyList[i].compX, enemyList[i].compY, 1, explosionTextureID); explosionList.addExplosion(explosion); } } } for (unsigned int j = 0; j < enemyList.size(); j++) { Point p2(enemyList[j].getCompX(), enemyList[j].getCompY()); if (i != j && Collision().isIntersect(enemyList[i].box, enemy, enemyList[j].box, p2, 28, minTransDist)) { if (enemyList[i].enemyType == 1) { enemyList[j].setMinTransDist(minTransDist.pointX, minTransDist.pointY); } else if (enemyList[j].enemyType == 1) { enemyList[i].setMinTransDist(minTransDist.pointX, minTransDist.pointY); } else { enemyList[i].setMinTransDist(minTransDist.pointX * 0.5, minTransDist.pointY * 0.5); enemyList[j].setMinTransDist(-minTransDist.pointX * 0.5, -minTransDist.pointY * 0.5); } } } Point playerPos(playerShipX, playerShipY); //std::cout << playerPos.pointX << "\t" << playerPos.pointY << "\t" << enemy.pointX << "\t" << enemy.pointY << std::endl; BoundingQuad lineBox(playerPos, playerPos, enemy, enemy); bool result = true; for (unsigned int j = 0; j < asteroidMapListRef->asteroidField.size(); j++) { Point p2(asteroidMapListRef->asteroidField[j].getRoidX(), asteroidMapListRef->asteroidField[j].getRoidY()); if (Collision().isIntersect(enemyList[i].box, enemy, asteroidMapListRef->asteroidField[j].box, p2, 28, minTransDist)) { enemyList[i].setMinTransDist(minTransDist.pointX * 2, minTransDist.pointY * 2); enemyList[i].turnAround(); } if (!Collision().hasLineOfSight(enemy, playerPos, lineBox, asteroidMapListRef->asteroidField[j].box, p2, 28)) { result = false; } } enemyList[i].setLOS(result); } for (unsigned int i = 0; i < playerProjectiles.getSize(); i++) { Bullet* b = playerProjectiles.getBullet(i); Point p1(b->getX(), b->getY()); for (unsigned int j = 0; j < asteroidMapListRef->asteroidField.size(); j++) { Point p2(asteroidMapListRef->asteroidField[j].getRoidX(), asteroidMapListRef->asteroidField[j].getRoidY()); if (Collision().isIntersect(b->box, p1, asteroidMapListRef->asteroidField[j].box, p2, 40, minTransDist)) { Explosion explosion(b->box.pointsN[2].pointX, b->box.pointsN[2].pointY, 0.3, explosionTextureID); explosionList.addExplosion(explosion); b->destroyed = true; } } } }