Creating "Item" definitions - c++

I am trying to think of a good way to define base-items for a small game I am creating in C++ using DirectX. Right now the structure would look something like:
struct itemdef {
string name;
ID3DXMesh* mesh;
vector<IDirect3DTexture9*> textures;
vector<short> abilities;
};
The problem I am having is I essentially want to make an array of these base properties without creating an upper limit for textures or abilities.
Essentially imagine it as having another array of "itemdef"
vector<itemdef> itemDefs;
and then wanting to add items to this array, either hardcoded or from a file:
itemDefs.push_back(NewItem("Wall", Assets.GetMesh(Mesh_Wall), ???, ???));
Basically, I have no idea how to put multiple single items into a parameter list for a vector array. The second problem being the need to create two lists in one set of arguments.
So my question is: What should replace the "???" fields in that statement above? Or, failing that, what better method should I use to store these basic definitions?
(for clarity: Pointers for textures are obtained virtually the same way as the mesh above was and the "abilities" are just short ints. Although it should be noted that for these definitions both meshes and textures could just be replaced with their enumerations rather than pointers)

I would build up the vector's first as local variables and then send them to the item constructor:
vector<IDirect3DTexture9*> tex;
vector<short*> abil;
// fill them with the data you need
itemDefs.push_back(NewItem("Wall", Assets.GetMesh(Mesh_Wall), tex, abil));
itemdef NewItem(const string& name, ID3DMesh* mesh, const vector<IDirect3DTexture9*>& textures, const vector<short*>& abilities)
{
itemdef retval;
retval.name = name;
retval.mesh = mesh;
retval.textures = textures;
retval.abilities = abilities;
return retval;
}
Alternatively you could write some function which builds and returns the vector's.
PS: Why do you use some global NewItem-function instead of a constructor?

Related

Passing pointer to single item in Vector of Multidimensional Array to Function c++

I'm working on a program using SDL. I have the following variable instantiated outside of my main function:
std::vector<SDL_Rect[TOTAL_ACTIVITIES][TOTAL_DIRECTIONS][ANIMATION_FRAMES]> gPersonSpriteClips;
(where the all-caps items are constant integers). It's a vector of arrays, because I intend to do a lot of sprite development later. For now, I just have a few placeholder sprites. So, the 3D array captures all aspects of a single human body-type spritesheet, and when I pull in the sheet I'll have the code split it up into multiple body types...
I have a class, "Character", which makes use of the array when it is preparing to render. Here is the call to render myCharacter in main:
myCharacter.render(bodySpritesheetTexture, &*gPersonSpriteClips[myCharacter.getBody()]);
Character.getBody() returns the vector index for the body type used by this instance of character. Here is the function declaration in Character.h:
void render(LTexture& characterSpriteSheetTexture, SDL_Rect spriteClips[TOTAL_ACTIVITIES][TOTAL_DIRECTIONS][ANIMATION_FRAMES]);
Here is the function itself in Character.cpp:
void Character::render(LTexture& characterSpriteSheetTexture, SDL_Rect spriteClips[TOTAL_PERSON_ACTIVITIES][TOTAL_CARDINAL_DIRECTIONS][PERSON_ANIMATION_FRAMES])
{
characterSpriteSheetTexture.render( mPosition.x, mPosition.y, &spriteClips[mActivity][mDirection][mAnimations[mActivity][mCurrentFrame]] );
}
mActivity is the enum for "which activity is presently being performed" by the character. mDirection is which direction he's facing. mAnimations lists frame orders (because some of these animations use the same sprites several times in various orders).
Finally, the render function for LTexture is taken right out of LazyFoo's SDL tutorials.
characterSpriteSheetTexture.render() is calling a function with the following declaration (in LTexture.h):
void render( int x, int y, SDL_Rect* clip = NULL, int targetHeight = NULL, int targetWidth = NULL, double angle = 0.0, SDL_Point* center = NULL, SDL_RendererFlip flip = SDL_FLIP_NONE );
So it's expecting an argument of type SDL_Rect* clip. That function makes a call to:
SDL_RenderCopyEx( gRenderer, mTexture, clip, &renderQuad, angle, center, flip );
I get an error when I compile the code, pointing me to a place inside the SDL libraries. I've successfully employed LTexture's render function by passing indexes from one-dimensional arrays of SDL_Rect into it, so I'm very confident that the problem exists in my vector argument.
Ignoring disagreements about naming conventions...... what am I doing wrong here, and what's the proper way to achieve what I'm trying to do?
Granted, I'll probably simplify my scheme for animating things significantly in the future; this is my first shot at generating a player character. Anyway, I'd like to know the mechanics of what's going wrong in this case.
Last thing, please don't suggest that I use boost. I'd really like to avoid boost for this program.
ETA:
Here is the declaration of mAnimations in Character.h:
std::vector<int> mAnimations[TOTAL_ACTIVITIES];
Here is the initialization of it in the default constructor:
for (int i = 0; i < TOTAL_ACTIVITIES; i++)
{
mAnimations[i].resize(ANIMATION_FRAMES);
for (int j = 0; j < ANIMATION_FRAMES; j++)
{
mAnimations[i][j] = j;
}
}
Change your global array definition like this:
using SdlRectArray = std::array<std::array<std::array<SDL_Rect, ANIMATION_FRAMES>, TOTAL_DIRECTIONS>, TOTAL_ACTIVITIES>;
std::vector<SdlRectArray> gPersonSpriteClips;
See here for why not to store arrays in a std::vector or any other container.
Accordingly, define your Character::render() method like this:
void render(LTexture& characterSpriteSheetTexture, SdlRectArray& spriteClips)
{
characterSpriteSheetTexture.render( mPosition.x, mPosition.y, &spriteClips[mActivity][mDirection][mAnimations[mActivity][mCurrentFrame]] );
}
And then you can call it like this:
myCharacter.render(bodySpritesheetTexture, gPersonSpriteClips[myCharacter.getBody()]);
as there's no need for doing &*.
It is difficult to tell from your question what the exact error is, but it seems likely that the root cause is "array decay".
In C++ (and in C), array arguments are almost always treated as pointers to the start of the array. For a multidimensional array, this means that the multiple-indexing you expect can't work, because the language has stripped away the size and shape information necessary.
The sole exception is that reference parameters do not decay in this way. However, if you rely on this, you (and anyone else who works on your code) will need to remember to use that exact reference parameter every time they pass the multidimensional array to another function.
In modern C++, this issue is typically fixed using std::array<>, which was designed for the purpose. In your case, that would be very verbose, so I'd suggest a type alias:
typedef std::array< std::array< std::array<SDL_Rect,
ANIMATION_FRAMES>, TOTAL_DIRECTIONS>, TOTAL_ACTIVITIES> SpriteClip;
std::vector<SpriteClip> gSpriteClips;
Alternatively, you could write a short class:
class SpriteClip {
SDL_Rect m_data[TOTAL_ACTIVITIES][TOTAL_DIRECTIONS][ANIMATION_FRAMES];
public:
SDL_Rect& get(activity, direction, frame) {
return m_data[activity][direction][frame];
}
};
This would let you change the representation easily -- for example, if you decided that you wanted different sprites to have different numbers of activities and frames.

