Animator in c++ with SDL2 - c++

I try to have a map where the key is an enum, and the value an array of SDL_Rect (which contains) all the coords for the animation.
std::map<Animation, SDL_Rect*> animations;
Animation currAnim;
I dont want to define a fixed number of animation like a solution I found here. How can I do ? Because
SDL_Rect right[3];
right[0].x = 264;
right[0].y = 0;
right[0].w = 36;
right[0].h = 64;
...
animations.insert(std::pair<Animation, SDL_Rect*>(Animation::MoveRight, right));
doesn't work.
I tried this but know I have another problem in my draw, where I must find the element of the vector with an int (frame) :
void Player::Draw(SDL_Renderer * renderer, int frame)
{
std::vector<SDL_Rect>::iterator it = std::find(animator->GetAnimations()[animator->GetCurrAnim()].begin(),
animator->GetAnimations()[animator->GetCurrAnim()].end(), frame);
SDL_RenderCopy(renderer, lTexture->GetTexture(), &*it, &rect);
}
I tried this but there is an error which said
'==' There is no operator found which accept type "SDL_Rect"

I would guess that the array you're using goes out of scope, thus the pointer you stored in the map is no longer valid.
Since you didn't post all of your code, one suggestion to you is to not store pointers as the data in the map. Instead, use std::vector.
#include <map>
#include <vector>
typedef std::map<Animation, std::vector<SDL_Rect>> AnimationMap;
//...
AnimationMap animations;
//...
std::vector<SDL_Rect> right(3);
right[0].x = 264;
right[0].y = 0;
right[0].w = 36;
right[0].h = 64;
//...
animations.insert(std::make_pair(Animation::MoveRight, right));
//...
If the vector right goes out of scope, the map is still ok, as a copy of the vector is placed in the data portion of the map.

Related

Are they actually garbage values or just the default values of enumeration if I don't initialize them?

I have branch positions that are not initialized to any value of side enumeration. However, when I try to draw them to the screen, they're actually on the same side, on the left side of the tree. I think those uninitialized branch positions are garbage values, a remnant from the memory that the PC has been used or hasn't been used. I'm not quite sure every time I run the program, they're always on the left side, which seems consistent, which is the first value in the side enumeration, which I assumed to be 0. Are they actually garbage values or just the default values of enumeration if I don't initialize them?
// Include important libraries here
#include <SFML/Graphics.hpp>
// Make code easier to type with "using namespace"
using namespace sf;
// Function declaration
void updateBranches(int seed);
const int NUM_BRANCHES = 6;
Sprite branches[NUM_BRANCHES];
// Where is the player/branch?
// Left or Right
enum class side { LEFT, RIGHT, NONE };
side branchPositions[NUM_BRANCHES];
// This is where our game start from
int main()
{
// Create a video mode object
VideoMode vm(1920, 1080);
// Create and open a window for the game
RenderWindow window(vm, "Timber!!!", Style::Fullscreen);
// Track whether the game is running
bool paused = true;
while (window.isOpen())
{
/*
****************************************
Handle the player's input
****************************************
*/
if (Keyboard::isKeyPressed(Keyboard::Escape))
{
window.close();
}
// Start the game
if (Keyboard::isKeyPressed(Keyboard::Enter))
{
paused = false;
// Reset the time and the score
score = 0;
timeRemaining = 6;
}
/*
****************************************
Update the scene
****************************************
*/
if (!paused)
{
// update the branch sprites
for (int i = 0; i < NUM_BRANCHES; i++)
{
float height = i * 150;
if (branchPositions[i] == side::LEFT)
{
// Move the sprite to the left side
branches[i].setPosition(610, height);
// Flip the sprite round the other way
branches[i].setRotation(180);
}
else if (branchPositions[i] == side::RIGHT)
{
// Move the sprite to the right side
branches[i].setPosition(1330, height);
// Set the sprite rotation to normal
branches[i].setRotation(0);
}
else
{
// hide the branch
branches[i].setPosition(3000, height);
}
}
} // End if(!paused)
/*
****************************************
Draw the scene
****************************************
*/
// Clear everything from the last frame
window.clear();
// Draw the branches
for (int i = 0; i < NUM_BRANCHES; i++)
{
window.draw(branches[i]);
}
// Show everything we just drew
window.display();
}
return 0;
}
Uninitialized (non-static) local variables are not initialized.
Uninitialized variables in namespace scope (including the global namespace, like your branchPositions array) are actually "zero" initialized.
So all elements of the branchPositions array should be zero, which is equal to LEFT.
Turn all warnings on and check what the compiler says. If your compiler complains then your code is very likely wrong.
It seems you are relying on the fact that static variables are initialised to zeroes. And by chance zero corresponds to one enumeration value. You are living very dangerous. You should usually be able to change the order of enumeration, but you can’t. Change the enum to LEFT = 1 and everything will break down.
In C++ it is defined that enum values start with 0 unless you define it otherwise, and each one is 1 more than the previous one unless you state otherwise. That’s something you can rely on. But you are relying on how variables are initialised and that is very, very dangerous.

