برنامه نویسی

از صفر تا پونگ: اولین پروژه SFML من

من این عبارت را داشتم بهبود منظم مدرسه (Kagaku Joutatsu) در پیشینه دسک تاپ من سالها. به راحتی ترجمه شده ، به این معنی است که برای به دست آوردن درک واقعی ، باید با آشنا شروع کنید – اساسی ترین اصول. یادگیری انسان با تقلید آغاز می شود: نوزادان از والدین خود تقلید می کنند ، نوازندگان قطعات کلاسیک بازی می کنند و نقاشان مطالعات کارشناسی ارشد را انجام می دهند. آنها می گویند تقلید صادقانه ترین شکل چاپلوسی است ، اما همچنین یکی از مؤثرترین راهها برای یادگیری چیز جدید است.


چرا پونگ؟

در اوایل دهه 1970 ، به آلن آلکورن توسط رئیس خود ، نولان بوشلن ، یک کار تمرینی داده شد: یک بازی ورزشی ساده را برای ادیسه مگناوکس آن زمان محبوب بازآفرینی کنید. اجرای آلکورن چنان جلا داد که بوشلن تصمیم گرفت آن را به صورت تجاری آزاد کند. این بازی – پرشور – یک ضربه برک آوت ، به راه اندازی آتاری به عنوان یک نام خانوادگی و Trailblazer در صنعت بازی های ویدیویی تازه کار کمک می کند.

به یک معنا ، پنگ از ابتدا یک کلون بود. این تقلید از “تنیس روی میز” مگناوکس ، که خود یک دیجیتالی در ورزش واقعی بود. بنابراین کلونینگ پنگ احساس مشتق نمی کند. در هر صورت ، احساس می کنم ادای احترام می کنم.


چرا حالا؟

این ایده از زمانی که برای اولین بار با CS50 روبرو شدم در ذهنم لگد می زد آشنایی با توسعه بازیبشر این دوره از یک رویکرد مطالعه موردی برای بازسازی بازی های کلاسیک در LUA استفاده می کند و به دانشجویان می دهد که در معرض اصول اصلی طراحی بازی قرار بگیرند. من این مفهوم را دوست داشتم اما نمی خواستم لوا را در بالای هر چیز دیگری که یاد می گرفتم انتخاب کنم.

با این حال ، این ایده با من گیر کرده است. من فهمیدم که برنامه نویسی این بازی ها به زبانی متفاوت مزایای دو برابر را ارائه می دهد: درک عمیق تر از مکانیک بازی و نحو زبان. مصرف کمتر منفعل ، تمرین عمدی تر. دو پرنده ، یک سنگ.

این ما را اکنون به ارمغان می آورد. تجربه من با هر دو C ++ و SFML این بود که سخاوتمندانه ، حداقل. من چند فصل از LearnCpp.com و یک فیلم YouTube را در مورد پیوند SFML به ویژوال استودیو تماشا کرد. این در مورد آن بود

اما من آمریکایی هستم – اعتماد به نفس بدون درآمد عملاً سرگرمی ملی است.


🔗 لینک پروژه

آیا می خواهید دنبال کنید یا به کد نگاه کنید؟

👉 repo github: bikurastudios / pong-clone

ساخته شده با SFML 3.0 در ویژوال استودیو 2022

15 ساعت کار بیش از یک هفته عصرها


تجزیه


تنظیم پنجره

اولین قدم گرفتن و اجرای پنجره بازی اولین قدم بود. این بیشتر از آموزش کپی از آموزش ها بود ، نه یک چالش کدگذاری اصلی.

sf::RenderWindow window(sf::VideoMode(800, 600), "Pong");
window.setFramerateLimit(60);
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید


دستگیره

بعدی: Paddles. من مستطیل های سفید ساده را ترسیم کردم و آنها را روی صفحه قرار دادم.

sf::RectangleShape paddle(sf::Vector2f(10.f, 100.f));
paddle.setPosition(50.f, 250.f);
paddle.setFillColor(sf::Color::White);
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