What data structure is prefered instead of manipulating multiple vectors

I have implemented a class that makes computations on images. The processing is being done on a subset of the given images (lets say 100 out of 1000) at a time and each image takes a different number of iterations to finish. The processing uses GPUs and therefore it is not possible to use all the images at once. When the processing of an image is finished then this image is removed and another one is added. So I am using three different vectors image_outcome, image_index, image_operation to keep infromations about the images:
The image_outcome is a std::vector<float> and each of its elements is a value that is used as a criterion to decide when the image is finished.
The image_index is a std::vector<int> that holds the index of image in the original dataset.
The image_operation is a std::vector<MyEnumValue> that holds the operation that is used to update the image_outcome. Is of an enum type and its value is one of many possible operations.
There are also two functions, one to remove the finished images and one to add as many images as removed (if there are still enough in the input).
The remove_images() function takes all three matrices and the image matrix and removes the elements using the std::vector.erase().
The add_images() takes again the three matrices and the image matrix adds new images and the relevant information to the vectors.
Because I am using an erase() on each vector with the same index (and also a similar way to add) I was thinking to:
Use a private struct that has three vectors (nested struct).
Use a private class that is implemented using three vectors (nested class).
Use a different data-structure other than vec.
A hight-level example of the code can be fund below:
class ComputationClass {
public:
// the constructor initializes the member variables
ComputationClass();
void computation_algorithm(std::vector<cv::Mat> images);
private:
// member variables which define the algorithms parameters
// add_images() and remove_images() functions take more than these
// arguments, but I only show the relevant here
add_images(std::vector<float>&, std::vector<int>&, std::vector<MyEnumValue>&);
remove_images(std::vector<float>&, std::vector<int>&, std::vector<MyEnumValue>&);
};
void ComputationClass::computation_algorithm(std::vector<cv::Mat> images) {
std::vector<float> image_output;
std::vector<int> image_index;
std::vector<MyEnumValue> image_operation;
add_images(image_output, image_index, image_operation);
while (there_are_still_images_to_process) {
// make computations by updating the image_output vector
// check which images finished computing
remove_images(image_output, image_index, image_operation);
add_images(image_output, image_index, image_operation);
}
}
I think, instead of a struct with 3 vectors, a single vector of user-defined objects would work better.
std::vector<MyImage> images;
class MyImage {
Image OImage; // the actual image
float fOutcome;
int dIndex;
MyEnumValue eOperation;
bool getIsDone() {
return fOutcome > 0; // random condition
}
}
You can add to vector or erase from vector with a condition
if( (*it).getIsDone() ) {
VMyVector.erase( it );
}
In my opinion, maintaining 3 vectors that go parallel is easy to make mistakes and hard to modify.

C++ Syntax: Add new vector to a list

Ok, so this is a bit complicated and my syntax memory sucks...
I have a list which holds vectors of objects called "Plane".
Here:
std::list<std::vector<Plane>> possible_planes;
Plane is a class I made.
What I am trying to do now is add new entries to that.
So something like this:
possible_planes.push_back(std::vector<Plane> new Plane(boundRect[i].area(), center[i]));
And here is where I fail to get the syntax right. What does the correct syntax look like?
You code is declaring a variable in the middle of an expression, as well as dynamically allocating when it should not be. Try this:
possible_planes.push_back(std::vector<Plane>());
possible_planes.back().push_back(Plane(boundRect[i].area(), center[i]));
Note, this could be reduced even more if I knew you were using a C++11 compliant toolchain.
1. first create new vector, then add the plane
possible_planes.push_back(std::vector<Plane>());
possible_planes.back().push_back(Plane(boundRect[i].area(), center[i]));
2. have a function like this one
std::vector<Plane> createNewPlaneVector(Plane& plane) {
std::vector<Plane> result;
result.push_back(plane);
return result;
}
then you can add then new vector in one line
possible_planes.push_back(createNewPlaneVector(Plane(boundRect[i].area(), center[i])));
If you are using C++11 then this gets simpler:
possible_planes.push_back(std::vector<Plane>() { Plane(boundRect[i].area(), center[i]) } );
Maybe try doing it with multiple lines and variables, like this:
vector<Plane> newPlane; // Vector you add to list later
Plane myPlane; // Your object
// Do what you want with your Plane object
newPlane.push_back(myPlane); // Insert your object to vector
possible_planes.push_back(newPlane); // Insert vector to list

Initialize a Matrix of Pairs in Constructor

I'm creating a boardgame (Tzaar if curious :D) in openGL and I need to initialize my logical board with the starting pieces in each place.
In my Game classe I have the following variable:
std::pair<char,int> logicBoard[17][9];
and want to initialize it in the constructor following somewhat this example:
logicBoard[][] = {
{(0,0),(0,0),(0,0),(0,0),('z',1),(0,0),(0,0),(0,0),(0,0)},
{(0,0),(0,0),(0,0),('c',1),(0,0),('z',1),(0,0),(0,0),(0,0)},
{(0,0),(0,0),('c',1),(0,0),('y',1),(0,0),('z',1),(0,0),(0,0)},
{(0,0),('c',1),(0,0),('b',1),(0,0),('y',1),(0,0),('z',1),(0,0)},
{('c',1),(0,0),('b',1),(0,0),('x',1),(0,0),('y',1),(0,0),('c',1)},
{(0,0),('b',1),(0,0),('a',1),(0,0),('x',1),(0,0),('b',1),(0,0)},
{('z',1),(0,0),('a',1),(0,0),('z',1),(0,0),('a',1),(0,0),('c',1)},
{(0,0),('y',1),(0,0),('c',1),(0,0),('c',1),(0,0),('b',1),(0,0)},
{('z',1),(0,0),('x',1),(0,0),(0,0),(0,0),('a',1),(0,0),('c',1)},
{(0,0),('y',1),(0,0),('z',1),(0,0),('z',1),(0,0),('b',1),(0,0)},
{('z',1),(0,0),('x',1),(0,0),('c',1),(0,0),('x',1),(0,0),('c',1)},
{(0,0),('y',1),(0,0),('a',1),(0,0),('x',1),(0,0),('y',1),(0,0)},
{('z',1),(0,0),('b',1),(0,0),('a',1),(0,0),('y',1),(0,0),('z',1)},
{(0,0),('c',1),(0,0),('b',1),(0,0),('y',1),(0,0),('z',1),(0,0)},
{(0,0),(0,0),('c',1),(0,0),('b',1),(0,0),('z',1),(0,0),(0,0)},
{(0,0),(0,0),(0,0),('c',1),(0,0),('z',1),(0,0),(0,0),(0,0)},
{(0,0),(0,0),(0,0),(0,0),('c',1),(0,0),(0,0),(0,0),(0,0)}
};
But since I'm not so in depth of C++, don't know the easiest way of doing so.
Want it to be easily modified too since the board will be sent to Prolog (with the game logic) program through sockets, so it returns the modified board again to this variable.
Why not use a Container to better management of your pairs?
It would be like this:
std::vector< std::pair<char,int> > logicBoard;
logicBoard.push_back({0, 1});
logicBoard.push_back({'c', 1});
And so on...
This way if you ever need, lets say, the size of your "array" you can simply use logicBoard.size();
I would define a typedef, and here is a compilable snippet
typedef std::pair<char,int> P;
P logicBoard[17][9] = {
{P(0,0),P(0,0),P(0,0),P(0,0),P('z',1),P(0,0),P(0,0),P(0,0),P(0,0)},
{P(0,0),P(0,0),P(0,0),P('c',1),P(0,0),P('z',1),P(0,0),P(0,0),P(0,0)},
{P(0,0),P(0,0),P('c',1),P(0,0),P('y',1),P(0,0),P('z',1),P(0,0),P(0,0)},
{P(0,0),P('c',1),P(0,0),P('b',1),P(0,0),P('y',1),P(0,0),P('z',1),P(0,0)},
{P('c',1),P(0,0),P('b',1),P(0,0),P('x',1),P(0,0),P('y',1),P(0,0),P('c',1)},
{P(0,0),P('b',1),P(0,0),P('a',1),P(0,0),P('x',1),P(0,0),P('b',1),P(0,0)},
{P('z',1),P(0,0),P('a',1),P(0,0),P('z',1),P(0,0),P('a',1),P(0,0),P('c',1)},
{P(0,0),P('y',1),P(0,0),P('c',1),P(0,0),P('c',1),P(0,0),P('b',1),P(0,0)},
{P('z',1),P(0,0),P('x',1),P(0,0),P(0,0),P(0,0),P('a',1),P(0,0),P('c',1)},
{P(0,0),P('y',1),P(0,0),P('z',1),P(0,0),P('z',1),P(0,0),P('b',1),P(0,0)},
{P('z',1),P(0,0),P('x',1),P(0,0),P('c',1),P(0,0),P('x',1),P(0,0),P('c',1)},
{P(0,0),P('y',1),P(0,0),P('a',1),P(0,0),P('x',1),P(0,0),P('y',1),P(0,0)},
{P('z',1),P(0,0),P('b',1),P(0,0),P('a',1),P(0,0),P('y',1),P(0,0),P('z',1)},
{P(0,0),P('c',1),P(0,0),P('b',1),P(0,0),P('y',1),P(0,0),P('z',1),P(0,0)},
{P(0,0),P(0,0),P('c',1),P(0,0),P('b',1),P(0,0),P('z',1),P(0,0),P(0,0)},
{P(0,0),P(0,0),P(0,0),P('c',1),P(0,0),P('z',1),P(0,0),P(0,0),P(0,0)},
{P(0,0),P(0,0),P(0,0),P(0,0),P('c',1),P(0,0),P(0,0),P(0,0),P(0,0)}
};
BTW depending on your Prolog interface that should be adaptable to actually exchange values. In case, maybe you want to keep P lowercase.

Dynamic multi-dimensional array

I have to create a three-dimensional array using class A as element ,class A is defined like below, should I use vector<vector<vector<A> > > or boost::multi_array? Which one is better?
struct C
{
int C_1;
short C_2;
};
class B
{
public:
bool B_1;
vector<C> C_;
};
class A
{
public:
bool A_1;
B B_[6];
};
If you know the size of all three dimensions at the time, that you write your code, and if you don't need checking for array bounds, then just use traditional arrays:
const int N1 = ...
const int N2 = ...
const int N3 = ...
A a[N1][N2][N3]
If the array dimensions can onlybe determined at run time, but remain constant after program initialization, and if array usage is distributed uniformly, then boost::multi_array is your friend. However, if a lot of dynamic extension is going on at runtime, and/or if array sizes are not uniform (for example, you need A[0][0][0...99] but only A[2][3][0...3]), then the nested vector is likely the best solution. In the case of non-uniform sizes, put the dimension, whose size variies the most, as last dimension. Also, in the nested vector solution, it is generally a good idea to put small dimensions first.
The main concern that I would have about using vector<vector<vector<A> > > would be making sure that the second- and third-level vectors all have the same length like they would in a traditional 3D array, since there would be nothing in the data type to enforce that. I'm not terribly familiar with boost::multi_array, but it looks like this isn't an issue there - you can resize() the whole array, but unless I'm mistaken you can't accidentally remove an item from the third row and leave it a different size than all of the other rows (for example).
So assuming concerns like file size and compile time aren't much of an issue, I would think you'd want boost::multi_array. If those things are an issue, you might want to consider using a plain-old 3D array, since that should beat either of the other two options hands-down in those areas.