简单介绍
第一个视频中是扫雷游戏简单介绍
框架搭建
先建立mindsweeper.cpp文件,main函数中建一个类Game(把扫雷的代码存放在这里)
实例化game类的对象
其实把game类和mindsweeper文档的命名互换一下会更好,在game类中包含SFML头文件#include <SFML/Graphics.hpp>(若没有配置请在项目属性中配置,为了在debug 和release 两个模式下都好用,把配置改为所有配置,附加库依赖项先填debug版)
接下来添加两个基本头文件,在主函数中提前书写必要的函数
把游戏框架的核心函数搭建起来(在Game.hpp)
在Run()函数中把框架搭建起来
绘制游戏窗口,并对窗口对象申明
一些用到的属性变量申明一下,在构造函数中进行变量初始化之前看一下游戏背景的素材尺寸,对窗口变量初始化
对窗口进行创建并设置帧频
有窗口对象了,在游戏循环模块把while的条件更换一下
申明gameQuit对象用于游戏的退出
在初始化函数中继续初始化工作。
为什么初始化的工作要分散在两个不同的函数中完成?
到MineSweeper.cpp中,其实直接Mine.Run()也可以,到时候可以试一下
程序可以运行没有报错
添加事件变量
运行后鼠标点击窗口可以正常关闭
按窗口的esape键应该也可以关闭
到此项目搭建完成
鼠标交互
下面是这节课的鼠标按键按压和释放相应操作,初步成功后添加右键。
至于双击的添加(案件在一定时间间隔内快速的点击两下),需要在game.h增加一个计时器(注意创建的时候即开始运行)
需要思考的是双击的时间间隔统计应该从上次的按键释放到下次的按键按下,超过500毫秒(根据实际情况进行调整)算双击否则就算单击
到此鼠标交互结束
下面是以上所有部分的代码
Game.h
#pragma once
#include <SFML/Graphics.hpp>
#include <windows.h>
#include <iostream>
class Game
{
public:
sf::RenderWindow window;
Game();
~Game();
bool gameOver, gameQuit;
int Window_width, Window_height, stageWidth, stageHeight;
//A Clock starts conuting as soon as it's created
sf::Clock mouseClickTimer;
void Initial();
void Input();
void Logic();
void Draw();
void Run();
};
Game.cpp
#include "Game.h"
Game::Game()
{
Window_width = 860;
Window_height = 600;
window.create(sf::VideoMode(Window_width, Window_width), L"MindSweeper by");
}
Game::~Game()
{
}
void Game::Initial()
{
window.setFramerateLimit(60); //每秒设置目标帧频
gameOver = false;
gameQuit = false;
}
void Game::Input()
{
sf::Event event;//event type 包括Window、Keyboard、Mouse、Joystick, 4类消息
//通过 bool Window::pollEvent (sf::Event & event) 从窗口顺序询问(polled) 事件。
// 如果有一个事件等待处理,该函数将返回false,同样重要的是要注意,一次可能有多个事件,因此我们必须确保捕获每个
//
//
while (window.pollEvent(event))
{
if (event.type == sf::Event::Closed)
{
window.close(); //窗口可以移动,调整大小和最小化,但是如果要关闭,需要自己去调用close()函数
gameQuit = true;
}
if (event.type==sf::Event::EventType::KeyReleased && event.key.code == sf::Keyboard::Escape)
{
window.close(); //窗口可以移动,调整大小和最小化,但是如果要关闭,需要自己去调用close()函数
gameQuit = true;
}
if (event.type == sf::Event::MouseButtonPressed && event.mouseButton.button == sf::Mouse::Left)
{
if(mouseClickTimer.getElapsedTime().asMilliseconds()>1000)
std::cout << "Mouse::Left Pressed" << std::endl;
else
{
std::cout << "Mouse::Left Double Clicked" << std::endl;
}
}
if (event.type == sf::Event::MouseButtonReleased && event.mouseButton.button == sf::Mouse::Left)
{
std::cout << "Mouse::Left Released" << std::endl;
}
if (event.type == sf::Event::MouseButtonPressed && event.mouseButton.button == sf::Mouse::Right)
{
std::cout << "Mouse::Right Pressed" << std::endl;
}
if (event.type == sf::Event::MouseButtonReleased && event.mouseButton.button == sf::Mouse::Right)
{
std::cout << "Mouse::Left Released" << std::endl;
}
}
}
void Game::Logic()
{
}
void Game::Draw()
{
}
void Game::Run()
{
do
{
Initial();
while(window.isOpen()&&gameOver==false)
{
Input();
Logic();
Draw();
}
} while (!gameQuit);
}
MineSweeper.cpp
#include "Game.h"
int main()
{
Game Mine;
while (Mine.window.isOpen())
{
Mine.Run();
}
}
类的初级应用
在扫雷游戏开始之前,先简单介绍类的封装应用。查看素材,游戏舞台由很多方格组成,为便于对素材进行管理,在Game.h做一下宏定义
方格的状态用枚举进行表示
创建一个雷的类来管理舞台上的栅格对象
创建一些变量,创建栅格数据, 数组取最高难度舞台尺寸
增加游戏结束状态的枚举
出现了红色下划线 。申明一下命名空间。
创建纹理对象和精灵对象等一系列变量。要使用声音需要包含头文件#include <SFML/Audio.hpp>
增加个游戏时钟gameClock
本节主要采用枚举类型,对游戏和素材状态进行管理,同时创建雷的类来对栅格对象进行管理
上一节中Game类的定义也是对游戏整体的封装,初衷均是为了对游戏的各对象的管理能够更直观并管理
Game类的实例化在项目的MineSweeper.cpp中实现。
Game.h
#pragma once
#include <SFML/Graphics.hpp>
#include <SFML/Audio.hpp>
#include <windows.h>
#include <iostream>
#define GRIDSIZE 25
#define LVL1_WIDTH 9
#define LVL1_HEIGHT 9
#define LVL1_NUM 10
#define LVL2_WIDTH 16
#define LVL2_HEIGHT 16
#define LVL2_NUM 40
#define LVL3_WIDTH 30
#define LVL3_HEIGHT 16
#define LVL3_NUM 99
//枚举定义网格状态
typedef enum GRIDSTAT
{
ncNULL, //空地
ncUNDOWN, //背景方块
ncMine, //地雷
ncONE, //数字
ncTWO,
ncTHREE,
ncFOUR,
ncFIVE,
ncSIX,
ncSEVEN,
ncEIGHT,
ncFLAG, //标记
ncQ, //问号
ncX, //备用
ncBOMBING, //爆炸的雷
ncUNFOUND //未检测出来的雷
};
typedef enum GAMEOVERSTATE
{
ncNo, //游戏未结束
ncWIN, //游戏胜利
ncLOSE, //游戏失败
};
using namespace sf;
class LEI
{
public:
int mState; //栅格的状态(栅格——雷
int mStateBackUp; //栅格原始状态备份
bool isPress; //栅格是否被点击
};
class Game
{
public:
sf::RenderWindow window;
Game();
~Game();
bool gameOver, gameQuit;
int Window_width, Window_height, stageWidth, stageHeight, mMineNum, mFlagCalc;
int gamelvl, mTine; //游戏难度,游戏计时
LEI mGameData[LVL3_HEIGHT][LVL3_WIDTH]; //数组取最高难度舞台尺寸
bool isGameBegin; //游戏是否开始
int isGameOverState; //游戏结束的状态
sf::Vector2i mCornPoint; //舞台的左顶点坐标
int gridSize; //块的大小
Texture tBackground, tTiles, tButtons, tNum, tTimer, tCounter, tGameOver; //创建精灵对象
Sprite sBackground, sTiles, sButtons, sNum, sTimer, sCounter, sGameOver; //创建纹理对象
sf::IntRect ButtonRectEasy, ButtonRectNormal, ButtonRectHard, ButtonRectBG, ButtonRectRestart, ButtonRectQuit;
SoundBuffer sbWin, sbBoom;
Sound soundWin, soundBoom;
Music bkMusic;
//A Clock starts conuting as soon as it's created
sf::Clock gameClock, mouseClickTimer;
void Initial();
void Input();
void Logic();
void Draw();
void Run();
};
Game.cpp
#include "Game.h"
Game::Game()
{
Window_height = 600;
Window_width = 860;
window.create(sf::VideoMode(Window_width, Window_width), L"MindSweeper by");
}
Game::~Game()
{
}
void Game::Initial()
{
window.setFramerateLimit(60); //每秒设置目标帧频
gameOver = false;
gameQuit = false;
}
void Game::Input()
{
sf::Event event;//event type 包括Window、Keyboard、Mouse、Joystick, 4类消息
//通过 bool Window::pollEvent (sf::Event & event) 从窗口顺序询问(polled) 事件。
// 如果有一个事件等待处理,该函数将返回false,同样重要的是要注意,一次可能有多个事件,因此我们必须确保捕获每个
//
//
while (window.pollEvent(event))
{
if (event.type == sf::Event::Closed)
{
window.close(); //窗口可以移动,调整大小和最小化,但是如果要关闭,需要自己去调用close()函数
gameQuit = true;
}
if (event.type == sf::Event::EventType::KeyReleased && event.key.code == sf::Keyboard::Escape)
{
window.close(); //窗口可以移动,调整大小和最小化,但是如果要关闭,需要自己去调用close()函数
gameQuit = true;
}
if (event.type == sf::Event::MouseButtonPressed && event.mouseButton.button == sf::Mouse::Left)
{
if (mouseClickTimer.getElapsedTime().asMilliseconds() > 1000)
std::cout << "Mouse::Left Pressed" << std::endl;
else
{
std::cout << "Mouse::Left Double Clicked" << std::endl;
}
}
if (event.type == sf::Event::MouseButtonReleased && event.mouseButton.button == sf::Mouse::Left)
{
std::cout << "Mouse::Left Released" << std::endl;
}
if (event.type == sf::Event::MouseButtonPressed && event.mouseButton.button == sf::Mouse::Right)
{
std::cout << "Mouse::Right Pressed" << std::endl;
}
if (event.type == sf::Event::MouseButtonReleased && event.mouseButton.button == sf::Mouse::Right)
{
std::cout << "Mouse::Left Released" << std::endl;
}
}
}
void Game::Logic()
{
}
void Game::Draw()
{
}
void Game::Run()
{
do
{
Initial();
while (window.isOpen() && gameOver == false)
{
Input();
Logic();
Draw();
}
} while (!gameQuit);
}
MineSweeper.cpp
#include "Game.h"
int main()
{
Game Mine;
while (Mine.window.isOpen())
{
Mine.Run();
}
}