DKdowneR

C++ Player out of tile map

Recommended Posts

Hi! I made a tile map reading from a file. Almost everything works good, but when a player go out of map, program runs into an error and says that "vector subscript out of range". My question is how to make check for it

Drawing map : 

void GameplayScreen::DrawMap(SDL_Renderer *renderer)
{
	for (int y = map.size() - 1; y >= 0; --y)
	{
		for (int x = getStartBlockX(), xEnd = getEndBlockX(); x < xEnd && x < map[y].size(); ++x)
		{
			if (map[y][x] != "0,0")
			{
				int tempX = atoi(map[y][x].substr(0, map[y][x].find(',')).c_str());
				int tempY = atoi(map[y][x].substr(map[y][x].find(',') + 1).c_str());

				srcRect.x = tempX * 32;
				srcRect.y = tempY * 32;
				srcRect.w = 32;
				srcRect.h = 32;

				destRect.x = x * 32 + posX;
				destRect.y = (y * 32 + posY);
				destRect.w = 32;
				destRect.h = 32;
              
				vBlock[Earth]->Draw(renderer, srcRect, destRect);
            }
		}
	}
}

getStartBlockX returns first map block, getEndBlockX returns last, so it's like render on screen only a piece of map, not all blocks.
tempX returns x coordinate of tile image,  tempY y coordinate. So, for example, if map is like :

0,0 0,0 0,0 0,0 0,0

0,0 0,0 0,0 0,0 0,0

1,0 2,0 0,3 1,0 1,0

0,0 is first block image, 1,0 is one next to the first, 0,3 is 2 under the first block etc.

 

 

Edited by DKdowneR

Share this post


Link to post
Share on other sites
1 hour ago, DKdowneR said:

Hi! I made a tile map reading from a file. Almost everything works good, but when a player go out of map, program runs into an error and says that "vector subscript out of range". My question is how to make check for it

Drawing map : 


void GameplayScreen::DrawMap(SDL_Renderer *renderer)
{
	for (int y = map.size() - 1; y >= 0; --y)
	{
		for (int x = getStartBlockX(), xEnd = getEndBlockX(); x < xEnd && x < map[y].size(); ++x)
		{
			if (map[y][x] != "0,0")
			{
				int tempX = atoi(map[y][x].substr(0, map[y][x].find(',')).c_str());
				int tempY = atoi(map[y][x].substr(map[y][x].find(',') + 1).c_str());

				srcRect.x = tempX * 32;
				srcRect.y = tempY * 32;
				srcRect.w = 32;
				srcRect.h = 32;

				destRect.x = x * 32 + posX;
				destRect.y = (y * 32 + posY);
				destRect.w = 32;
				destRect.h = 32;
              
				vBlock[Earth]->Draw(renderer, srcRect, destRect);
            }
		}
	}
}

getStartBlockX returns first map block, getEndBlockX returns last, so it's like render on screen only a piece of map, not all blocks.
tempX returns x coordinate of tile image,  tempY y coordinate. So, for example, if map is like :

0,0 0,0 0,0 0,0 0,0

0,0 0,0 0,0 0,0 0,0

1,0 2,0 0,3 1,0 1,0

0,0 is first block image, 1,0 is one next to the first, 0,3 is 2 under the first block etc.



 

 

Well you dont check x to being negative. Also when x and and xEnd are equal, you are standing on the same x-line - but from your condition you exit the loop, is this indented? Shouldnt this be x <= xEnd ? Or does getEndBlockX returns the range instead of the last index? From the name of the function i would expect, the last index.

 

Also why you dont have a getStartBlockY() and getEndBlockY() or are your player limited to X-direction only ?

 

Edited by Finalspace

Share this post


Link to post
Share on other sites

I'm planning to do with Y direction. It doesnt matter that it's x < xEnd or x <= xEnd, because I add 1 right in the method. They looks like this: 

int GameplayScreen::getStartBlockX()
{
	return (int)(-posX + (int)posX % 32) / 32;
}
int GameplayScreen::getEndBlockX()
{
	return (int)(-posX + (int)posX % 32 + System::getFM()->getW()) / 32 + 1;
}

