我正在用C++中的SDL2库编写一个简单的基于窗口的游戏。在SDL2_ttf库的帮助下,我在SDL_Window上显示静态字体就像游戏的名称一样没有问题。但是我还想向用户显示他们有多少条命和他们的分数(这将是SDL窗口保持打开的持续时间)。
这是我的sdlGame。h和sdlGame。cpp文件:
#ifndef sdlGame_h
#define sdlGame_h
#include <SDL2/SDL.h>
#include <SDL2_image/SDL_image.h>
#include <SDL2_ttf/SDL_ttf.h>
/* FOR WINDOWS, UNCOMMENT THESE 3 LINES
#include <SDL.h>
#include <SDL_image.h>
#include <SDL_ttf.h>
*/
#include "Game.h"
class Image {
private:
SDL_Surface * m_surface;
SDL_Texture * m_texture;
bool m_hasChanged;
public:
Image () ;
~Image();
void loadFromFile (const char* filename, SDL_Renderer * renderer);
void loadFromCurrentSurface (SDL_Renderer * renderer);
void draw (SDL_Renderer * renderer, int x, int y, int w=-1, int h=-1);
SDL_Texture * getTexture() const;
void setSurface(SDL_Surface * surf);
};
class SDLSimple {
private :
Game game;
SDL_Window * window;
SDL_Renderer * renderer;
TTF_Font * font;
Image font_im,font_score,font_time;
SDL_Color font_color;
Image shipImg;
Image astroImg;
Image spaceImg;
Image starImg;
Image shieldImg;
Image slowImg;
Image clrImg;
Image hpImg;
Image im_fantome;
bool mouse;
bool key;
public :
SDLSimple ();
~SDLSimple ();
void sdlBoucle ();
void sdlAff ();
};
#endif /* sdlGame_h */
#include <cassert>
#include <time.h>
#include "sdlGame.h"
#include <stdlib.h>
#include <string>
#include <iostream>
using namespace std;
const int TAILLE_SPRITE = 32;
float temps () {
return float(SDL_GetTicks()) / CLOCKS_PER_SEC; // conversion des ms en secondes en divisant par 1000
}
float timePassed = temps();
// ============= CLASS IMAGE =============== //
Image::Image () : m_surface(nullptr), m_texture(nullptr), m_hasChanged(false) {
}
Image::~Image()
{
SDL_FreeSurface(m_surface);
SDL_DestroyTexture(m_texture);
m_surface = nullptr;
m_texture = nullptr;
m_hasChanged = false;
}
void Image::loadFromFile (const char* filename, SDL_Renderer * renderer) {
m_surface = IMG_Load(filename);
if (m_surface == nullptr) {
string nfn = string("../") + filename;
cout << "Error: cannot load "<< filename <<". Trying "<<nfn<<endl;
m_surface = IMG_Load(nfn.c_str());
if (m_surface == nullptr) {
nfn = string("../") + nfn;
m_surface = IMG_Load(nfn.c_str());
}
}
if (m_surface == nullptr) {
cout<<"Error: cannot load "<< filename <<endl;
SDL_Quit();
exit(1);
}
SDL_Surface * surfaceCorrectPixelFormat = SDL_ConvertSurfaceFormat(m_surface,SDL_PIXELFORMAT_ARGB8888,0);
SDL_FreeSurface(m_surface);
m_surface = surfaceCorrectPixelFormat;
m_texture = SDL_CreateTextureFromSurface(renderer,surfaceCorrectPixelFormat);
if (m_texture == NULL) {
cout << "Error: problem to create the texture of "<< filename<< endl;
SDL_Quit();
exit(1);
}
}
void Image::loadFromCurrentSurface (SDL_Renderer * renderer) {
m_texture = SDL_CreateTextureFromSurface(renderer,m_surface);
if (m_texture == nullptr) {
cout << "Error: problem to create the texture from surface " << endl;
SDL_Quit();
exit(1);
}
}
void Image::draw (SDL_Renderer * renderer, int x, int y, int w, int h) {
int ok;
SDL_Rect r;
r.x = x;
r.y = y;
r.w = (w<0)?m_surface->w:w;
r.h = (h<0)?m_surface->h:h;
if (m_hasChanged) {
ok = SDL_UpdateTexture(m_texture,nullptr,m_surface->pixels,m_surface->pitch);
assert(ok == 0);
m_hasChanged = false;
}
ok = SDL_RenderCopy(renderer,m_texture,nullptr,&r);
assert(ok == 0);
}
SDL_Texture * Image::getTexture() const {return m_texture;}
void Image::setSurface(SDL_Surface * surf) {m_surface = surf;}
// ============= CLASS SDLJEU =============== //
SDLSimple::SDLSimple () : game() {
// Initialisation de la SDL
if (SDL_Init(SDL_INIT_VIDEO) < 0) {
cout << "Erreur lors de l'initialisation de la SDL : " << SDL_GetError() << endl;
SDL_Quit();
exit(1);
}
if (TTF_Init() != 0) {
cout << "Erreur lors de l'initialisation de la SDL_ttf : " << TTF_GetError() << endl;
SDL_Quit();
exit(1);
}
int imgFlags = IMG_INIT_PNG | IMG_INIT_JPG;
if( !(IMG_Init(imgFlags) & imgFlags)) {
cout << "SDL_image could not initialize! SDL_image Error: " << IMG_GetError() << endl;
SDL_Quit();
exit(1);
}
int dimx, dimy;
dimx = game.getTerrain().getDimX();
dimy = game.getTerrain().getDimY();
dimx = dimx * TAILLE_SPRITE;
dimy = dimy * TAILLE_SPRITE;
// Creation de la fenetre
window = SDL_CreateWindow("Space Race", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 960, 960, SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE);
if (window == nullptr) {
cout << "Erreur lors de la creation de la fenetre : " << SDL_GetError() << endl;
SDL_Quit();
exit(1);
}
renderer = SDL_CreateRenderer(window,-1,SDL_RENDERER_ACCELERATED);
// IMAGES (filepaths are placeholders)
shipImg.loadFromFile("filepath", renderer);
astroImg.loadFromFile("filepath", renderer);
hpImg.loadFromFile("/filepath", renderer);
shieldImg.loadFromFile("filepath", renderer);
spaceImg.loadFromFile("filepath", renderer);
starImg.loadFromFile("filepath", renderer);
slowImg.loadFromFile("filepath", renderer);
clrImg.loadFromFile("filepath", renderer);
// FONTS
font = TTF_OpenFont("filepathforfont",50);
if (font == nullptr)
font = TTF_OpenFont("filepathforfont",50);
if (font == nullptr) {
cout << "Failed to load DejaVuSansCondensed.ttf! SDL_TTF Error: " << TTF_GetError() << endl;
SDL_Quit();
exit(1);
}
font_color.r = 255;font_color.g = 255;font_color.b = 255;
font_im.setSurface(TTF_RenderText_Solid(font,"Space Race",font_color));
font_score.setSurface(TTF_RenderText_Solid(font,"Score",font_color));
font_time.setSurface(TTF_RenderText_Solid(font, timePassed, font_color));
font_im.loadFromCurrentSurface(renderer);
font_score.loadFromCurrentSurface(renderer);
font_time.loadFromCurrentSurface(renderer);
}
SDLSimple::~SDLSimple () {
TTF_CloseFont(font);
TTF_Quit();
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(window);
SDL_Quit();
}
void SDLSimple::sdlAff () {
SDL_SetRenderDrawColor(renderer, 230, 240, 255, 255);
SDL_RenderClear(renderer);
int x,y;
const Terrain& ter = game.getTerrain();
const Ship& ship = game.getShip();
for (x=0;x<ter.getDimY();x++){
for (y=0;y<ter.getDimX();y++){
if (ter.getXYasChar(x,y)==' '){
spaceImg.draw(renderer,x*TAILLE_SPRITE,y*TAILLE_SPRITE,TAILLE_SPRITE,TAILLE_SPRITE);
}
else if (ter.getXYasChar(x,y)=='*'){
starImg.draw(renderer,x*TAILLE_SPRITE,y*TAILLE_SPRITE,TAILLE_SPRITE,TAILLE_SPRITE);
}
else if (ter.getXYType(x,y)==Terrain::ASTRO){
spaceImg.draw(renderer,x*TAILLE_SPRITE,y*TAILLE_SPRITE,TAILLE_SPRITE,TAILLE_SPRITE);
astroImg.draw(renderer,x*TAILLE_SPRITE,y*TAILLE_SPRITE,TAILLE_SPRITE,TAILLE_SPRITE);
}
}
}
// Afficher le sprite de Pacman
shipImg.draw(renderer,ship.getX()*TAILLE_SPRITE,ship.getY()*TAILLE_SPRITE,TAILLE_SPRITE,TAILLE_SPRITE);
// Ecrire un titre par dessus
SDL_Rect positionTitre;
SDL_Rect positionScore;
SDL_Rect positionTime;
positionTitre.x = 480;positionTitre.y = 0;positionTitre.w = 100;positionTitre.h = 30;
positionScore.x = 0; positionScore.y = 0; positionScore.w = 100; positionScore.h = 30;
positionTime.x = 0; positionTime.y = 30; positionTime.w = 100; positionTime.h = 23;
SDL_RenderCopy(renderer,font_im.getTexture(),nullptr,&positionTitre);
SDL_RenderCopy(renderer,font_score.getTexture(),nullptr,&positionScore);
SDL_RenderCopy(renderer,font_time.getTexture(),nullptr,&positionTime);
}
void SDLSimple::sdlBoucle () {
SDL_Event events;
bool quit = false;
Uint32 t = SDL_GetTicks(), nt;
// tant que ce n'est pas la fin ...
while (!quit) {
nt = SDL_GetTicks();
if (nt-t>500) {
game.actionsAuto();
t = nt;
}
// tant qu'il y a des évenements à traiter (cette boucle n'est pas bloquante)
while (SDL_PollEvent(&events)) {
if (events.type == SDL_QUIT) quit = true; // Si l'utilisateur a clique sur la croix de fermeture
else if (events.type == SDL_KEYDOWN) { // Si une touche est enfoncee
bool deleteAstroCollided = false;
switch (events.key.keysym.scancode) {
case SDL_SCANCODE_W:
deleteAstroCollided = game.keyboardListener('s'); // car Y inverse
break;
case SDL_SCANCODE_S:
deleteAstroCollided = game.keyboardListener('w'); // car Y inverse
break;
case SDL_SCANCODE_A:
deleteAstroCollided = game.keyboardListener('a');
break;
case SDL_SCANCODE_D:
deleteAstroCollided = game.keyboardListener('d');
break;
case SDL_SCANCODE_ESCAPE:
case SDL_SCANCODE_Q:
quit = true;
break;
default: break;
}
}
}
if(game.getShip().getLifeCount() == 0){
quit = true;
}
// on affiche le jeu sur le buffer cach�
sdlAff();
// on permute les deux buffers (cette fonction ne doit se faire qu'une seule fois dans la boucle)
SDL_RenderPresent(renderer);
}
}
你可以看到在。h文件,我已经声明了一个名为“font_time”的字体来表示时间的ttf_font。
在.cpp文件中,我有一个名为“temps()”的全局函数,它返回使用SDL_GetTicks()花费的时间,并将其除以1000以获得以秒为单位的时间。我有一个名为“time Passed”的浮点数,它使用temps()函数来获取经过的时间。
在一行中,我试图像渲染其他字体一样渲染字体:
font_time.setSurface(TTF_RenderText_Solid(font, to_string(timePassed), font_color));
但是,我有一个错误说:没有匹配的函数用于调用'TTF_RenderText_Solid'
我阅读了文档,我看到第二个参数是指向文本的const char指针,但我认为它只适用于静态字符数组,因为当我将不是变量的字符串直接传递给代码时,它工作得很好。
有没有什么方法可以只使用SDL_ttf的成员函数在屏幕上显示动态文本?如果没有,我如何创建一个动态的文本类,使用SDL渲染等.?
1条答案
按热度按时间egdjgwm81#
TTF_RenderText_Solid()
将const char *
作为第二个参数,而不是std::string
或float
:从
std::string
中抓取一个C字符串,std::to_string()
通过std::string::c_str()
返回,并使用它: