Hello guys. I want to integrate depth with my textures. My idea is to have a global vector that will contain all the textures I wanna render, and depending on how large or small the depth is associated with each texture, it will render it lastly / firstly to convey a depth in my 2D game. I’m using C++ if it matters, but I’ve developed code and I can’t comprehend why it’s not working. Would anyone be willing to take a glance at my code?
Also, yes it is incredibly messy and inconsistent, but I plan to fix that soon.
#ifndef TEXTURE
#define TEXTURE
//libraries to include
#include <SDL.h>
#include <SDL_image.h>
#include
#include
#include
#include
/*
You have to make a texture an object if you want to move a texture across the screen and stuff.
The functions in this texture class is basically what you’re gonna get without making it an object (of the object class)
*/
class texture {
private:
//textures counter
static int texturesExist;
//the texture
SDL_Texture* textureImage;
//texture dimensions
int w;
int h;
//texture coordinates
int x;
int y;
//texture depth and alpha
int depth; //bigger number is closer / rendered last while lower number rendered first.
Uint8 alpha; //from 0-255. We use Uint8 because since the integer is set to only be 8 bits, it can only go from 0 to 255, which is prefect in this case.
//animation stuff
bool isAnimated = false; //image by default is not animated
int numberOfFrames = 0;
int animationSpeed = 100; //milliseconds
public:
//default constructor
texture();
//default constructor
texture(int tempDepth, int tempAlpha);
//argument constructor for animations
texture(int tempNumberOfFrames, int tempAnimationSpeed, int tempDepth, int tempAlpha);
//loads image at specified path
bool loadFromFile(std::string path);
//deallocates texture
void free();
//adds the sprite to the vector to render
void displaySprite(int tempX, int tempY);
//Renders texture at given coordinates
void displaySpriteInTextureDepth(int tempX, int tempY);
//Getter Functions
int getW() { return w; }
int getH() { return h; }
int getX() { return x; }
int getY() { return y; }
int getDepth() { return depth; }
int getAlpha() { return alpha; }
SDL_Texture* getSprite() { return textureImage; }
//Setter Functions
void setW(int temp) { w = temp; }
void setH(int temp) { h = temp; }
void setX(int temp) { x = temp; }
void setY(int temp) { y = temp; }
void setDepth(int temp) { depth = temp; }
bool setAlpha(Uint8 temp);// { alpha = temp; }
void setTexture(std::string path) { free(); loadFromFile(path); }
void setSprite(SDL_Texture* temp) { textureImage = temp; }
//Tile the Sprite
void tileSprite(int tempW, int tempH);
//Stretch the sprite
void stretchSprite(int stretchW, int stretchH);
//deconstructor
~texture();
//// Add a static vector to store textures
//static std::vector<texture> textureDepth;
//
//
//// Define a custom comparison function for sorting by order
//static bool CompareOrderByDepth(texture& a, texture& b) {
// return a.depth < b.depth;
//}
//
//// Static function to render all textures in the correct order
//static void RenderTextures() {
// // Sort textures by order
// //std::sort(textureDepth.begin(), textureDepth.end(), CompareOrderByDepth);
//
// //// Render the textures in the correct order
// //for (texture& tex : textureDepth) {
// // tex.putTextureIn_textureDepth(tex.getX(), tex.getY());
// //}
//
// if (textureDepth.empty()) {
//
// std::cout << "textureDepth IS empty\n";
//
// }
// else {
//
// std::cout << "textureDepth is NOT empty\n";
//
// }
//
// // Render the textures in the correct order
// for (int i = 0; i < textureDepth.size(); i++) {
// textureDepth[i].putTextureIn_textureDepth(textureDepth[i].getX(), textureDepth[i].getY());
// std::cout << "textureDepth[" << i << "] x value: " << textureDepth[i].getX() << "\n";
// std::cout << "textureDepth[" << i << "] y value: " << textureDepth[i].getY() << "\n";
//
// }
//
// //debug
// for (int i = 0; i < textureDepth.size(); i++) {
// std::cout << textureDepth[i].getSprite() << "\n";
// }
//
//}
};
// Add a static vector to store textures
std::vector textureDepth;
void texture::displaySprite(int tempX, int tempY) {
x = tempX;
y = tempY;
// Add the created texture to the static vector
textureDepth.push_back(*this);
}
// Define a custom comparison function for sorting by order
bool compareDepths(texture& a, texture& b) {
return a.getDepth() < b.getDepth();
}
// Static function to render all textures in the correct order
void RenderTextures() {
// Sort textures by order
std::sort(textureDepth.begin(), textureDepth.end(), compareDepths);
//debug
if (textureDepth.empty()) {
std::cout << "textureDepth IS empty\n";
}
else {
std::cout << "textureDepth is NOT empty\n";
}
// Render the textures in the correct order
for (int i = 0; i < textureDepth.size(); i++) {
textureDepth[i].displaySpriteInTextureDepth(textureDepth[i].getX(), textureDepth[i].getY());
std::cout << "textureDepth[" << i << "] x value: " << textureDepth[i].getX() << "\n";
std::cout << "textureDepth[" << i << "] y value: " << textureDepth[i].getY() << "\n";
}
//debug
for (int i = 0; i < textureDepth.size(); i++) {
std::cout << textureDepth[i].getSprite() << "\n";
}
}
//texturesCounter
int texture::texturesExist = 0;
//default constructor
texture::texture() {
/*
The texture is only animated if you use the argument constructor.
So, maybe make another function to load an animation?
*/
textureImage = NULL;
w = 0;
h = 0;
x = 0;
y = 0;
depth = 0;
alpha = 255;
// Add the created texture to the static vector
//textureDepth.push_back(*this);
//textures counter
texturesExist++;
}
//argument constructor
texture::texture(int tempDepth, int tempAlpha) {
/*
Assumes is the constructor has arguments, it's an animation.
If it's not an animation (just a still image), there's no reason
it should have any arguments.
*/
textureImage = NULL;
w = 0;
h = 0;
x = 0;
y = 0;
depth = tempDepth;
alpha = tempAlpha;
//animation stuff
isAnimated = false; //image by default is not animated
numberOfFrames = 0;
animationSpeed = 100; //milliseconds
// Add the created texture to the static vector
//textureDepth.push_back(*this);
//textures counter
texturesExist++;
}
//argument constructor for animation
texture::texture(int tempNumberOfFrames, int tempAnimationSpeed, int tempDepth, int tempAlpha) {
/*
Assumes is the constructor has arguments, it's an animation.
If it's not an animation (just a still image), there's no reason
it should have any arguments.
*/
textureImage = NULL;
w = 0;
h = 0;
x = 0;
y = 0;
depth = tempDepth;
alpha = tempAlpha;
//Animation Stuff
isAnimated = true;
numberOfFrames = tempNumberOfFrames;
animationSpeed = tempAnimationSpeed;
// Add the created texture to the static vector
textureDepth.push_back(*this);
//textures counter
texturesExist++;
}
//set alpha
bool texture::setAlpha(Uint8 temp) {
//temp can be from 0-255, 255 being solid and 0 being completely transparent.
if ((alpha >= 0) && (alpha <= 255)) {
alpha = temp;
SDL_SetTextureAlphaMod(textureImage, alpha);
return true;
}
return false;
}
//loads image at specified path
bool texture::loadFromFile(std::string path) {
//freeing any images if they were already loaded
free();
//The final texture
SDL_Texture* newTexture = NULL;
//Load image at specified path
SDL_Surface* loadedSurface = IMG_Load(path.c_str());
if (loadedSurface == NULL)
{
printf("Unable to load image %s! SDL_image Error: %s\n", path.c_str(), IMG_GetError());
}
else
{
//Color key image
SDL_SetColorKey(loadedSurface, SDL_TRUE, SDL_MapRGB(loadedSurface->format, 0, 0xFF, 0xFF));
//Create texture from surface pixels
newTexture = SDL_CreateTextureFromSurface(renderer, loadedSurface);
if (newTexture == NULL)
{
printf("Unable to create texture from %s! SDL Error: %s\n", path.c_str(), SDL_GetError());
}
else
{
//Get image dimensions
w = loadedSurface->w;
h = loadedSurface->h;
}
//Get rid of old loaded surface
SDL_FreeSurface(loadedSurface);
}
//Return success
textureImage = newTexture;
return textureImage != NULL;
}
//deallocates texture
void texture::free() {
if (textureImage != NULL) {
SDL_DestroyTexture(textureImage);
textureImage = NULL;
w = 0;
h = 0;
x = 0;
y = 0;
}
}
void texture::displaySpriteInTextureDepth(int tempX, int tempY) {
/*
Maybe in the future, you can mofidy this function so animations also
work with sprite sheets containing other sprites. As of now, animations
must be their own sprite sheets.
*/
x = tempX;
y = tempY;
// If the sprite is animated
if (isAnimated) {
static int currentFrame = 0;
static Uint32 lastFrameTime = SDL_GetTicks();
Uint32 currentTime = SDL_GetTicks();
// Calculate the time elapsed since the last frame change
Uint32 elapsedTime = currentTime - lastFrameTime;
// Check if it's time to advance to the next frame
if (elapsedTime >= animationSpeed) {
currentFrame++;
if (currentFrame >= numberOfFrames) {
currentFrame = 0; // Loop back to the first frame
}
lastFrameTime = currentTime;
}
// Calculate the frame width from w (width of entire sprite)
int frameWidth = w / numberOfFrames;
// Calculate the source rect for the current frame
SDL_Rect srcRect = { currentFrame * frameWidth, 0, frameWidth, h };
// Set rendering space and render to the screen
SDL_Rect renderTexture = { x, y, frameWidth, h };
SDL_RenderCopy(renderer, textureImage, &srcRect, &renderTexture);
}
else {
// Not animated, render the whole texture
SDL_Rect renderTexture = { x, y, w, h };
SDL_RenderCopy(renderer, textureImage, NULL, &renderTexture);
}
}
//Tile the Sprite
void texture::tileSprite(int tempW, int tempH) {
//assumes you want to do it from top left. We can fix this.
int xCoordCounter = 0;
int yCoordCounter = 0;
for (int i = 0; i < tempH; i++) {
for (int j = 0; j < tempW; j++) {
displaySprite(xCoordCounter, yCoordCounter);
//add to x coordinate
//if animation
if (isAnimated) {
xCoordCounter += (w / numberOfFrames);
}
else {
xCoordCounter += w;
}
}
//reset x and add to y coordinates
xCoordCounter = 0;
yCoordCounter += h;
}
}
//Stretch the sprite
void texture::stretchSprite(int stretchW, int stretchH) {
//void objTexture::stretchSprite(int tempX, int tempY, float stretchW, float stretchH) {
//set rendering space and render to the screen
//SDL_Rect renderTexture = { tempX, tempY, (w * stretchW), (h * stretchH) };
//SDL_RenderCopy(renderer, textureImage, NULL, &renderTexture);
/*
Make it so the parameters are the width and height you want to
scale it to and the time it will take to do so. Make it like the
move object function where it will over time increase in size, or
if you put 0, immediately.
*/
w *= stretchW;
h *= stretchH;
//the only problem with this is doing anything below 0 doesn't invert it. It just doesn't show.
}
//deconstructor
texture::~texture() {
free();
//textures counter
texturesExist--;
}
#endif