I'm trying to build a gamengine, and I need to sort characters and rooftiles based on the y-coordinate of their feet before drawing them, so that folk/tiles infront are drawn ontop of folk/tiles behind them. I've gotten it to work with just characters, but I need rooftiles as well.
the classes are both children of renderable, and share some data. The classes are forward-declared, and there are global lists g_entities, g_tiles, and g_renderable.
class renderable {
public:
float x;
float y;
float width;
float height;
SDL_Surface* image;
SDL_Texture* texture;
void render(SDL_Renderer * renderer, camera fcamera) {
rect obj(floor((x -fcamera.x)* fcamera.zoom), floor((y-fcamera.y)* fcamera.zoom), floor(width *fcamera.zoom), floor(height * fcamera.zoom));
rect cam(0, 0, fcamera.width, fcamera.height);
if(RectOverlap(obj, cam)) {
SDL_Rect dstrect = { (x -fcamera.x)* fcamera.zoom, (y-fcamera.y)* fcamera.zoom, width *fcamera.zoom, height * fcamera.zoom};
SDL_RenderCopy(renderer, texture, NULL, &dstrect);
}
}
};
class entity: public renderable {
public:
float x;
float y;
float xagil;
float yagil;
//... other stuff, including image and texture
void render(SDL_Renderer * renderer, camera fcamera);
};
class tile: public renderable {
public:
int x;
int y;
int z = 0; //represents layer. 0 default
float width;
float height;
//... other stuff, including image and texture
void render(SDL_Renderer * renderer, camera fcamera);
};
The list is created when the map is loaded with
for (int i = 0; i < g_entities.size(); i++) {
g_renderable.push_back(g_entities[i]);
}
for (int i = 0; i < g_tiles.size(); i++) {
if(g_tiles[i]->z ==2) {
g_renderable.push_back(g_tiles[i]);
g_tiles.erase(g_tiles.begin() + i);
i--;
}
}
And then in main I planned to sort the g_renderable array instead of the g_entities array and have everything snug, but instead I get a SIGFAULT. I tracked down the problem with GDB and it turns out that g_renderable[] isnt getting informed with the attributes of g_entities[] (and probly not g_tiles[] either).
This is what I mean:
g_renderable.clear();
g_renderable.reserve(g_entities.size() + g_tiles.size()); // preallocate memory
cout << "g_entities.size" <<g_entities.size() << endl;
cout << "g_entities.size" <<g_entities.size() << endl;
cout << "g_entities height " << g_entities[0]->height << endl; //couts 122
for (int i = 0; i < g_entities.size(); i++) {
g_renderable.push_back(g_entities[i]);
}
cout << "g_renderable height " << g_renderable[0]->height << endl; //couts 0
for (int i = 0; i < g_tiles.size(); i++) {
if(g_tiles[i]->z ==2) {
g_renderable.push_back(g_tiles[i]);
g_tiles.erase(g_tiles.begin() + i);
i--;
}
}
Why doesnt my vector return the member data as expected?
Related
I want to make a tilemap but when I run this code, the tiles becomes white, the texture has a problem. I know it that from the sf::Texture reference here says that the texture must exist in order to that the sprite can use it. But I dont know how to make it possible.
Here's the code:
class Tile
{
private:
sf::Sprite sprite;
sf::Texture tex;
public:
Tile(int x, int y, sf::Texture tex)
{
this->tex = tex;
this->sprite.setTexture(this->tex);
this->sprite.setPosition(x, y);
}
void render(sf::RenderWindow* target)
{
target->draw(this->sprite);
}
class Tilemap
{
private:
Tile tiles[36][64];
sf::Texture tex[4];
public:
//const/dest
Tilemap()
{
this->tex[0].loadFromFile("Resources/Tilemap/Water/water1.png");
int x = -WIDTH+WIDTH/2;
int y = -HEIGTH/2;
for (int i = 0; i < 36; i++)
{
for (int j = 0; j < 64; j++)
{
this->tiles[i][j] = Tile(x, y, this->tex[0]);
x += 60;
}
y += 60;
x = -WIDTH + WIDTH / 2;
}
}
render(sf::RenderWindow* target, sf::Vector2f pos)
{
for (int i = 0; i < 34; i++)
{
for (int j = 0; j < 64; j++)
{
this->tiles[i][j].render(target);
}
}
};
Tilemap map;
map = Tilemap();
Thank you in advance for any answers :)
I have already solved it by myself. Every tile has one sf::Texture tex and every time I need to change it I just load it again from different file.
I'm trying to code a function that, given an index as the input argument, extract the corresponding layer from a 3D matrix, returning a 2D matrix.
My default 3D matrix constructor looks something like this:
Matrice3D(unsigned int depth, unsigned int height, unsigned int width, const T &value) : _3D_matrix(0), _height(0), _width(0), _depth(0) {
try {
_3D_matrix = new T[height * width * depth];
for (int z = 0; z < depth; z++) {
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
_3D_matrix[y * width * depth + x * depth + z] = value;
}
}
}
}
catch(...) {
delete[] _3D_matrix;
throw;
}
_height = height;
_width = width;
_depth = depth;
}
(the try/catch is still a wip, I know it's not a thing to do).
So far, I've coded this:
void slice(int index) {
try{
_2D_matrix = new T[_height * _width];
}catch(...){
delete[] _2D_matrix;
_height = 0;
_width = 0;
_depth = 0;
throw;
}
_depth = 1;
for (int k = 0; k< _depth; k++) {
for (int j = 0; j< _height; j++) {
for (int i = 0; i< _width; i++) {
_2D_matrix[j * _width + i] =
_3D_matrix[j * _width * _depth + i * _depth + index];
}
}
}
}
I guess the logic behind the assignment done with the nested for cycles is right, but I don't really know how to return the new matrix.
From the main, used to test the code, I'm calling
std::cout << "--------TEST SLICE------------" << std::endl;
Matrice3D<int> m1(3,3,3,17);
std::cout << "Setter su (0,0,2,99)" << std::endl;
m1(0,0,2,91); //setting a value
m1.slice(2);
std::cout << "Matrix obtained from slicing the layer 2: " <<std::endl;
std::cout << m1;
but I keep getting the first layer of the matrix, whatever index I choose for the input.
Create a new class Matrice2D and return that in slice().
The reason why your get total garbage in your code is that you destroy the _depth of the 3D matrix. It's not even the first layer but really just garbage.
The only time new and delete should appear is in classes named something_ptr. You don't need raw pointers here, and you should be returning a 2DMatrix from slice.
template <typename T>
class 2DMatrix;
template <typename T>
class 3DMatrix {
std::vector<T> data;
std::size_t height, width, depth;
public:
3DMatrix(std::size_t height, std::size_t width, std::size_t depth, T value = {})
: data(height * width * depth, value),
height(height),
width(width),
depth(depth)
{}
2DMatrix<T> slice(std::size_t index) {
2DMatrix<T> result(height, width);
for (std::size_t i = index; i < data.size(); i += depth) {
result.data[i / depth] = data[i];
}
return result;
}
// other members
}
template <typename T>
class 2DMatrix {
std::vector<T> data;
std::size_t height, width;
friend class 3DMatrix<T>;
public:
2DMatrix(std::size_t height, std::size_t width, T value = {})
: data(height * width, value),
height(height),
width(width)
{}
// other members
}
I got the following problem:
I'm somewhat new to C++, looked up how to make multidimensional arrays without predefinition of size, I found something and tried it. I got a Process returned 139 (0x8B) as an answer. I looked up everything I found about it but It didn't help me at all.
My system: Linux Mint 64 Bit, Editor: Code::Blocks and Clion
Project: https://github.com/blueburningcoder/AntWorld.git
essential code:
#include <SFML/Graphics.hpp>
#include <iostream>
#include <vector>
using namespace std;
using namespace sf;
/*
* Tile: the background is out of tiles
*
* setSize:
* #param x: X-location of the Tile later on
* #param y: Y-location of the Tile later on
* #param height2: the height of the tile
* #param width2: the width of the tile
* (the 2 is there since the scope resolution operator didn't work for some reason)
* setting the size, position and color of the rect
*
*
* drawTile:
* #param renderWindow: the window the rect is drawn in
* drawing the rect
*/
class Tile {
private:
int locX, locY, height, width;
//
RectangleShape rect;
public:
void setSize(int x, int y, int height2, int width2){
locX = x;
locY = y;
height = height2;
width = width2;
rect.setSize(Vector2f(height, width));
rect.setFillColor(Color::Blue);
rect.setPosition(Vector2f(locX, locY));
}
void drawTile(RenderWindow *renderWindow){
renderWindow->draw(rect);
}
};
/*
* Maze: including all the Tiles, used to manipulate only specific Tiles
* #param xSize: how many tiles are gonna be in x direction
* #param ySize: how many tiles are gonna be in y direction
*
* drawMaze:
* #param renderWindow: needed for the Tile.drawTile method to draw on
* drawing all Tiles in the MAP
*/
class Maze {
private:
int sizeX = -1, sizeY = -1;
vector<vector<Tile> > MAP;
public:
Maze(int xSize, int ySize){
sizeX = xSize;
sizeY = ySize;
for(int i = 0; i < xSize; i++){
for(int j = 0; j < ySize; j++){
Tile tile;
tile.setSize(i * 35, j * 35, 30, 30);
// tile might not have been initialized?
MAP[i][j] = tile;
}
}
}
void drawMaze(RenderWindow *renderWindow){
// TODO: draw Tiles!
for(int i = 0; i < sizeX; i++){
for(int j = 0; j < sizeY; j++){
MAP[i][j].drawTile(renderWindow);
}
}
}
};
int main()
{
// Create the main window
RenderWindow app(VideoMode(800, 600), "SFML window");
// Load a sprite to display
Texture texture;
cout << "there's no error yet..." << endl;
if (!texture.loadFromFile("cb.bmp")) {
cout << "failed to load!" << endl;
return EXIT_FAILURE;
}
Sprite sprite(texture);
cout << "creating the maze ..." << endl;
// Creating a 10 x 10 Maze
Maze maze(10, 10);
// Start the game loop
while (app.isOpen())
{
// Process events
sf::Event event;
while (app.pollEvent(event))
{
// Close window : exit
if (event.type == sf::Event::Closed)
app.close();
}
cout << "gonna draw it ..." << endl;
// Clear screen
app.clear();
// Draw the sprite
app.draw(sprite);
// drawing the Maze
maze.drawMaze(&app);
// Update the window
app.display();
}
return EXIT_SUCCESS;
}
correct answer below
You cannot insert into a std::vector just via indexing, you need to call the appropriate constructor which allocates a fixed amount of space.
std::vector<int> array(4);
// array[0 ... 3] are now accessible.
So your declaration should be like this :
MAP = std::vector<std::vector<Tile>>(xSize, std::vector<Tile>(ySize));
// now access MAP[i][j]
// It basically reads, MAP has xSize number of elements where each defaults to a std::vector<Tile>(ySize).
Here is an example.
#include <iostream>
#include "Shapes.h"
int main()
{
//variables
int height = 0;
int width = 0;
Rectangle rect = Rectangle();
Triangle tran = Triangle();
Square sqar = Square();
std::cout << "What is the width of the shape? ";
std::cin >> width;
std::cout << "What is the height of the shape?";
std::cin >> height;
rect.set_lengths(width, height);
std::cout << "If the shape is a triangle, the area is " << tran.area() << "." << std::endl;
std::cout << "If the shape is a rectangle, the area is " << rect.area() << "." << std::endl;
std::cout << "If the shape is a square, the area is " << sqar.areaByWidth() << " by the width value," << std::endl;
std::cout << "and " << sqar.areaByHeight() << " by the height value." << std::endl;
system("pause");
}
Header file:
//Our base class
class Shape
{
protected:
int width, height, shapes = 0;
public:
void set_lengths(int width, int height)
{
width = width; height = height;
}
};
//Rectangle is a shape
class Rectangle : public Shape
{
public:
Rectangle()
{
std::cout << "Created a rectangle!\n";
shapes = shapes + 1;
}
~Rectangle()
{
shapes = shapes - 1;
}
int area()
{
return width * height;
}
};
//Triangle is a shape
class Triangle : public Shape
{
public:
Triangle()
{
shapes = shapes + 1;
std::cout << "Created a triangle!\n";
}
~Triangle()
{
shapes = shapes - 1;
}
int area()
{
return width * height / 2;
}
};
//Square is a shape
class Square : public Shape
{
public:
Square()
{
shapes = shapes + 1;
std::cout << "Created a square!";
}
~Square()
{
shapes = shapes - 1;
}
int areaByWidth()
{
return width * width;
}
int areaByHeight()
{
return height * height;
}
};
When I set the values, it works fine (shows the correct value in visual studio debugger), but when I call area() it brings back -846388729 or something similiar? Why is the value being reset? I have been banging my head against a wall for hours on this. Seems like a common problem to noobies like myself but I'm not understanding the other solutions on here :(
The function set_lengths did not set the member variable correctly, just set the value back to the function arguments.
change
void set_lengths(int width, int height)
{
width = width; height = height;
}
to
void set_lengths(int width, int height)
{
this->width = width; this->height = height;
}
Or change the name of the member variables for a good habit:
int width_, height_, shapes_;
void set_lengths(int width, int height)
{
width_ = width;
height_ = height;
}
Becuase width and height are not initilized.
Change the line to:
int i = 0, j = 0, k = 0;
Also, you're only setting the dimension of the rect object, not the triangle or the square.
I'm trying to calculate the area of the circle and the rectangle by using the existing data (radius ,width, and height). But i have some errors, i hope you can help me fix it.
#include <iostream>
#include <vector>
#include <string>
using namespace std;
class Shape
{
public:
virtual void Draw () = 0;
virtual void MoveTo (int newx, int newy) = 0;
virtual int GetArea()const = 0;
};
class Rectangle : public Shape
{
public:
Rectangle (int x, int y, int w, int h);
virtual void Draw ();
virtual void MoveTo (int newx, int newy);
int GetArea() {return height * width;}
private:
int x, y;
int width;
int height;
};
void Rectangle::Draw ()
{
cout << "Drawing a Rectangle at (" << x << "," << y
<< "), width " << width << ", height " << height << "\n";
};
void Rectangle::MoveTo (int newx, int newy)
{
x = newx;
y = newy;
}
Rectangle::Rectangle (int initx, int inity, int initw, int inith)
{
x = initx;
y = inity;
width = initw;
height = inith;
}
class Circle : public Shape
{
public:
Circle (int initx, int inity, int initr);
virtual void Draw ();
virtual void MoveTo (int newx, int newy);
int GetArea() {return 3.14 * radius * radius;}
private:
int x, y;
int radius;
};
void Circle::Draw ()
{
cout << "Drawing a Circle at (" << x << "," << y
<< "), radius " << radius <<"\n";
}
void Circle::MoveTo (int newx, int newy)
{
x = newx;
y = newy;
}
Circle::Circle (int initx, int inity, int initr)
{
x = initx;
y = inity;
radius = initr;
}
int main ()
{
Shape * shapes[2];
shapes[0] = new Rectangle (10, 20, 5, 6);
shapes[1] = new Circle (15, 25, 8);
for (int i=0; i<2; ++i) {
shapes[i]->Draw();
shapes[i]->GetArea();
}
return 0;
}
Rectangle::GetArea method should be const. You declared it non-const, so it is not considered an override of Shape::GetArea, so Rectangle is considered abstract.
You may want to rethink your return type too.
int Circle::GetArea() {return 3.14 * radius * radius;}
As pointed by #Cătălin Pitiș, the GetArea() methods in derived classes need to be const. Otherwise compiler will complain that you have not provided the implementation for pure virtual functions (hence the derived classes become abstract) and will not allow you to create objects of the. Additionally, you need to declare a virtual destructor for Shape class. Otherwise, you will not be able release the memory properly. Also, you are not releasing the memory in main() function. You should use delete to release the memory allocated for the objects.