Data analysis - memory bug c++

I am a data scientist, currently working on some C++ code to extract triplet particles from a rather large text file containing 2D coordinate data of particles in ~10⁵ consecutive frames. I am struggling with a strange memory error that I don't seem to understand.
I have a vector of structs, which can be divided into snippets defined by their frame. For each frame, I build an array with unique ID's for each individual coordinate pair, and if at any point the coordinate pair is repeated, the coordinate pair is given the old coordinate pair. This I then use later to define whether the particle triplet is indeed a trimer.
I loop over all particles and search forward for any corresponding coordinate pair. After I'm done, and no particles were found, I define this triplet to be unique and push the coordinates into a vector that corresponds to particle IDs.
The problem is: after the 18th iteration, at line trimerIDs[i][0] = particleCounter; , the variable trimerCands (my big vector array) suddenly becomes unreadable. Can this be that the vector pointer object is being overwritten? I put this vector fully on the heap, but even if I put it on stack, the error persists.
Do any of you have an idea of what I might be overlooking? Please note that I am rather new at C++, coming from other, less close to the metal, languages. While I think I understand how stack/heap allocations work, especially with respect to vectors/vector structs, I might be very wrong!
The error that Eclipse gives me in the variables tab is:
Failed to execute MI command:
-data-evaluate-expression trimerCands
Error message from debugger back end:
Cannot access memory at address 0x7fff0000000a
The function is as follows.
struct trimerCoords{
float x1,y1,x2,y2,x3,y3;
int frame;
int tLength1, tLength2, tLength3;
};
void removeNonTrimers(std::vector<trimerCoords> trimerCands, int *trCandLUT){
// trimerCands is a vector containing possible trimers, tLengthx is an attribute of the particle;
// trCandLUT is a look up table array with indices;
for (int currentFrame = 1; currentFrame <=framesTBA; currentFrame++){ // for each individual frame
int nTrimers = trCandLUT[currentFrame] - trCandLUT[currentFrame-1]; // get the number of trimers for this specific frame
int trimerIDs[nTrimers][3] = {0}; // preallocate an array for each of the inidivual particle in each triplet;
int firstTrim = trCandLUT[currentFrame-1]; // first index for this particular frame
int lastTrim = trCandLUT[currentFrame] - 1; // last index for this particular frame
bool found;
std::vector<int> traceLengths;
traceLengths.reserve(nTrimers*3);
// Block of code to create a unique ID array for this particular frame
std::vector<Particle> currentFound;
Particle tempEntry;
int particleCounter = 0;
for (int i = firstTrim; i <= lastTrim; i++){
// first triplet particle. In the real code, this is repeated three times, for x2/y2 and x3/y3, corresponding to the
tempEntry.x = trimerCands[i].x1;
tempEntry.y = trimerCands[i].y1;
found = false;
for (long unsigned int j = 0; j < currentFound.size(); j++){
if (fabs(tempEntry.x - currentFound[j].x) + fabs(tempEntry.y - currentFound[j].y) < 0.001){
trimerIDs[i][0] = j; found = true; break;
}
}
if (found == false) {
currentFound.push_back(tempEntry);
traceLengths.push_back(trimerCands[i].tLength1);
trimerIDs[i][0] = particleCounter;
particleCounter++;
}
}
// end block of create unique ID code block
compareTrips(nTrimers, trimerIDs, traceLengths, trimerfile_out);
}
}
If anything's unclear, let me know!