(بله ، اعداد جادویی قبلاً شروع به خزیدن کرده اند.)


حرکت

برای رسیدگی به ورودی بدون اتصال آن به نرخ فریم ، من معرفی کردم deltaTime و آن را با سرعت دلخواه ضرب کرد.

if (sf::Keyboard::isKeyPressed(sf::Keyboard::W))
    paddle.move(0.f, -paddleSpeed * deltaTime);

if (sf::Keyboard::isKeyPressed(sf::Keyboard::S))
    paddle.move(0.f, paddleSpeed * deltaTime);
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید


مکانیک توپ

منطق توپ شبیه به بالشتک ها بود – آن را تنظیم کنید ، آن را موقعیت کنید ، سرعت را اختصاص دهید.

sf::CircleShape ball(10.f);
ball.setPosition(400.f, 300.f);
sf::Vector2f ballVelocity(200.f, 200.f);
ball.move(ballVelocity * deltaTime);
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

در کد من ، ballVelocity از نظر فنی شکسته است من سعی کردم جهت شروع را تصادفی کنم اما هرگز ژنراتور شماره تصادفی را بذر نکردم. بنابراین توپ هر بار در همان جهت حرکت می کند – به طور جدی “تصادفی”.


تشخیص برخورد

اینجاست که همه چیز کثیف شد.

من احتمالاً چهار ساعت به عقب و جلو بین فیلم های YouTube و انجمن ها صرف تلاش برای نوشتن یک عملکرد برخورد می کردم که خطاها را به چپ و راست نمی اندازد. حتی کوپیلوت گیر کرده بود ، و من با یک هوش مصنوعی توهم آور مبنی بر اینکه آیا یک عملکرد وجود داشته است یا نه ، درگیر دعوا شدم. سرانجام متوجه شدم که کد مربوط به تقاطع ها برای نسخه SFML 3.0 به روز شده است. بنابراین ، آنچه قبلاً مانند این تایپ می شد:

if (playerRect.getGlobalBounds().intersects(targetRect.getGlobalBounds()))
    Collision;
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

اکنون بیشتر شبیه به این است:

if (playerRect.getGlobalBounds().findIntersection(targetRect.getGlobalBounds()))
    Collision;
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

من احتمالاً باید این را سریعتر فهمیده بودم ، اما شما زندگی می کنید و یاد می گیرید.

به هر حال ، این محافظ صفحه نمایش DVD است که من وقتی فهمیدم که واقعاً قرار است انجام دهم ، ساخته ام:

یک توپ سفید روی صفحه حرکت می کند و از لبه های پنجره بلند می شود

سرانجام ، من در برخورد اساسی AABB (جعبه محدودیت محور) مستقر شدم. این کاربردی است ، هرچند کامل نیست. گاهی اوقات توپ به سمت بالشتک می چرخد ​​و قبل از خاموش شدن به شدت شتاب می یابد.

sf::FloatRect leftPaddleBounds = paddle.getGlobalBounds();
sf::FloatRect rightPaddleBounds = paddle2.getGlobalBounds();
sf::FloatRect ballBounds = ball.getGlobalBounds();

if (const std::optional intersection = ballBounds.findIntersection(leftPaddleBounds)) {
    sound_leftPaddle.play();
    ballVelocity.x *= -1.1f;
}

if (const std::optional intersection = ballBounds.findIntersection(rightPaddleBounds)) {
    sound_rightPaddle.play();
    ballVelocity.x *= -1.1f;
}
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

وقتی راحت تر از برخورد با برخورد برخورد می کنم ، این موضوع را دوباره مرور خواهیم کرد.


سیستم امتیاز دهی

اگر توپ خارج از صفحه می رود ، یک امتیاز کسب کنید و تنظیم مجدد کنید:

if (ball.getPosition().x < 0.f) {
    player2Score += 1;
    resetBall();
}

