【发布时间】:2014-10-06 08:38:17
【问题描述】:
我目前正在为我自己的个人视频游戏项目开发一个内部 GUI,目前我已经完成了基本框架的创建。它由以下类组成:
- GUI_Engine
- GUI_Element
- GUI_Panel
- GUI_Window
GUI_Element 是我将使用我的框架创建的所有 GUI 类的抽象基类,它的子类是 GUI_Panel。 GUI_Panel 的孩子是 GUI_Window。
GUI_Engine 存储指向 GUI_Element 的指针并加载各种 PNG 文件以供所有 GUI_Element 使用。这些 PNG 文件存储在 SpritePool 中,这是一个简单的双向量,存储 SDL_Texture 和 std::string。字符串是 PNG 文件名。
我目前有两个 PNG 文件无法使用 void GUI_Window::render() 函数中的以下代码正确渲染,“window_top”和“window_bottom”。这些 16x16 文件是用于渲染窗口顶部和底部边框的图块;然而,它们是仅有的两个未正确渲染的纹理。
这是 GUI_Element 的代码:
/*
Class: GUI_Element
Purpose: -To provide an ABSTRACT base class for all the GUI elements within the framework.
Notes: >The class already holds basic functions for hot, cold, select, and deslect.
Function pointers are going to use to provide callback/like functionality.
*/
#ifndef GUI_ELEMENT_H
#define GUI_ELEMENT_H
#include "globalvar.h"
#include "Input.h"
#include "SpritePool.h"
class GUI_Element
{
public:
GUI_Element() {}
GUI_Element(SpritePool gui_skin, int x, int y, int w, int h, bool visible, GUI_Element* parent);
virtual ~GUI_Element();
//set functions
void set_texture_ptr(SDL_Texture** texture) {texture_ptr = texture;}
void set_parent_element(GUI_Element* parent);
void set_frame(int x, int y, int w, int h);
void set_offset_x(int i) {offset_x = i;}
void set_offset_y(int i) {offset_y = i;}
void set_x(int i) {frame.x = i;}
void set_y(int i) {frame.y = i;}
void set_w(int i) {frame.w = i;}
void set_h(int i) {frame.h = i;}
void set_visible(bool b);
void set_hot(bool b);
void set_selected(bool b);
//get functions
SDL_Texture** get_texture_ptr() {return texture_ptr;}
GUI_Element* get_parent_element() {return parent_element;}
SDL_Rect* get_frame() {return &frame;}
int get_offset_x() {return offset_x;}
int get_offset_y() {return offset_y;}
int get_x() {return frame.x;}
int get_y() {return frame.y;}
int get_w() {return frame.w;}
int get_h() {return frame.h;}
//is_property functions
bool is_visible() {return visible;}
bool is_hot() {return hot;}
bool is_selected() {return selected;}
//on_action functions
virtual void on_hot() = 0;
virtual void on_cold() = 0;
virtual void on_select() = 0;
virtual void on_deselect() = 0;
//render/update/check input functions
virtual void render() = 0;
virtual void update() = 0;
virtual void check(Input &input) = 0;
protected:
int offset_x, offset_y;
SDL_Texture** texture_ptr;
GUI_Element* parent_element;
SDL_Rect frame;
bool visible;
bool hot;
bool selected;
void (*func_hot) ();
void (*func_select) ();
void (*func_cold) ();
void (*func_deselect) ();
private:
};
这是 GUI_Window 的代码:
#ifndef GUI_WINDOW_H
#define GUI_WINDOW_H
#include "GUI_Panel.h"
class GUI_Window : public GUI_Panel
{
public:
GUI_Window(SpritePool gui_skin, int x, int y, int w, int h, bool visible, std::string str);
virtual ~GUI_Window();
void set_name(std::string str) {name = str;}
void set_menubar_properties(bool minimize, bool pin, bool exit);
void set_border_visible(bool b);
void set_bg_visible(bool b);
std::string get_name() {return name;}
bool get_minimize_visible() {return minimize_visible;}
bool get_pin_visible() {return pin_visible;}
bool get_exit_visible() {return exit_visible;}
bool get_border_visible() {return border_visible;}
bool get_bg_visible() {return bg_visible;}
virtual void on_hot();
virtual void on_cold();
virtual void on_select();
virtual void on_deselect();
//render/update/check input functions
virtual void render();
virtual void update();
virtual void check(Input &input);
protected:
std::string name;
bool minimize_visible;
bool pin_visible;
bool exit_visible;
bool border_visible;
bool bg_visible;
SDL_Rect tile_frame;
SDL_Texture** window_top;
SDL_Texture** window_bottom;
SDL_Texture** window_left;
SDL_Texture** window_right;
SDL_Texture** window_topleft;
SDL_Texture** window_topright;
SDL_Texture** window_bottomleft;
SDL_Texture** window_bottomright;
SDL_Texture** window_minimize;
SDL_Texture** window_pin;
SDL_Texture** window_exit;
SDL_Texture** gui_bg;
private:
};
#endif // GUI_WINDOW_H
这是 GUI_Window::render() 的代码:
void GUI_Window::render()
{
if (visible)
{
if (bg_visible)
{
SDL_RenderCopy(g_renderer, *gui_bg, NULL, &frame);
}
if (border_visible)
{
tile_frame.x = frame.x;
tile_frame.y = frame.y;
tile_frame.w = 16;
tile_frame.h = 16;
SDL_RenderCopy(g_renderer, *window_topleft, NULL, &tile_frame);
tile_frame.y = frame.y;
while (tile_frame.x < (frame.x + frame.w - 32))
{
SDL_RenderCopy(g_renderer, *window_top, NULL, &tile_frame);
tile_frame.x += 16;
}
tile_frame.x += 16;
SDL_RenderCopy(g_renderer, *window_topright, NULL, &tile_frame);
if (window_top == NULL)
std::cout << "oh well" << std::endl;
while (tile_frame.y < (frame.y + frame.h - 16))
{
tile_frame.y += 16;
SDL_RenderCopy(g_renderer, *window_right, NULL, &tile_frame);
}
SDL_RenderCopy(g_renderer, *window_bottomright, NULL, &tile_frame);
while (tile_frame.x > frame.x + 16)
{
tile_frame.x -= 16;
SDL_RenderCopy(g_renderer, *window_bottom, NULL, &tile_frame);
}
tile_frame.x -= 16;
SDL_RenderCopy(g_renderer, *window_bottomleft, NULL, &tile_frame);
while (tile_frame.y > frame.y + 16)
{
tile_frame.y -= 16;
SDL_RenderCopy(g_renderer, *window_left, NULL, &tile_frame);
}
}
if (exit_visible)
{
tile_frame.x = frame.x + frame.w - 16;
tile_frame.y = frame.y;
SDL_RenderCopy(g_renderer, *window_exit, NULL, &tile_frame);
}
if (pin_visible)
{
tile_frame.x = frame.x + frame.w - 32;
tile_frame.y = frame.y;
SDL_RenderCopy(g_renderer, *window_pin, NULL, &tile_frame);
}
if (minimize_visible)
{
tile_frame.x = frame.x + frame.w - 48;
tile_frame.y = frame.y;
SDL_RenderCopy(g_renderer, *window_minimize, NULL, &tile_frame);
}
}
}
我已经检查了以下内容:
- GUI_Engine 正确加载所有 PNG 文件。没有 SDL_Texture* 为 NULL;
- GUI_Window 应该正确地将所有 SDL_Texture* 加载到 SDL_Texture** 中。这些指针都不是 NULL。
- GUI_Window::render() 中的循环逻辑运行正常。
- 奇怪的是,如果将 SDL_Texture** 更改为 window_top 和 window_bottom 以外的其他内容,则会呈现顶部和底部栏。
注意:
SDL_Texture** 名称与 PNG 文件完全相同。
它是这样的:
编辑:这是我的 SpritePool 类中的纹理加载代码:
void SpritePool::load_texture(std::string path)
{
SDL_Texture* loaded_texture = NULL;
SDL_Surface* loaded_surface = NULL;
loaded_surface = IMG_Load(path.c_str());
if (loaded_surface == NULL)
std::cout << path << " unable to be loaded!" << std::endl;
else
{
loaded_texture = SDL_CreateTextureFromSurface(g_renderer, loaded_surface);
if (loaded_texture == NULL)
std::cout << path << " unable to be converted to SDL_Texture*!" << std::endl;
else
std::cout << path << " loaded!" << std::endl;
}
SDL_FreeSurface(loaded_surface);
texture_pool.push_back(loaded_texture);
texture_names.push_back(path);
}
有人请帮帮我!
【问题讨论】:
-
听起来这两个纹理/PNG 有问题。 1. 尝试在其他地方渲染纹理一次(比如在 window_top_left 的位置。2. 检查 PNG 是否正确。alpha 有什么奇怪的地方吗? 3. 尝试将您知道的另一个 PNG 复制到 window_top 的 PNG 中和 window_bottom。
-
是的,实际上,我已经完成了所有这三个操作。似乎问题出在 指针 上,因为如果我将它们加载为 SDL_Texture* 而不是 SDL_Texture**,文件呈现正常。诡异的。但为什么呢?
-
好的,所以我刚刚添加了纹理加载代码。不过,它确实有效。
-
你为什么要使用 SDL_Texture**?为什么需要指向指针的指针?为什么不简单地传递一个简单的指针?现在这纯粹是猜测,因为我看不到您调用
set_texture_pointer的代码:如果您通过执行ptr = &texture_pool[i]之类的操作获得SDL_Texture**,然后您继续向texture_pool添加其他纹理(我假设是一个向量),当texture_pool在内部调整大小时,指针可能会四处移动并且您的 SDL_Texture** 不再有效。 -
@Cinch:
SDL_Texture是对象,SDL 正在向您返回指向该对象的指针。无需存储指向此指针的指针。 SDL 在内部存储对象并为您提供指向它们的指针。或许可以查看关于 c 指针的教程:tutorialspoint.com/cprogramming/c_pointers.htm。它们有时会很棘手。
标签: c++ graphics png sdl sdl-2