/*! \internal */ QSizeF *QGraphicsLayoutItemPrivate::effectiveSizeHints(const QSizeF &constraint) const { Q_Q(const QGraphicsLayoutItem); QSizeF *sizeHintCache; const bool hasConstraint = constraint.width() >= 0 || constraint.height() >= 0; if (hasConstraint) { if (!sizeHintWithConstraintCacheDirty && constraint == cachedConstraint) return cachedSizeHintsWithConstraints; sizeHintCache = cachedSizeHintsWithConstraints; } else { if (!sizeHintCacheDirty) return cachedSizeHints; sizeHintCache = cachedSizeHints; } for (int i = 0; i < Qt::NSizeHints; ++i) { sizeHintCache[i] = constraint; if (userSizeHints) combineSize(sizeHintCache[i], userSizeHints[i]); } QSizeF &minS = sizeHintCache[Qt::MinimumSize]; QSizeF &prefS = sizeHintCache[Qt::PreferredSize]; QSizeF &maxS = sizeHintCache[Qt::MaximumSize]; QSizeF &descentS = sizeHintCache[Qt::MinimumDescent]; normalizeHints(minS.rwidth(), prefS.rwidth(), maxS.rwidth(), descentS.rwidth()); normalizeHints(minS.rheight(), prefS.rheight(), maxS.rheight(), descentS.rheight()); // if the minimum, preferred and maximum sizes contradict each other // (e.g. the minimum is larger than the maximum) we give priority to // the maximum size, then the minimum size and finally the preferred size COMBINE_SIZE(maxS, q->sizeHint(Qt::MaximumSize, maxS)); combineSize(maxS, QSizeF(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX)); expandSize(maxS, prefS); expandSize(maxS, minS); boundSize(maxS, QSizeF(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX)); COMBINE_SIZE(minS, q->sizeHint(Qt::MinimumSize, minS)); expandSize(minS, QSizeF(0, 0)); boundSize(minS, prefS); boundSize(minS, maxS); COMBINE_SIZE(prefS, q->sizeHint(Qt::PreferredSize, prefS)); expandSize(prefS, minS); boundSize(prefS, maxS); // Not supported yet // COMBINE_SIZE(descentS, q->sizeHint(Qt::MinimumDescent, constraint)); if (hasConstraint) { cachedConstraint = constraint; sizeHintWithConstraintCacheDirty = false; } else { sizeHintCacheDirty = false; } return sizeHintCache; }
int main() { std::srand(static_cast<unsigned int>(std::time(NULL))); // Define some constants const float pi = 3.14159f; const int gameWidth = 800; const int gameHeight = 600; sf::Vector2f paddleSize(25, 100); float ballRadius = 10.f; bool easyMode = true; bool hardMode = false; // create the window sf::RenderWindow window(sf::VideoMode(gameWidth, gameHeight), "Dizzy Pong"); // set a view sf::View view = window.getDefaultView(); view.zoom(2.f); window.setView(view); float rVal = 0.005; // Load the sounds used in the game sf::SoundBuffer ballSoundBuffer; if (!ballSoundBuffer.loadFromFile("resources/ball.wav")) return EXIT_FAILURE; sf::Sound ballSound(ballSoundBuffer); sf::SoundBuffer outSoundBuffer; if (!outSoundBuffer.loadFromFile("resources/boxing_bell.wav")) return EXIT_FAILURE; sf::Sound outSound(outSoundBuffer); // set up text sf::Text text; int textXpos = 0; int textYpos = 0; int textSize = 44; sf::Color textColor = sf::Color::White; sf::Font font; if (!font.loadFromFile("resources/sansation.ttf")) return EXIT_FAILURE; text.setFont(font); text.setString("Hello!"); text.setCharacterSize(textSize); text.setColor(textColor); text.setPosition(textXpos, textYpos); sf::Text pauseMessage; pauseMessage.setFont(font); pauseMessage.setString("Welcome to SFML pong!\nPress space to start the game"); pauseMessage.setCharacterSize(textSize); pauseMessage.setColor(textColor); pauseMessage.setPosition(170.f, 150.f); sf::Text toggleInstruct; toggleInstruct.setFont(font); toggleInstruct.setString("Press h to toggle hard mode"); toggleInstruct.setCharacterSize(textSize*.8); toggleInstruct.setColor(textColor); toggleInstruct.setPosition(gameWidth / 3, gameHeight - 50); sf::Text playerScore; int pScore = 0; playerScore.setFont(font); playerScore.setString(std::to_string(pScore)); playerScore.setCharacterSize(textSize); playerScore.setColor(textColor); playerScore.setPosition(170.f, 150.f); sf::Text compScore; int cScore = 0; compScore.setFont(font); compScore.setString(std::to_string(cScore)); compScore.setCharacterSize(textSize); compScore.setColor(textColor); compScore.setPosition(370.f, 150.f); //set up visual boundaries sf::Vector2f boundSize(gameWidth, gameHeight); sf::RectangleShape boundary(boundSize); boundary.setFillColor(sf::Color::Black); boundary.setOutlineColor(sf::Color::White); boundary.setOutlineThickness(10); sf::Color boundColor; if (easyMode) boundColor = sf::Color::Red; else boundColor = sf::Color::Black; sf::RectangleShape leftBound(sf::Vector2f(15, gameHeight)); leftBound.setPosition(sf::Vector2f(-15, 0)); leftBound.setFillColor(boundColor); sf::RectangleShape rightBound(sf::Vector2f(15, gameHeight)); rightBound.setPosition(gameWidth, 0); rightBound.setFillColor(boundColor); //set up left paddle sf::Vector2f paddlePosL(10 + paddleSize.x / 2, gameHeight / 2); Paddle leftPaddle = Paddle::Paddle(paddleSize, sf::Color::White, paddlePosL); //set up right paddle sf::Vector2f paddlePosR((gameWidth-10)-paddleSize.x/2, gameHeight / 2); Paddle rightPaddle = Paddle::Paddle(paddleSize, sf::Color::White, paddlePosR); //set up ball Ball ball = Ball::Ball(ballRadius); // Define the paddles properties sf::Clock AITimer; const sf::Time AITime = sf::seconds(0.1f); const float paddleSpeed = 400.f; float rightPaddleSpeed = 0.f; const float ballSpeed = 400.f; float ballAngle = 0.f; // to be changed later sf::Clock clock; bool isPlaying = false; bool newRound = true; // run the program as long as the window is open while (window.isOpen()) { // check all the window's events that were triggered since the last iteration of the loop sf::Event event; while (window.pollEvent(event)) { // Window closed or escape key pressed: exit if ((event.type == sf::Event::Closed) || ((event.type == sf::Event::KeyPressed) && (event.key.code == sf::Keyboard::Escape))) { window.close(); break; } // h key pressed: toggle hardMode if ((event.type == sf::Event::KeyPressed) && (event.key.code == sf::Keyboard::H)) { hardMode = !hardMode; if (hardMode) boundColor = sf::Color::Black; else if (!hardMode) boundColor = sf::Color::Red; leftBound.setFillColor(boundColor); rightBound.setFillColor(boundColor); } // Space key pressed: play if ((event.type == sf::Event::KeyPressed) && (event.key.code == sf::Keyboard::Space)) { if (!isPlaying) { // (re)start the game isPlaying = true; clock.restart(); // Reset the position of the paddles and ball leftPaddle.paddle.setPosition(10 + paddleSize.x / 2, gameHeight / 2); rightPaddle.paddle.setPosition(gameWidth - 10 - paddleSize.x / 2, gameHeight / 2); ball.ball.setPosition(gameWidth / 2, gameHeight / 2); // Reset the ball angle do { // Make sure the ball initial angle is not too much vertical ballAngle = (std::rand() % 360) * 2 * pi / 360; } while (std::abs(std::cos(ballAngle)) < 0.7f); } } } if (isPlaying) { float deltaTime = clock.restart().asSeconds(); if (newRound){ // Reset the position of the paddles and ball leftPaddle.paddle.setPosition(10 + paddleSize.x / 2, gameHeight / 2); rightPaddle.paddle.setPosition(gameWidth - 10 - paddleSize.x / 2, gameHeight / 2); ball.ball.setPosition(gameWidth / 2, gameHeight / 2); // Reset the ball angle do { // Make sure the ball initial angle is not too much vertical ballAngle = (std::rand() % 360) * 2 * pi / 360; } while (std::abs(std::cos(ballAngle)) < 0.7f); newRound = false; } // Move the player's paddle if (sf::Keyboard::isKeyPressed(sf::Keyboard::Up) && (leftPaddle.paddle.getPosition().y - paddleSize.y / 2 > 5.f)) { leftPaddle.paddle.move(0.f, -paddleSpeed * deltaTime); } if (sf::Keyboard::isKeyPressed(sf::Keyboard::Down) && (leftPaddle.paddle.getPosition().y + paddleSize.y / 2 < gameHeight - 5.f)) { leftPaddle.paddle.move(0.f, paddleSpeed * deltaTime); } // Move the computer's paddle if (((rightPaddleSpeed < 0.f) && (rightPaddle.paddle.getPosition().y - paddleSize.y / 2 > 5.f)) || ((rightPaddleSpeed > 0.f) && (rightPaddle.paddle.getPosition().y + paddleSize.y / 2 < gameHeight - 5.f))) { rightPaddle.paddle.move(0.f, rightPaddleSpeed * deltaTime); } // Update the computer's paddle direction according to the ball position if (AITimer.getElapsedTime() > AITime) { AITimer.restart(); if (ball.ball.getPosition().y + ballRadius > rightPaddle.paddle.getPosition().y + paddleSize.y / 2) rightPaddleSpeed = paddleSpeed; else if (ball.ball.getPosition().y - ballRadius < rightPaddle.paddle.getPosition().y - paddleSize.y / 2) rightPaddleSpeed = -paddleSpeed; else rightPaddleSpeed = 0.f; } // Move the ball float factor = ballSpeed * deltaTime; ball.ball.move(std::cos(ballAngle) * factor, std::sin(ballAngle) * factor); // Check collisions between the ball and the screen //offscreen, play out sound if (ball.ball.getPosition().x - ballRadius < 0.f) { outSound.play(); if (cScore >= 3) { isPlaying = false; pauseMessage.setString("You lost!\nPress space to restart or\nescape to exit"); cScore = 0; pScore = 0; compScore.setString(std::to_string(cScore)); playerScore.setString(std::to_string(pScore)); newRound = true; rVal = 0; } else{ cScore = cScore + 1; compScore.setString(std::to_string(cScore)); newRound = true; if (!hardMode) rVal = 0; //pauseMessage.setString("You lost!\nPress space to restart or\nescape to exit"); } } if (ball.ball.getPosition().x + ballRadius > gameWidth) { outSound.play(); if (pScore >= 3) { isPlaying = false; pauseMessage.setString("You won!\nPress space to restart or\nescape to exit"); pScore = 0; cScore = 0; compScore.setString(std::to_string(cScore)); playerScore.setString(std::to_string(pScore)); newRound = true; rVal = 0; } else{ pScore++; playerScore.setString(std::to_string(pScore)); newRound = false; if (!hardMode) rVal = 0; //pauseMessage.setString("You won!\nPress space to restart or\nescape to exit"); } } //collisions with walls, play bounce sound if (ball.ball.getPosition().y - ballRadius < 0.f) { ballSound.play(); ballAngle = -ballAngle; ball.ball.setPosition(ball.ball.getPosition().x, ballRadius + 0.1f); } if (ball.ball.getPosition().y + ballRadius > gameHeight) { ballSound.play(); ballAngle = -ballAngle; ball.ball.setPosition(ball.ball.getPosition().x, gameHeight - ballRadius - 0.1f); } // Check the collisions between the ball and the paddles // Left Paddle if (ball.ball.getPosition().x - ballRadius < leftPaddle.paddle.getPosition().x + paddleSize.x / 2 && ball.ball.getPosition().x - ballRadius > leftPaddle.paddle.getPosition().x && ball.ball.getPosition().y + ballRadius >= leftPaddle.paddle.getPosition().y - paddleSize.y / 2 && ball.ball.getPosition().y - ballRadius <= leftPaddle.paddle.getPosition().y + paddleSize.y / 2) { if (ball.ball.getPosition().y > leftPaddle.paddle.getPosition().y) ballAngle = pi - ballAngle + (std::rand() % 20) * pi / 180; else ballAngle = pi - ballAngle - (std::rand() % 20) * pi / 180; ballSound.play(); ball.ball.setPosition(leftPaddle.paddle.getPosition().x + ballRadius + paddleSize.x / 2 + 0.1f, ball.ball.getPosition().y); if (!hardMode) rVal += .003; } // Right Paddle if (ball.ball.getPosition().x + ballRadius > rightPaddle.paddle.getPosition().x - paddleSize.x / 2 && ball.ball.getPosition().x + ballRadius < rightPaddle.paddle.getPosition().x && ball.ball.getPosition().y + ballRadius >= rightPaddle.paddle.getPosition().y - paddleSize.y / 2 && ball.ball.getPosition().y - ballRadius <= rightPaddle.paddle.getPosition().y + paddleSize.y / 2) { if (ball.ball.getPosition().y > rightPaddle.paddle.getPosition().y) ballAngle = pi - ballAngle + (std::rand() % 20) * pi / 180; else ballAngle = pi - ballAngle - (std::rand() % 20) * pi / 180; ballSound.play(); ball.ball.setPosition(rightPaddle.paddle.getPosition().x - ballRadius - paddleSize.x / 2 - 0.1f, ball.ball.getPosition().y); if (!hardMode) rVal += .003; } } // clear the window with black color window.clear(sf::Color::Black); // draw boundaries window.draw(boundary); window.draw(leftBound); window.draw(rightBound); if (isPlaying) { //roatate the view if (hardMode) rVal += 0.000001; view.rotate(rVal); window.setView(view); // Draw the paddles, score, and the ball window.draw(leftPaddle.paddle); window.draw(rightPaddle.paddle); window.draw(playerScore); window.draw(compScore); window.draw(ball.ball); } else { // Draw the pause message if (newRound){ view.setRotation(0); window.setView(view); window.draw(pauseMessage); window.draw(toggleInstruct); } } // end the current frame window.display(); } return 0; }
/*! \internal Note: Can potentially return the attached QQuickLayoutAttached object through \a attachedInfo. It is like this is because it enables it to be reused. The goal of this function is to return the effective minimum, preferred and maximum size hints that the layout will use for this item. This function takes care of gathering all explicitly set size hints, normalizes them so that min < pref < max. Further, the hints _not_explicitly_ set will then be initialized with the implicit size hints, which is usually derived from the content of the layouts (or items). The following table illustrates the preference of the properties used for measuring layout items. If present, the USER properties will be preferred. If USER properties are not present, the HINT properties will be preferred. Finally, the FALLBACK properties will be used as an ultimate fallback. Note that one can query if the value of Layout.minimumWidth or Layout.maximumWidth has been explicitly or implicitly set with QQuickLayoutAttached::isExtentExplicitlySet(). This determines if it should be used as a USER or as a HINT value. Fractional size hints will be ceiled to the closest integer. This is in order to give some slack when the items are snapped to the pixel grid. | *Minimum* | *Preferred* | *Maximum* | +----------------+----------------------+-----------------------+--------------------------+ |USER (explicit) | Layout.minimumWidth | Layout.preferredWidth | Layout.maximumWidth | |HINT (implicit) | Layout.minimumWidth | implicitWidth | Layout.maximumWidth | |FALLBACK | 0 | width | Number.POSITIVE_INFINITY | +----------------+----------------------+-----------------------+--------------------------+ */ void QQuickGridLayoutItem::effectiveSizeHints_helper(QQuickItem *item, QSizeF *cachedSizeHints, QQuickLayoutAttached **attachedInfo, bool useFallbackToWidthOrHeight) { for (int i = 0; i < Qt::NSizeHints; ++i) cachedSizeHints[i] = QSizeF(); QQuickLayoutAttached *info = attachedLayoutObject(item, false); // First, retrieve the user-specified hints from the attached "Layout." properties if (info) { struct Getters { SizeGetter call[NSizes]; }; static Getters horGetters = { {&QQuickLayoutAttached::minimumWidth, &QQuickLayoutAttached::preferredWidth, &QQuickLayoutAttached::maximumWidth}, }; static Getters verGetters = { {&QQuickLayoutAttached::minimumHeight, &QQuickLayoutAttached::preferredHeight, &QQuickLayoutAttached::maximumHeight} }; for (int i = 0; i < NSizes; ++i) { SizeGetter getter = horGetters.call[i]; Q_ASSERT(getter); if (info->isExtentExplicitlySet(Qt::Horizontal, (Qt::SizeHint)i)) cachedSizeHints[i].setWidth(qCeil((info->*getter)())); getter = verGetters.call[i]; Q_ASSERT(getter); if (info->isExtentExplicitlySet(Qt::Vertical, (Qt::SizeHint)i)) cachedSizeHints[i].setHeight(qCeil((info->*getter)())); } } QSizeF &minS = cachedSizeHints[Qt::MinimumSize]; QSizeF &prefS = cachedSizeHints[Qt::PreferredSize]; QSizeF &maxS = cachedSizeHints[Qt::MaximumSize]; QSizeF &descentS = cachedSizeHints[Qt::MinimumDescent]; // For instance, will normalize the following user-set hints // from: [10, 5, 60] // to: [10, 10, 60] normalizeHints(minS.rwidth(), prefS.rwidth(), maxS.rwidth(), descentS.rwidth()); normalizeHints(minS.rheight(), prefS.rheight(), maxS.rheight(), descentS.rheight()); // All explicit values gathered, now continue to gather the implicit sizes //--- GATHER MAXIMUM SIZE HINTS --- combineImplicitHints(info, Qt::MaximumSize, &maxS); combineSize(maxS, QSizeF(std::numeric_limits<qreal>::infinity(), std::numeric_limits<qreal>::infinity())); // implicit max or min sizes should not limit an explicitly set preferred size expandSize(maxS, prefS); expandSize(maxS, minS); //--- GATHER MINIMUM SIZE HINTS --- combineImplicitHints(info, Qt::MinimumSize, &minS); expandSize(minS, QSizeF(0,0)); boundSize(minS, prefS); boundSize(minS, maxS); //--- GATHER PREFERRED SIZE HINTS --- // First, from implicitWidth/Height qreal &prefWidth = prefS.rwidth(); qreal &prefHeight = prefS.rheight(); if (prefWidth < 0 && item->implicitWidth() > 0) prefWidth = qCeil(item->implicitWidth()); if (prefHeight < 0 && item->implicitHeight() > 0) prefHeight = qCeil(item->implicitHeight()); // If that fails, make an ultimate fallback to width/height if (!info && (prefWidth < 0 || prefHeight < 0)) info = attachedLayoutObject(item); if (useFallbackToWidthOrHeight && info) { /* This block is a bit hacky, but if we want to support using width/height as preferred size hints in layouts, (which we think most people expect), we only want to use the initial width. This is because the width will change due to layout rearrangement, and the preferred width should return the same value, regardless of the current width. We therefore store the width in the implicitWidth attached property. Since the layout listens to changes of implicitWidth, (it will basically cause an invalidation of the layout), we have to disable that notification while we set the implicit width (and height). Only use this fallback the first time the size hint is queried. Otherwise, we might end up picking a width that is different than what was specified in the QML. */ if (prefWidth < 0 || prefHeight < 0) { item->blockSignals(true); if (prefWidth < 0) { prefWidth = item->width(); item->setImplicitWidth(prefWidth); } if (prefHeight < 0) { prefHeight = item->height(); item->setImplicitHeight(prefHeight); } item->blockSignals(false); } } // Normalize again after the implicit hints have been gathered expandSize(prefS, minS); boundSize(prefS, maxS); //--- GATHER DESCENT // Minimum descent is only applicable for the effective minimum height, // so we gather the descent last. const qreal minimumDescent = minS.height() - item->baselineOffset(); descentS.setHeight(minimumDescent); if (attachedInfo) *attachedInfo = info; }