# 進階程式設計期末專題 - 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)