C++ SFML Array Error: Access violation reading location 0xC0000005

I am making a game with C++ and SFML, and I am having a problem during rendering various items with array. When I try to draw an array of sprites, the debugging is alright, and there are no warning and errors, but my game program runs only 20 seconds, then it stops running, and says, 'Unhandled exception at 0x7C50CF2E(sfml-graphics-d-2.dll), ECOVID-19 SFML.exe): 0xC0000005: Access violation reading location 0xCCCCCCD0.' I did everything I can, but I don't know why this exception occurs.
Here are my codes that I suspect the causation of the error.
Thank you for reading in spite of my poor English.
#include <SFML/Graphics.hpp>
...
using namespace std;
using namespace sf;
...
int main () {
...
//item Sprites
Texture bombTex;
bombTex.loadFromFile("images/bomb.png");
Sprite bomb;
...
Texture bomb2Tex;
bomb2Tex.loadFromFile("images/bomb_2.png");
Sprite bomb_2;
...
Texture cakeTex;
cakeTex.loadFromFile("images/cake.png");
Sprite cake;
...
Texture coffeeTex;
coffeeTex.loadFromFile("images/coffee.png");
Sprite coffee;
...
Texture chickenTex;
chickenTex.loadFromFile("images/chicken.png");
Sprite chicken;
...
Texture pizzaTex;
pizzaTex.loadFromFile("images/pizza.png");
Sprite pizza;
//item array (I made an item array to display & render various items in the game screen.)
Sprite item[10]; //Although I change the array size to 4 or 5, the same exception occurs.
item[0] = bomb;
item[1] = coffee;
item[2] = bomb_2;
item[3] = chicken;
item[4] = pizza;
std::vector<Sprite> items;
items.push_back(Sprite(item[4]));
...
while (window.isOpen())
{ ...
...
for (size_t i = 0; i < items.size(); i++)
{
if (humanArr[index].getGlobalBounds().intersects(item[i].getGlobalBounds()))
//humanArr[index] is a player Sprite.
{
...
items.erase(items.begin() + i);
}
}
...
window.clear();
...
for (size_t i = 0; i < items.size(); i++)
{
window.draw(item[i]); // <- the exception error occurs here.
}
...
window.display();
}
return 0;
}
What may be happening is that when you copy the Sprite item[10]; to the std::vector<Sprite> items; the Sprite class is making a shallow copy. It means that if the Sprite class is allocating any memory with new operator and storing it in a member pointer, then the shallow copy will only copy the address to which the pointer is pointing. When you do call items.erase(items.begin() + i); the destructor of the Sprite will be called, and in the destructor it may be calling delete in that pointer to some resourse.
When you call window.draw(item[i]); the library will try to use that resource and will find an invalid address.
What I suggest is that you don't use the Sprite item[10]; and only the std::vector<Sprite> items; , like this:
std::vector<Sprite> items;
items.push_back(bomb);
items.push_back(coffee);
...
window.draw(items[i]);
You don't need to use an intermediate array, just the std::vector<Sprite>;

Trying to draw rectangles stored in an array, but only one rectangle appears?