Also I don't think that I should check for x is negative, because it's always positive
 

 

getW() returns window width.

Edited by DKdowneR

Share this post


Link to post
Share on other sites

I don't see an error with the for loops, maybe I'm overlooking it. Are you sure the error isn't somehow in this call:

1 hour ago, Finalspace said:

vBlock[Earth]->Draw(renderer, srcRect, destRect);

What is the value of Earth?

Share this post


Link to post
Share on other sites

You can just use the keyword continue or break from that loop

1 hour ago, DKdowneR said:

int GameplayScreen::getEndBlockX() { return (int)(-posX + (int)posX % 32 + System::getFM()->getW()) / 32 + 1; }

Also, I don't think this is doing what you think it is. I think you need more parenthesis to control the order of operations.

Share this post


Link to post
Share on other sites

What you think it is? It returns last block, so if window is 1280 width,  it returns 40, that's only what I need it to do and in draw for loop, loop through 0 to 40. So, it renders 40 block instead of ~90. If start block = 5, end = 45, etc. so, always depends on window it returns everything to render only that what need to be on the screen, nothing more, nuting less.

Edited by DKdowneR

Share this post


Link to post
Share on other sites

So, is posX screen coordinates for a tile, or the start block or what?

(int)(-posX + (int)posX % 32 + System::getFM()->getW()) / 32 + 1

if start block = 5

(int)(-5 + (int)5 % 32 + 1280) / 32 + 1

(int)(-5 + 5 + 1280) / 32 + 1

(int)(1280) / 32 + 1

(int)40 + 1 =

41 not 45

 

Edited by Yxjmir
Math error

Share this post


Link to post
Share on other sites
6 hours ago, DKdowneR said:

Also I don't think that I should check for x is negative, because it's always positive

What values can posX have?

If posX can be greater than 32, getStartBlockX will return a negative number.

return (int)(-posX + (int)posX % 32) / 32;

//Assuming posX = 33:
//Ignoring the int-casts to show it simpler.
return (-33 + 33 % 32) / 32;
return (-33 + 1) / 32;
return -32 / 32;
return -1;

 

Share this post


Link to post
Share on other sites

posX is a value that decrease if position X of Player is higher than or equal (1280/2) - playerWidth and if Player moves right. if moves left and position X of Player is lower than or equal (1280/2) - playerWidth, posX increase.

The player and map moving formula are :
 

//moving right
if (posX >= (System::getFM()->getW() / 2) - getHitBoxX() && System::getSM()->GetGame()->getMoveMap())// && System::getSM()->GetGame()->getPosX() >= -1760)
{
	System::getSM()->GetGame()->MoveMap(-moveSpeed, 0);
}
	// player posX
else posX += moveSpeed;

moveAnim = true;


// moving left
if (posX <= (System::getFM()->getW() / 2) - getHitBoxX() && System::getSM()->GetGame()->getMoveMap() && System::getSM()->GetGame()->getPosX() < 0)
{
	System::getSM()->GetGame()->MoveMap(-moveSpeed, 0);
}
else if (posX - System::getSM()->GetGame()->getPosX() + moveSpeed >= 0 && posX >= 0)
{
  // player posX
	posX += moveSpeed;
}
else if (posX >= 0)
{
	UpdatePosX(moveSpeed + 1);
}
moveAnim = true;

Getgame returns GameplayScreen instace, move map is a method that add moveSpeed to posX of map. getMoveMap() returns boolean, if true, map can move, if false, it cannot.

LactoseposX is always negative or 0.

Yxjmir, that's right. I gave a bad example. It's 40 because if posX = 5, still I can see only 40 block and a piece of 41, and then I add 1 to get 1 more blocks. It returns ~41.

Untitled.png

as you can see, on the right site there are pieces of blocks.

Edited by DKdowneR

Share this post


Link to post
Share on other sites

Depending on your compiler, modulo of a negative number can result in undefined behavior.

Regardless, it should be fairly easy to track down where the error is in your case, since you can reproduce it easily:

