# 進階程式設計期末專題 - StarburstGame ## 動機 暑假時有想到可以自己來做小遊戲,當時有嘗試用$RPGMaker$做出一個小遊戲,不過因為當時做出來的成品不是很滿意,趁這次專題再挑戰做一次小遊戲。 ## 目標 使用$SFML(跨平台多媒體庫)$做出好玩又有趣的小遊戲 ## SFML簡介 $SFML(簡單快速多媒體庫)$是一個跨平台的軟件開發庫,旨在為計算機中的各種多媒體組件提供簡單的應用程序編程接口。 ### 程式庫簡單介紹 #### Window 建立和開啟視窗 ```=c++ sf::RenderWindow window(sf::VideoMode(800, 600), "SFML"); //建立新視窗 while (window.isOpen()) //開啟新視窗 { sf::Event event; while (window.pollEvent(event)) //偵測事件發生 { if (event.type == sf::Event::Closed) window.close(); } } ``` #### Event 基本事件控制 ```=c++ sf::Event event; while (window.pollEvent(event)) { //不同事件條件偵測 switch (event.type) { case sf::Event::Closed: window.close(); break; case sf::Event::KeyPressed: // ... break; default: break; } } ``` 常用事件 ```=c++ //文字輸入 sf::Event::TextEntered //按下按鍵 sf::Event::KeyPressed //放開按鍵 sf::Event::KeyReleased //滾動滑鼠滾輪 sf::Event::MouseWheelScrolled //滑鼠按下 sf::Event::MouseButtonPressed //滑鼠鬆開 sf::Event::MouseButtonReleased ``` #### Texture&Sprite $Texture$ $:$ 是一張圖片,但主要是用來改變物件的外觀。像是一個物品的材質。因為Texture本身不是物件,因此不能移動它。 $Sprite$ $:$ 是一張圖片,同時也是一個物件,意思是他擁有座標(x, y),你能移動/創建/刪除他。 $Texture$搭配$Sprite$ ```=c++ sf::Texture texture; texture.loadFromFile("picture.png"); //引入texture的材質 sf::Sprite sprite; sprite(texture); //使sprite(物體)包上材質 //在畫面上畫出sprite window.clear(); // 畫面背景 window.draw(sprite);// 畫出物體 window.display();// 畫面更新表現 ``` ## 實作 ### 遊戲想法 遊戲空間中有兩名玩家,互相碰撞,先碰到閃耀魔眼的玩家即輸。 ### 遊戲方式 > GAMEPLAY: PLAYER1(THE CYAN ONE) ↑---UP ↓---DOWN ←---LEFT →---RIGHT >PLAYER2(THE BLUE ONE) W---UP S---DOWN A---LEFT D---RIGHT --------------------------------------------------- ### 環境 $Microsoft$ $Visual$ $Studio$ $C++$ ### code ```c++= #include <iostream> #include <SFML/Audio.hpp> #include <SFML/Graphics.hpp> using namespace sf; // 物體碰撞 bool intersects(const CircleShape& c1, const CircleShape& c2) { FloatRect circ1 = c1.getGlobalBounds(); FloatRect circ2 = c2.getGlobalBounds(); return circ1.intersects(circ2); } int main() { // 建立畫面 VideoMode videomode(600, 600); RenderWindow window(videomode, "STARBURST GAME"); // 建立Player1 CircleShape circle; circle.setFillColor(Color::Cyan); circle.setPosition(100, 100); circle.setRadius(18); // 建立Player2 CircleShape circle2; circle2.setFillColor(Color::Blue); circle2.setPosition(100, 500); circle2.setRadius(18); // 建立閃耀魔眼(NPC人物) CircleShape GlameEyes; Texture glameeyes; glameeyes.loadFromFile("resources/glameeyes.png"); GlameEyes.setRadius(76); GlameEyes.setTexture(&glameeyes, true); GlameEyes.setPosition(470, 465); // 建立背景 Texture background; background.loadFromFile("resources/floor74.jpg"); Sprite BackGround; BackGround.setTexture(background); BackGround.setScale(Vector2f(0.6, 1.06571936057)); // PLAYER1勝利畫面 Texture CongratulationsCyan; CongratulationsCyan.loadFromFile("resources/congratulationscyan.jpg"); Sprite congratulationscyan; congratulationscyan.setTexture(CongratulationsCyan); congratulationscyan.setScale(Vector2f(0.6, 1.06571936057)); // PLAYER2勝利畫面 Texture CongratulationsBlue; CongratulationsBlue.loadFromFile("resources/congratulationsblue.jpg"); Sprite congratulationsblue; congratulationsblue.setTexture(CongratulationsBlue); congratulationsblue.setScale(Vector2f(0.6, 1.06571936057)); // 建立BGM音樂 Music music; music.openFromFile("resources/Swordland.ogg"); music.setLoop(true); music.play(); int dire = 1; while (window.isOpen()) { // 控制閃耀魔眼移動 if (GlameEyes.getPosition().y > 0 && dire == 1) { GlameEyes.move(0, -1); if (GlameEyes.getPosition().y == 1) { dire = 0; } } else if (GlameEyes.getPosition().y < 570 && dire == 0) { GlameEyes.move(0, 1); if (GlameEyes.getPosition().y == 569) { dire = 1; } } //畫面呈現 window.clear(Color::White); window.draw(BackGround); window.draw(circle); window.draw(circle2); window.draw(GlameEyes); window.display(); // 事件控制 Event event; if (window.pollEvent(event)) { if (event.type == Event::Closed) { window.close(); } } // 玩家鍵盤事件控制 if (Keyboard::isKeyPressed(Keyboard::Up)) { if (circle.getPosition().y > 0) { circle.move(0, -1); } } if (Keyboard::isKeyPressed(Keyboard::Down)) { if (circle.getPosition().y < 570) { circle.move(0, 1); } } if (Keyboard::isKeyPressed(Keyboard::Left)) { if (circle.getPosition().x > 0) { circle.move(-1, 0); } } if (Keyboard::isKeyPressed(Keyboard::Right)) { if (circle.getPosition().x < 570) { circle.move(1, 0); } } if (Keyboard::isKeyPressed(Keyboard::W)) { if (circle2.getPosition().y > 0) { circle2.move(0, -1); } } if (Keyboard::isKeyPressed(Keyboard::S)) { if (circle2.getPosition().y < 570) { circle2.move(0, 1); } } if (Keyboard::isKeyPressed(Keyboard::A)) { if (circle2.getPosition().x > 0) { circle2.move(-1, 0); } } if (Keyboard::isKeyPressed(Keyboard::D)) { if (circle2.getPosition().x < 570) { circle2.move(1, 0); } } // 玩家碰撞事件控制 if (intersects(circle, circle2)) { circle2.move(3, 0); } if (intersects(circle2, circle)) { circle.move(3, 0); } // 玩家勝利條件控制 Time time = seconds(5); if (intersects(circle, GlameEyes)) { window.draw(congratulationsblue); window.display(); sleep(time); window.close(); } if (intersects(circle2, GlameEyes)) { window.draw(congratulationscyan); window.display(); sleep(time); window.close(); } } } ``` ### 實際遊玩影片 [Youtube影片-程式設計專題 星爆小遊戲](https://youtu.be/x05QOPOnZiM) ## 心得 這個遊戲計畫原本想做更大一點,不過學測在即時間實在是不太夠,之後有時間再好好開發出一款有介面又有好的畫面效果的遊戲,除此之外code也有很多地方可以再修改,像是把角色用struct統合會好很多,總之做遊戲還蠻有趣的,之後學學unity好了。 ## 參考資料 [Youtube Playlist-SFML 2.4 For Beginners](https://www.youtube.com/playlist?list=PL21OsoBLPpMOO6zyVlxZ4S4hwkY_SLRW9) [SFML-Game-Developme-By-Example.pdf](https://github.com/BijayanBhattarai/BooksCollection/blob/master/Game%20Developement/SFML-Game-Developme-By-Example.pdf) [iT邦幫忙-寫遊戲初體驗](https://ithelp.ithome.com.tw/users/20130096/ironman/3531)