渲染器如何传递给 类 的其余部分?
How did a Renderer pass to the rest of the classes?
我有一个游戏 class,它通过其构造函数初始化 window 和 SDL 渲染器。我从目前阅读的内容(不多)了解到每个 window.
应该只有一个渲染器
然后我有一个播放器class,我想通过构造函数加载带有图像的纹理,为此我需要渲染器,因此,我将渲染器作为构造函数参数并以这种方式我被迫从 Game 的构造函数将渲染器传递给 Player 构造函数(因为它在 The Game class 中实例化了 Player class)。
事实是渲染器在创建之前就被传递了,我不知道是否有另一种方法可以从游戏中调用播放器的构造函数,因为它迫使我那样说。我留下代码给你看:
游戏class:
#pragma once
#include <iostream>
#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>
#include "player.hpp"
//#include "helpers.hpp"
using namespace std;
#define WINDOW_WIDHT 640
#define WINDOW_HEIGTH 480
class Game
{
public:
Game();
~Game();
void loop();
void update() {}
void input();
void render();
void draw() {}
private:
SDL_Window *window;
SDL_Renderer *renderer = nullptr;
SDL_Event event;
SDL_Texture *gTexture;
bool running;
Player player;
};
Game::Game() : player(renderer)
{
SDL_Init(0);
SDL_CreateWindowAndRenderer(WINDOW_WIDHT, WINDOW_HEIGTH, 0, &window, &renderer);
SDL_SetWindowTitle(window, "Intento...");
//inicializa la carga de pngs
int imgFlags = IMG_INIT_PNG;
if (!IMG_Init(imgFlags) & imgFlags)
{
cout << "No se puede inicializar SDL_Img" << endl;
}
running = true;
loop();
}
Game::~Game()
{
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(window);
IMG_Quit();
SDL_Quit();
}
void Game::loop()
{
while (running)
{
input();
render();
update();
}
}
void Game::render()
{
SDL_SetRenderDrawColor(renderer, 255, 0, 0, 255);
SDL_Rect rect;
rect.x = rect.y = 0;
rect.w = WINDOW_WIDHT;
rect.h = WINDOW_HEIGTH;
SDL_RenderFillRect(renderer, &rect);
SDL_RenderPresent(renderer);
}
void Game::input()
{
while (SDL_PollEvent(&event) > 0)
{
switch (event.type)
{
case SDL_QUIT:
running = false;
break;
}
}
}
Clase 玩家:
#pragma once
#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>
#include <iostream>
//#include "helpers.hpp"
using namespace std;
class Player
{
public:
Player(SDL_Renderer *renderer);
~Player() = default;
const SDL_Rect getDest() { return dest; }
const SDL_Rect getSrc() { return src; }
void setDest(int x, int y, int w, int h);
void setSrc(int x, int y, int w, int h);
SDL_Texture *loadTexture(std::string path, SDL_Renderer *renderer);
private:
SDL_Rect dest;
SDL_Rect src;
};
Player::Player(SDL_Renderer *renderer){
loadTexture("mario.png", renderer);
/* setSrc(48, 48, 48, 48);
setDest(100, 100, 48, 48);
SDL_Rect playerRectSrc = getSrc();
SDL_Rect playerRectDest = getDest(); */
}
void Player::setDest(int x, int y, int w, int h){
dest.x = x;
dest.y = y;
dest.w = w;
dest.h = h;
}
void Player::setSrc(int x, int y, int w, int h){
src.x = x;
src.y = y;
src.w = w;
src.h = h;
}
SDL_Texture* Player::loadTexture(std::string path, SDL_Renderer *renderer)
{
SDL_Texture *newTexture = NULL;
SDL_Surface *loadedSurface = IMG_Load(path.c_str());
if (loadedSurface == NULL)
{
cout << "No se pudo cargar la imagen" << endl;
}
else
{
newTexture = SDL_CreateTextureFromSurface(renderer, loadedSurface);
if (newTexture == NULL)
{
cout << "No se pudo generar la textura para player" << endl;
}
SDL_FreeSurface(loadedSurface);
}
return newTexture;
}
问题是创建渲染器后如何调用Player构造函数?我唯一能想到的不是通过构造函数创建纹理,而是通过函数创建纹理,但这不是正确的做法,对吧?这就是构造函数的用途
The only thing I can think of is not to create the texture through the constructor, but through a function, but it wouldn't be the right thing to do, right? that's what the constructor is for
没错。但是,SDL 是一个 C 库,因此它不使用负责 construction/destruction 的 C++ RAII。首先,我们在成员初始化列表 (: foo{}, bar{foo}
) 中调用构造函数,它为我们提供了完全构造的成员对象。然后,我们在构造函数体中做任何我们想做的事({ use(foo); }
)。但是,在您的情况下,在成员初始化 (: player{renderer}
).
之前需要构造函数主体 ({ SDL_CreateWindowAndRenderer(...); }
)
The question is how to call the Player constructor after the renderer has been created?
在构造 Player
:
之前构造 所有 SDL_
东西
class RenderWindow {
SDL_Window* window;
SDL_Renderer* renderer;
public:
RenderWindow() {
SDL_Init(0);
SDL_CreateWindowAndRenderer(WINDOW_WIDHT, WINDOW_HEIGTH, 0, &window, &renderer);
SDL_SetWindowTitle(window, "Intento...");
}
// an easy double-free protection, you can use anything else
RenderWindow(RenderWindow&&) = delete;
~RenderWindow() {
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(window);
SDL_Quit();
}
// lvalue-only to forbid dangling like RenderWindow{}.raw_renderer()
auto raw_renderer() & { return renderer; }
};
现在,您的 Player
和 Game
可以以自然的 RAII 构造然后使用的方式实现:
class Player {
public:
Player(SDL_Renderer*); // TODO implement
};
class Game {
// note the declaration order: construction goes from top to bottom
RenderWindow render_window;
Player player;
public:
// SDL_* happens in render_window{},
// so player{render_window.raw_renderer()} gets an initialized SDL_Renderer
Game(): /*render_window{},*/ player{render_window.raw_renderer()} {}
};
我有一个游戏 class,它通过其构造函数初始化 window 和 SDL 渲染器。我从目前阅读的内容(不多)了解到每个 window.
应该只有一个渲染器然后我有一个播放器class,我想通过构造函数加载带有图像的纹理,为此我需要渲染器,因此,我将渲染器作为构造函数参数并以这种方式我被迫从 Game 的构造函数将渲染器传递给 Player 构造函数(因为它在 The Game class 中实例化了 Player class)。
事实是渲染器在创建之前就被传递了,我不知道是否有另一种方法可以从游戏中调用播放器的构造函数,因为它迫使我那样说。我留下代码给你看:
游戏class:
#pragma once
#include <iostream>
#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>
#include "player.hpp"
//#include "helpers.hpp"
using namespace std;
#define WINDOW_WIDHT 640
#define WINDOW_HEIGTH 480
class Game
{
public:
Game();
~Game();
void loop();
void update() {}
void input();
void render();
void draw() {}
private:
SDL_Window *window;
SDL_Renderer *renderer = nullptr;
SDL_Event event;
SDL_Texture *gTexture;
bool running;
Player player;
};
Game::Game() : player(renderer)
{
SDL_Init(0);
SDL_CreateWindowAndRenderer(WINDOW_WIDHT, WINDOW_HEIGTH, 0, &window, &renderer);
SDL_SetWindowTitle(window, "Intento...");
//inicializa la carga de pngs
int imgFlags = IMG_INIT_PNG;
if (!IMG_Init(imgFlags) & imgFlags)
{
cout << "No se puede inicializar SDL_Img" << endl;
}
running = true;
loop();
}
Game::~Game()
{
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(window);
IMG_Quit();
SDL_Quit();
}
void Game::loop()
{
while (running)
{
input();
render();
update();
}
}
void Game::render()
{
SDL_SetRenderDrawColor(renderer, 255, 0, 0, 255);
SDL_Rect rect;
rect.x = rect.y = 0;
rect.w = WINDOW_WIDHT;
rect.h = WINDOW_HEIGTH;
SDL_RenderFillRect(renderer, &rect);
SDL_RenderPresent(renderer);
}
void Game::input()
{
while (SDL_PollEvent(&event) > 0)
{
switch (event.type)
{
case SDL_QUIT:
running = false;
break;
}
}
}
Clase 玩家:
#pragma once
#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>
#include <iostream>
//#include "helpers.hpp"
using namespace std;
class Player
{
public:
Player(SDL_Renderer *renderer);
~Player() = default;
const SDL_Rect getDest() { return dest; }
const SDL_Rect getSrc() { return src; }
void setDest(int x, int y, int w, int h);
void setSrc(int x, int y, int w, int h);
SDL_Texture *loadTexture(std::string path, SDL_Renderer *renderer);
private:
SDL_Rect dest;
SDL_Rect src;
};
Player::Player(SDL_Renderer *renderer){
loadTexture("mario.png", renderer);
/* setSrc(48, 48, 48, 48);
setDest(100, 100, 48, 48);
SDL_Rect playerRectSrc = getSrc();
SDL_Rect playerRectDest = getDest(); */
}
void Player::setDest(int x, int y, int w, int h){
dest.x = x;
dest.y = y;
dest.w = w;
dest.h = h;
}
void Player::setSrc(int x, int y, int w, int h){
src.x = x;
src.y = y;
src.w = w;
src.h = h;
}
SDL_Texture* Player::loadTexture(std::string path, SDL_Renderer *renderer)
{
SDL_Texture *newTexture = NULL;
SDL_Surface *loadedSurface = IMG_Load(path.c_str());
if (loadedSurface == NULL)
{
cout << "No se pudo cargar la imagen" << endl;
}
else
{
newTexture = SDL_CreateTextureFromSurface(renderer, loadedSurface);
if (newTexture == NULL)
{
cout << "No se pudo generar la textura para player" << endl;
}
SDL_FreeSurface(loadedSurface);
}
return newTexture;
}
问题是创建渲染器后如何调用Player构造函数?我唯一能想到的不是通过构造函数创建纹理,而是通过函数创建纹理,但这不是正确的做法,对吧?这就是构造函数的用途
The only thing I can think of is not to create the texture through the constructor, but through a function, but it wouldn't be the right thing to do, right? that's what the constructor is for
没错。但是,SDL 是一个 C 库,因此它不使用负责 construction/destruction 的 C++ RAII。首先,我们在成员初始化列表 (: foo{}, bar{foo}
) 中调用构造函数,它为我们提供了完全构造的成员对象。然后,我们在构造函数体中做任何我们想做的事({ use(foo); }
)。但是,在您的情况下,在成员初始化 (: player{renderer}
).
{ SDL_CreateWindowAndRenderer(...); }
)
The question is how to call the Player constructor after the renderer has been created?
在构造 Player
:
SDL_
东西
class RenderWindow {
SDL_Window* window;
SDL_Renderer* renderer;
public:
RenderWindow() {
SDL_Init(0);
SDL_CreateWindowAndRenderer(WINDOW_WIDHT, WINDOW_HEIGTH, 0, &window, &renderer);
SDL_SetWindowTitle(window, "Intento...");
}
// an easy double-free protection, you can use anything else
RenderWindow(RenderWindow&&) = delete;
~RenderWindow() {
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(window);
SDL_Quit();
}
// lvalue-only to forbid dangling like RenderWindow{}.raw_renderer()
auto raw_renderer() & { return renderer; }
};
现在,您的 Player
和 Game
可以以自然的 RAII 构造然后使用的方式实现:
class Player {
public:
Player(SDL_Renderer*); // TODO implement
};
class Game {
// note the declaration order: construction goes from top to bottom
RenderWindow render_window;
Player player;
public:
// SDL_* happens in render_window{},
// so player{render_window.raw_renderer()} gets an initialized SDL_Renderer
Game(): /*render_window{},*/ player{render_window.raw_renderer()} {}
};