For every loop, before using the x and y indices anywhere, print/log them.

When your application crashes, see what the x and y values are. Then, the next step is to find out why they are broken, and how to fix it.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now


  • Forum Statistics

    • Total Topics
      627711
    • Total Posts
      2978753
  • Similar Content

    • By Josheir
      I am working on a SFML c++ program that uses two rendering windows passed from main to the function drawmessage in a class textmessage.  I was using the second window for displaying debug information that is displayed because I could not get the appropriate information from the SFML object.
      With that said, here is the part of that function that works the first time through and does not on the second usage.  I really have changed the code to try and get it working.   For example I created the two objects locally here for testing.  I am sorry about the extra commented statements they help convey the message too.
      There is the same problem though, the statement :     string test =     message_holder10.getString(); is working and shows "asty" on every run.  On the first run of the program there is a display of the text correctly however on the second call there is no display of it.  (I am stepping through until the display command.)
      I feel like I have exhausted my tries so I am asking for help please.
      If it is the font I will just die, I really don't think it is.
       
       
       
                  sf::Text message_holder10;
                  sf::RenderWindow windowtype3(sf::VideoMode(700, 1000), "a");

                  if ((space_is_used && on_last_line) || (space_is_used && ((line_number) == (total_lines - 2))))
                  {

                      //string temp_string = message::Get_Out_Bound_String();
                      //int length_of_string = temp_string.length();
                      sf::Font Fontforscore;
                      if (gflag == 0)
                      {
                          gflag = 1;
                          
                          if (!Fontforscore.loadFromFile("ARIALBD.ttf"))
                          {
                              exit(1);
                          }

                          message_holder10.setFont(Fontforscore);
                          message_holder10.setCharacterSize(100);
                          message_holder10.setFillColor(sf::Color::Red);
                          message_holder10.setOrigin(0, 0);
                          message_holder10.setPosition(0, 0);
                          windowtype2.close();
                      }
                      message_holder10.setString("asty");
                          
                          //int y_for_space = display_y_setting + (total_lines - 2) * each_vertical_offset_is;
                          //int this_width = 0;
                          
                          //float x = message_holder.getLocalBounds().width;

                          
                          
                          //message_holder.setPosition( ( (first_width - x )/2), y_for_space);
                          
                  
                          //windowtype2.close();

                          string test =     message_holder10.getString();
                          
                          windowtype3.clear();
                          windowtype3.draw(message_holder10);
                          windowtype3.display();
                          
                          
                           
       
                          //windowtype.display();
                      

                       Wait_For_Space_Press();
                      
       
      /////////////////////////
       
      Before, the :      windowtype3.display()  without the clear was drawing other text in this call, just not this one particular text message with it!
       
      Thank you so much I am wondering what it can be,
       
      Josheir
    • By Tispe
      Hi
      I want to test out a polymorphic entity component system where the idea is that the components of an entity are "compositioned" using templated multiple inheritance. But I am running into an issue because I am stacking a bunch of methods with the same names inside a class (but they have different signatures). I want these methods to be overloaded by the template type but my compiler says the access is ambiguous. I have issues making them unambiguous with the using declaration because the paramter pack expansion causes a syntax error.
      Can anyone here give me some advice on this?
       
      template <class T> class component { T m_data; protected: component() {}; ~component() {}; public: void set(const T& data) { m_data = data; }; }; template <class ...Ts> class entity : public component<Ts>... { public: entity() {}; ~entity() {}; //using component<Ts>::set...; // syntax error }; struct position { float x{}; float y{}; float z{}; }; struct velocity { float x{}; float y{}; float z{}; }; int main() { entity<position, velocity> myEntity; position pos = { 1.0f, 1.0f, 1.0f }; velocity vel = { 2.0f, 2.0f, 2.0f }; myEntity.set(pos); // error C2385: ambiguous access of 'set' //myEntity.set(vel); return 0; }  
    • By Baemz
      Hello,
      I've been working on some culling-techniques for a project. We've built our own engine so pretty much everything is built from scratch. I've set up a frustum with the following code, assuming that the FOV is 90 degrees.
      float angle = CU::ToRadians(45.f); Plane<float> nearPlane(Vector3<float>(0, 0, aNear), Vector3<float>(0, 0, -1)); Plane<float> farPlane(Vector3<float>(0, 0, aFar), Vector3<float>(0, 0, 1)); Plane<float> right(Vector3<float>(0, 0, 0), Vector3<float>(angle, 0, -angle)); Plane<float> left(Vector3<float>(0, 0, 0), Vector3<float>(-angle, 0, -angle)); Plane<float> up(Vector3<float>(0, 0, 0), Vector3<float>(0, angle, -angle)); Plane<float> down(Vector3<float>(0, 0, 0), Vector3<float>(0, -angle, -angle)); myVolume.AddPlane(nearPlane); myVolume.AddPlane(farPlane); myVolume.AddPlane(right); myVolume.AddPlane(left); myVolume.AddPlane(up); myVolume.AddPlane(down); When checking the intersections I am using a BoundingSphere of my models, which is calculated by taking the average position of all vertices and then choosing the furthest distance to a vertex for radius. The actual intersection test looks like this, where the "myFrustum90" is the actual frustum described above.
      The orientationInverse is the viewMatrix in this case.
      bool CFrustum::Intersects(const SFrustumCollider& aCollider) { CU::Vector4<float> position = CU::Vector4<float>(aCollider.myCenter.x, aCollider.myCenter.y, aCollider.myCenter.z, 1.f) * myOrientationInverse; return myFrustum90.Inside({ position.x, position.y, position.z }, aCollider.myRadius); } The Inside() function looks like this.
      template <typename T> bool PlaneVolume<T>::Inside(Vector3<T> aPosition, T aRadius) const { for (unsigned short i = 0; i < myPlaneList.size(); ++i) { if (myPlaneList[i].ClassifySpherePlane(aPosition, aRadius) > 0) { return false; } } return true; } And this is the ClassifySpherePlane() function. (The plane is defined as a Vector4 called myABCD, where ABC is the normal)
      template <typename T> inline int Plane<T>::ClassifySpherePlane(Vector3<T> aSpherePosition, float aSphereRadius) const { float distance = (aSpherePosition.Dot(myNormal)) - myABCD.w; // completely on the front side if (distance >= aSphereRadius) { return 1; } // completely on the backside (aka "inside") if (distance <= -aSphereRadius) { return -1; } //sphere intersects the plane return 0; }  
      Please bare in mind that this code is not optimized nor well-written by any means. I am just looking to get it working.
      The result of this culling is that the models seem to be culled a bit "too early", so that the culling is visible and the models pops away.
      How do I get the culling to work properly?
      I have tried different techniques but haven't gotten any of them to work.
      If you need more code or explanations feel free to ask for it.

      Thanks.
       
    • By AyeRonTarpas
      A friend of mine and I are making a 2D game engine as a learning experience and to hopefully build upon the experience in the long run.

      -What I'm using:
          C++;. Since im learning this language while in college and its one of the popular language to make games with why not.     Visual Studios; Im using a windows so yea.     SDL or GLFW; was thinking about SDL since i do some research on it where it is catching my interest but i hear SDL is a huge package compared to GLFW, so i may do GLFW to start with as learning since i may get overwhelmed with SDL.  
      -Questions
      Knowing what we want in the engine what should our main focus be in terms of learning. File managements, with headers, functions ect. How can i properly manage files with out confusing myself and my friend when sharing code. Alternative to Visual studios: My friend has a mac and cant properly use Vis studios, is there another alternative to it?  
    • By Defend
      Not asking about singletons here (nor advocating). With that clarified:
      If we assume someone wants a global + unique object, why isn't a namespace always the preferred approach in C++, over implementing a singleton class?
      I've only seen the namespace approach encouraged when there aren't statics being shared. Eg; from Google's style guidelines:
      But why not have non-member functions that share static data, declared in an unnamed namespace? And why isn't this generally suggested as a better alternative to writing a singleton class in C++?
  • Popular Now