My code is here:
As stated above, I'm trying to draw a series of bars across the screen with different x positions and I've stored them in arrays. It seems the code only draws 1 rectangle, even though I've checked and each bar has a different x position so I'm sure its an issue with how I'm drawing the objects but it feels right.
I've also made a similar program with vectors using the same loop for drawing but with .at(i) instead which does work but this oddly does not.
I've been trying to figure this out for a while and I'm tired now so please help, point out my errors... etc...
#include <SFML/Graphics.hpp>
int main()
{
sf::RenderWindow window(sf::VideoMode(640, 640), "Square", sf::Style::Close | sf::Style::Resize);
sf::RectangleShape bar[64] = {sf::RectangleShape(sf::Vector2f( (window.getSize().x)/64.0f ,100.0f))};
// creates 64 bars of equal width
for (int i = 0; i < 64; i++)
{
bar[i].setFillColor(sf::Color(0, 0, 255, 255));
bar[i].setPosition( 10*i , (window.getSize().y)/2);
// sets bars x position to shift over for every bar
}
bar[3].setPosition(600, 300);
// just a test doesn't render even though it should
while (window.isOpen())
{
//////////////////////////////////////////////////
window.clear(sf::Color(130, 130, 150, 255));
for (int i = 0; i < 64; i++)
{
window.draw(bar[i]);
}
window.display();
/////////////////////////////////////////////////
}```
I cut out the rest of the code as the rest works and really has nothing to do with the code for simplicity sake
I want it to render out rectangles across the screen but it only displays one and I can't figure out why?
sf::RectangleShape has default ctor:
sf::RectangleShape::RectangleShape ( const Vector2f & size = Vector2f(0, 0) )
You have defined rectangle's size only for the first one, other 63 have default size (0,0).
You can copy/paste your rect definition in raw array, or use std::vector and call ctor which takes value and number of elements:
std::vector<sf::RectangleShape> bars( 64, // num of elems
sf::RectangleShape( sf::Vector2f(window.getSize().x/64.0f ,100.0f) ) );
Another solution is to call setSize in every iteration of loop (just like with setFillColor, setPosition etc).

C++ and SDL problem

I want to blit surfaces that I've created in two classes. One is called Map, that holds the relevant map vector as well as some other stuff. The other is a Tile class. There is a problem when I run the program.
I get no errors, and the program runs as it should. Any ideas? It's probably a stupid mistake somewhere.
Map populate
void map::Populate(map M)
for(int x=0;x<=19;x++)
{
for(int y=0;y<=15;y++)
{
int y2 = (y*32);
int x2 = (y*32);
Tile T(x2,y2);
M.AddToMap(&T);
printf("Added Tile");
Render
void map::Render(SDL_Surface* screen)
{
for(int x=0;x<grid.size();x++)
{
printf("test");
Tile* T = grid[x];
SDL_Surface* k = T->GetIcon();
SDL_Rect dstrect;
dstrect.x = (screen->w - k->w) / 2;
dstrect.y = (screen->h - k->h) / 2;
SDL_BlitSurface(k, 0, screen, &dstrect);
You're not stating what the problem actually is, just that the program "runs as it should".
Problems in your code:
int x2 = (y*32); should likely be x*32.
void map::Populate(map M) takes a map by value - this copies the map you pass, and any changes will not be visible in the passed map. map & M passes a reference, so changes will be seen in the map you pass.
M.AddToMap(&T) adds a pointer to the local Tile variable, which gets invalidated each iteration of the inner loop. More likely you want new Tile(T) there, or better yet a smart pointer such as boost's shared_ptr. Remember that you also need to delete those Tiles if you don't use a smart pointer.
New code:
void map::Populate(map & M)
for(int x=0; x<20; x++)
{
for(int y=0; y<16; y++)
{
int y2 = (y*32);
int x2 = (x*32);
M.AddToMap(new Tile(x2,y2));
printf("Added Tile");
You are adding a reference to a local variable to your map in Populate. If the method doesn't make a copy of the input, this is most likely wrong. Make a copy (pass by value) or store a smart pointer to your Tile. Of course you can store a plain old pointer, but make sure to delete those Tiles in the end!
Assuming your problem is that the image doesn't show up you may need to post the setup code for the screen and surfaces so we can see if that is the problem.