if (ball.getPosition().x > window.getSize().x) {
    player1Score += 1;
    resetBall();
}
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

سپس متن نمایش داده شده را به روز کنید:

player2ScoreString = std::to_string(player2Score);
scoreTextLeft.setString(player2ScoreString);

player1ScoreString = std::to_string(player1Score);
scoreTextRight.setString(player1ScoreString);
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید


قابلیت مکث

یک سیستم مکث مناسب به یک دستگاه دولتی احتیاج دارد ، اما من از یک بولی ساده استفاده کردم:

bool isPaused = false;

if (!isPaused) {
    // game loop
}

if (sf::Keyboard::isKeyPressed(sf::Keyboard::P)) {
    isPaused = !isPaused;
}
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

این ظریف نیست ، اما کار می کند.


بازنشانی بازی

من فقط پس از برخورد یک بازیکن به 10 امتیاز اجازه می دهم. کی startNewGame است ، true، همه چیز بازنشانی می کند:

if (startNewGame) {
    player1Score = 0;
    player2Score = 0;
    // Update score text

    // Reset positions
    ball.setPosition({400.f, 300.f});
    paddle.setPosition({50.f, 250.f});
    paddle2.setPosition({725.f, 250.f});

    // Reassign velocity
    directionX = randomDirection();
    directionY = randomDirection();
    ballVelocity = {200.f * directionX, 200.f * directionY};

    startNewGame = false;
}
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

در آینده ، من یک ویژگی تنظیم مجدد را می خواهم که در هر زمان کار کند.


Buggier از دفترچه راهنمای یک متخصص شناس

یک لیست اشکال غیر تجربی:

  • مستندات منسوخ برای ایجاد پنجره و ورودی

  • بالشتک های خارج از صفحه

  • توپ در صفحه نمایش با سرعت ترمینال

  • چند خط if اظهارات بدون {}

  • تعاریف عملکرد در داخل main()

  • سردرگمی با sf::Vector2f استدلال

  • جعبه های محدود از نظر مفهومی روشن اما ضعیف اجرا شده است

  • مشکل در بارگیری پرونده های قلم

  • عدم به روزرسانی متن نمره

  • ضرب و شتم دولت بیش از حد

در اینجا نمونه ای بد از منطق از اوایل به بعد آورده شده است:

if (keyPressed->scancode == sf::Keyboard::Scancode::Space) {
    if (Pause == true)
        Pause = false;
    if (Pause == false)
        Pause = true;
}
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

سرانجام ساده شد:

if (keyPressed->scancode == sf::Keyboard::Scancode::Space)
    Pause = !Pause;
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید


خلاصه بررسی کد

من هیچ برنامه نویسی در حلقه فوری خود ندارم ، بنابراین کد خود را به یک هوش مصنوعی انداختم و به آن گفتم که به من یک بررسی بدهد. در اینجا نتایج وجود دارد:

موضوعات مهم:

  1. main() 600+ خط بدون تجزیه بود

  2. منطق بازی ، ورودی و ارائه همه در main()

  3. کد تکراری (مرطوب)

  4. رسیدگی به رویداد ناکارآمد

مسائل جزئی:

  1. کد اظهار نظر بیش از حد

  2. استفاده بیش از حد از اعداد جادویی

  3. بدون استفاده از خطای دارایی

  4. منطق سخت و سخت به دلیل کمبود ضامن


پس چه چیزی یاد گرفتیم؟

در کل ، این یک پروژه اول محکم بود. من یک تن یاد گرفتم و با چیزی قابل پخش دور شدم. مهمتر از همه ، من به خودم ثابت کردم که می توانم یک بازی را شروع و به پایان برسانم. این افزایش اعتماد به نفس به تنهایی باعث شد کل روند ارزش آن را داشته باشد.

این همه برای این هفته ، مردمی است. هفته بعد وقتی که به پرنده Flappy نگاه می کنیم می بینیم.

سایونارا

نوشته های مشابه

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

دکمه بازگشت به بالا