使用C++与SFML编写一个简单的撞球游戏Part3——创建游戏启动界面

有游戏窗口了,接下来就为游戏添加一个启动界面吧!!!

我们将以SplashScreen.png跟MainMenu.png两幅图做为启动界面,资源可以点击这里下载

下载后请在项目文件夹里新建一个名为images的文件夹,然后把两幅图拷贝进去。

接下来就需要为两幅图分别创建一个类,以及进行相关设置,首先是SplashScreen,代码如下:

SplashScreen.h

1 #pragma once
2 class SplashScreen
3 {
4 public:
5     void Show(sf::RenderWindow& window);
6 };

SplashScreen.cpp

 1 #include "StdAfx.h"
 2 #include "SplashScreen.h"
 3 
 4 void SplashScreen::Show(sf::RenderWindow& renderWindow)
 5 {
 6     //创建texture对象来读取图片
 7     sf::Texture image;
 8     if(image.loadFromFile("images/SplashScreen.png") != true)
 9     {
10         return;
11     }
12 
13     //创建sprite对象来存储图片
14     sf::Sprite sprite(image);
15 
16     //如果图片成功创建则将其显示到游戏窗口里
17     renderWindow.draw(sprite);
18     renderWindow.display();
19 
20     sf::Event event;
21     while(true)
22     {
23         //跟上一part一样,用renderWindow对象来监听鼠标动作事件
24         while(renderWindow.pollEvent(event))
25         {
26             if(event.type == sf::Event::EventType::KeyPressed 
27                 || event.type == sf::Event::EventType::MouseButtonPressed
28                 || event.type == sf::Event::EventType::Closed )
29             {
30                 return;
31             }
32         }
33     }
34 }

然后是MainMenu,代码如下:

MainMenu.h

 1 #pragma once
 2 #include "SFML\Window.hpp"
 3 #include "SFML\Graphics.hpp"
 4 #include <list>
 5 
 6 class MainMenu
 7 {
 8 
 9 public:
10     enum MenuResult { Nothing, Exit, Play };    
11 
12     //用结构体来存储矩形点击区域的属性参数信息
13     struct MenuItem
14     {
15     public:
16         //用来存储矩形区域范围的点的模板对象
17         //一个点包含两个坐标值,两点形成一矩形区域
18         sf::Rect<int> rect;
19         MenuResult action;
20     };
21 
22     MenuResult Show(sf::RenderWindow& window);
23 
24 private:
25     MenuResult GetMenuResponse(sf::RenderWindow& window);
26     MenuResult HandleClick(int x, int y);
27 
28     //用来存储点击区域的容器
29     std::list<MenuItem> _menuItems;
30 };

MainMenu.cpp

 1 #include "stdafx.h"
 2 #include "MainMenu.h"
 3 
 4 
 5 MainMenu::MenuResult MainMenu::Show(sf::RenderWindow& window)
 6 {
 7     sf::Texture image;
 8     image.loadFromFile("images/mainmenu.png");
 9     sf::Sprite sprite(image);
10 
11     //设置鼠标点击矩形区域范围
12 
13     //play的点击范围
14     MenuItem playButton;
15     playButton.rect.top= 145;
16     playButton.rect.left = 0;
17     playButton.rect.width = 380;
18     playButton.rect.height = 1023;
19     playButton.action = Play;
20 
21     //Exit的点击范围
22     MenuItem exitButton;
23     exitButton.rect.top = 383;
24     exitButton.rect.left = 0;
25     exitButton.rect.height = 1023;
26     exitButton.rect.width = 560;
27     exitButton.action = Exit;
28 
29     //把点击范围放进容器里面
30     _menuItems.push_back(playButton);
31     _menuItems.push_back(exitButton);
32 
33     window.draw(sprite);
34     window.display();
35 
36     return GetMenuResponse(window);
37 }
38 
39 //判断鼠标点击位置是否在矩形区域里面从而返回状态参数
40 MainMenu::MenuResult MainMenu::HandleClick(int x, int y)
41 {
42     //迭代器遍历list容器里面存放的点击区域以供判断
43     std::list<MenuItem>::iterator it;
44 
45     for ( it = _menuItems.begin(); it != _menuItems.end(); it++)
46     {
47         sf::Rect<int> menuItemRect = (*it).rect;
48         if( menuItemRect.width > y 
49             && menuItemRect.top < y 
50             && menuItemRect.left < x 
51             && menuItemRect.height > x)
52         {
53             return (*it).action;
54         }
55     }
56 
57     return Nothing;
58 }
59 
60 //根据鼠标动作来做出相应的响应
61 MainMenu::MenuResult  MainMenu::GetMenuResponse(sf::RenderWindow& window)
62 {
63     sf::Event menuEvent;
64 
65     //这里的42!=43可以理解为true
66     while(42 != 43)
67     {
68 
69         while(window.pollEvent(menuEvent))
70         {
71             if(menuEvent.type == sf::Event::MouseButtonPressed)
72             {
73                 return HandleClick(menuEvent.mouseButton.x,menuEvent.mouseButton.y);
74             }
75             if(menuEvent.type == sf::Event::Closed)
76             {
77                 return Exit;
78             }
79         }
80     }
81 }

补充点:如果是用添加类的方式创建类的话,在添加MainMenu的时候会被禁止,因为MainMenu是被MFC保留的类名,所以还是乖乖地先添加.h再添加.cpp吧。

    值得一提的是,MainMenu.h中的容器list应该是被include在stdafx.h里面的,原文解释说包含在MainMenu.h里是方便起见而已.

最后要回到Game.h里面添加两个函数与private下面:

static void ShowSplashScreen();
static void ShowMenu();

当然还要实现它们,在Game.cpp里面添加(记得要include MainMenu.h 和 SplashScreen.h):

 1 void Game::ShowSplashScreen()
 2 {
 3     SplashScreen splashScreen;
 4     splashScreen.Show(_mainWindow);
 5     _gameState = Game::ShowingMenu;
 6 }
 7 
 8 void Game::ShowMenu()
 9 {
10     MainMenu mainMenu;
11     MainMenu::MenuResult result = mainMenu.Show(_mainWindow);
12     switch(result)
13     {
14     case MainMenu::Exit:
15         _gameState = Exiting;
16         break;
17     case MainMenu::Play:
18         _gameState = Playing;
19         break;
20     }
21 }

再把Start方法里面的_gameState 改为 Game::ShowingSplash;

让GameLoop方法变成如下样子就大功告成了:

 1 void Game::GameLoop()
 2 {
 3     sf::Event currentEvent;
 4     //从消息队列里面拿出消息
 5     _mainWindow.pollEvent(currentEvent);
 6   
 7     switch(_gameState)
 8     {
 9     case Game::ShowingSplash:
10         {
11             ShowSplashScreen();
12             break;
13         }
14     case Game::ShowingMenu:
15         {
16             ShowMenu();
17             break;
18         }
19     case Game::Playing:
20         {
21             //用黑色填充游戏画面
22             _mainWindow.clear(sf::Color(0,0,0));
23             _mainWindow.display();
24         
25             if(currentEvent.type == sf::Event::Closed)
26             {
27                 _gameState = Game::Exiting;
28             }
29             if(currentEvent.type == sf::Event::KeyPressed)
30             {
31                 if(currentEvent.key.code == sf::Keyboard::Escape) ShowMenu();
32             } 
33           break;
34         }
35      }  
36 }

现在按F5试试吧~~~~

原文地址:https://www.cnblogs.com/tomboy/p/2567324.html