KAZESUI'S PROFILE
Search
Filter
[RM2K3] DynRPG Compiling Error
Scope here refers to variable life time, and is something which goes back to the stack vs heap thing again. Variables declared in a function generally have that function as their scope.
However, stuff on the heap (or global memory, like your std::map variables) can be changed at arbitrary points of the code. If you really showed the full function in that snippet, then there should be some issues with it, since the text images never get freed up or reset.
once this you enter this if, and create an image for myText, it should never be entered again for that specific index (e.g. once you create a text for i = 0, it should never be entered whenever i = 0 the next time you enter the loop), since the image has already been created and will return always return true, which becomes false after the negation from '!'. Note that the negation operator will only be applied toand not to both since the negation operator has a higher precedence than the 'logical and' operator '&&'. You could apply it to both by using a parenthesis, but then you get a memory leak instead. As mentioned, these variables are never destroyed automatically, since myText is global.
Unless these images are freed somewhere else in the code, then this should mean that you should be running into issues after having gone through one battle with one set of enemies and then encountering a new set of enemies. (If you have the same enemies, i.e. 4 king slimes in every battle, you'll probably not notice this issue).
If the images are freed, then that's not in the code snippet and that's why I'm not able to assess properly if there are issues with regards to memory management.
However, stuff on the heap (or global memory, like your std::map variables) can be changed at arbitrary points of the code. If you really showed the full function in that snippet, then there should be some issues with it, since the text images never get freed up or reset.
if(!myText[i] && RPG::monsters[i]) //Checks is there is a valid Image object and associated Monster exists.
once this you enter this if, and create an image for myText, it should never be entered again for that specific index (e.g. once you create a text for i = 0, it should never be entered whenever i = 0 the next time you enter the loop), since the image has already been created and will return always return true, which becomes false after the negation from '!'. Note that the negation operator will only be applied to
myText[i]
myText[i] && RPG::monsters[i]
Unless these images are freed somewhere else in the code, then this should mean that you should be running into issues after having gone through one battle with one set of enemies and then encountering a new set of enemies. (If you have the same enemies, i.e. 4 king slimes in every battle, you'll probably not notice this issue).
If the images are freed, then that's not in the code snippet and that's why I'm not able to assess properly if there are issues with regards to memory management.
[RM2K3] DynRPG Compiling Error
Can't address too many of the earlier points mentioned, as scope is pretty important for these questions, and the scope is not contained in these snippets.
The code presented looks fine I would say. No need for optimization at this point.
And no, I don't see any obvious way to alter the damage itself, though instead of swapping the skill, you might be able to just alter the skill / spell itself directly for when a critical is supposed to happen, and change it back afterwards.
e.g. Do the check if it is supposed to cause a critical with onDoBattlerAction(), and change the skill if so, and then change it back to default with onBattlerActionDone(). This might even be safer than swapping skills during the battle, though I'm not sure how this would be best implemented, or the exact order in which calculations take place, so a different order of things might be required.
The code presented looks fine I would say. No need for optimization at this point.
And no, I don't see any obvious way to alter the damage itself, though instead of swapping the skill, you might be able to just alter the skill / spell itself directly for when a critical is supposed to happen, and change it back afterwards.
e.g. Do the check if it is supposed to cause a critical with onDoBattlerAction(), and change the skill if so, and then change it back to default with onBattlerActionDone(). This might even be safer than swapping skills during the battle, though I'm not sure how this would be best implemented, or the exact order in which calculations take place, so a different order of things might be required.
[RM2K3] DynRPG Compiling Error
It's perfectly fine to use if statements this way, and is even a standard way of doing it (I do this in my plugins as well). I'm just stressing the importance of setting it to NULL after calling destroy since the if statement won't generally work if you don't do this. The program itself does not know if there is an object or not at the end of the address during runtime, it just goes to wherever the address points and tries to access data as if it would be an object of the type defined by the pointer type. Upon trying to access data which the OS tells the program it does not have access to (because it has been de-allocated or never allocated in the first place), it will throw an exception and crash the program.
If you make sure to always reallocate memory for the image before this becomes a problem, you won't run into issues, but then you don't need the if statement either.
You do not need to initialize a pointer to NULL if you give it an address shortly after creation. You DO need to set it to NULL if you have an if statement checking the content of the pointer before it has been given an address however, because variables in c++ do not assume 0 or NULL as a default value.
e.g. if we alter the code from my previous example accordingly, we'll crash at the first if already
Telling you exactly what to do is hard without having the full source / context itself, but assuming that the if statements make sense, then you should probably also set the pointers to NULL after you destroy them.
If you make sure to always reallocate memory for the image before this becomes a problem, you won't run into issues, but then you don't need the if statement either.
You do not need to initialize a pointer to NULL if you give it an address shortly after creation. You DO need to set it to NULL if you have an if statement checking the content of the pointer before it has been given an address however, because variables in c++ do not assume 0 or NULL as a default value.
e.g. if we alter the code from my previous example accordingly, we'll crash at the first if already
RPG::Image* img; if(img) // img is not NULL, which evaluates as true, so this branch will now be entered RPG::screen->canvas->draw(x, y, img); // This should crash now img = RPG::Image::create(); RPG::Image::destroy(img); if(img) //img is likely not NULL, which evaluates as true, so this branch will be entered RPG::screen->canvas->draw(x, y, img); // This will likely crash
Telling you exactly what to do is hard without having the full source / context itself, but assuming that the if statements make sense, then you should probably also set the pointers to NULL after you destroy them.
[RM2K3] DynRPG Compiling Error
author=McBickWon't this try to change the value of an object that doesn't exist and crash?RPG::Image::destroy(myImage[0]); ... myImage[0] = NULL; //Won't this crash? ...
Let me try to illustrate with code
RPG::Image* img; // at this point, img contains random numbers img = NULL; // Sets the address in img to NULL, meaning it is not pointing at anything img = RPG::Image::create(); // create() allocates memory for an image, and returns the address to that memory RPG::Image::destroy(img); // destroy() goes to the address stored in img, and deallocates the memory. Probably does not remove address at this point img = NULL; // Manually sets the address to NULL to reaffirm that the pointer is not pointing at anything.
Note that img never has the value of an object, but just the address to a point in memory which can be used to retrieve the object, and values within it. Of course, when you set a pointer to NULL, you cannot access anything from the object either (as there is no object), but you can't do that after destroying the image anyway (accessing deallocated memory will cause the program to crash).
The benefit of doing this is that
RPG::Image* img = NULL; if(img) // img is NULL, which evaluates as false, so this branch will never be entered RPG::screen->canvas->draw(x, y, img); // This would normally crash, but here will never be executed img = RPG::Image::create(); RPG::Image::destroy(img); if(img) //img is likely not NULL, which evaluates as true, so this branch will be entered RPG::screen->canvas->draw(x, y, img); // This will likely crash
You can use if statements to check if the pointer has been allocated like this.
Also note that NULL is a value which can be set to every pointer variable, regardless of type.
[RM2K3] DynRPG Compiling Error
This is fine as long as you keep in mind what I mentioned, i.e.
For this reason, and because it is a good habit as well, I would adjust your code to
since doing this, ensures that your if(img) will always be valid (or whatever other pointer you might be using at some point).
RPG::Image* img = RPG::Image::create(); img->loadFromFile(loc); RPG::Image::destroy(img); if(img) RPG::screen->canvas->draw(x, y, img); // This will probably crash
For this reason, and because it is a good habit as well, I would adjust your code to
if(RPG::battleData->battlePhase == RPG::BPHASE_END) //This would be in the callback onFrame { RPG::Image::destroy(myImage[0]); RPG::Image::destroy(myImage[1]); ... myImage[0] = NULL; myImage[1] = NULL; ... }
since doing this, ensures that your if(img) will always be valid (or whatever other pointer you might be using at some point).
[RM2K3] DynRPG Compiling Error
author=McBick
I thought transitioning through scenes cleared the canvas and any graphical objects were also cleared away as well, but it seems I was wrong. If I were to do something like this:if(myImage[i]) { RPG::Image::destroy(myImage[i]); } if(!myImage[i]) { myImage[i] = RPG::Image::create(); myImage[i]->loadFromFile(loc); }
This should essentially destroy the Image before creating a new one. The point of this would be if the battle ended without destroying the Image object then it would be destroyed during the next battle when the relevant Image is to be created again, so there won't be duplicates, or a memory leak.
Rather than doing this, maybe you use the callback "onInitFinished", Then you create all the images you intend to use (assuming you do not want to use too many different types of images). Doing this means you do not have to check with an if statement if there is an image in your array and you will not have to delete it. If RPG::Image::create is only used within this callback it will not cause any memory leaks. This is probably the easiest and safest way to do it (at the expense of eating a little bit more RAM than if you would allocate this dynamically as the need arises, but with the sizes used by rm2k3 and the setups of today, this is unlikely going to be a problem anyway).
You could try it your way as well, but that would be the point where you will start running it runtime errors, exactly because your if statement does not check if you've allocated a space for your image, it just checks if the pointer is set to 0 / NULL. It is possible that "RPG::Image::destroy" does this for you, but there is no guarantee of this, and there's a good chance the pointer will have the address of where the image used to be, but no is not anymore because it was destroyed. This address is not equal to 0 / NULL, so it will pass the if and try to destroy an image which has already been destroyed and will fail since there is no more image there.
You should add
myImage[i] = NULL;
or something similar after you call RPG::Image::destroy to be more certain.
Of course, I assume these two if statements of yours are not placed that close in the real code, as destroying and creating an image each frame is not good either, which is what would happen if they were this close.
[RM2K3] DynRPG Compiling Error
RPG::Image::create() allocates memory on the heap, not in the stack. Also transitioning from between scenes (for example from Battle to the Map) does not destroy any RPG::Image data. If you do not call free() before calling RPG::Image::create() again, you will create a memory leak.
That said, as long as you keep the image creation behind and if like this and you simply re-use the images already drawn with some logic as to when they are supposed be drawn, you do not really need to delete them manually. While scene changes will not remove any images, closing the game will free this memory as well.
If you want to test this a little bit more easily, find a really big picture which you load into your plugin, and then monitor the task manager. The bigger the better, as this will help you notice if there's anything there (as long as your logic is generic enough to allow for a test like this without becoming too artificial). That said, it might be safe as is as well, even if there is a memory leak if it is that tiny.
That said, as long as you keep the image creation behind and if like this and you simply re-use the images already drawn with some logic as to when they are supposed be drawn, you do not really need to delete them manually. While scene changes will not remove any images, closing the game will free this memory as well.
If you want to test this a little bit more easily, find a really big picture which you load into your plugin, and then monitor the task manager. The bigger the better, as this will help you notice if there's anything there (as long as your logic is generic enough to allow for a test like this without becoming too artificial). That said, it might be safe as is as well, even if there is a memory leak if it is that tiny.
[RM2K3] DynRPG Compiling Error
Theoretically, if you want to store an array of pointers of different types, you can convert all of these pointer to "void*". But once you want to access the content of the pointer, you need to know the type of the pointer.
Note that the example is more pedagogical than practical, but that would be a conceptual way to deal with arbitrary pointer types. Also, beware that there could be some syntax errors in there, as I don't have a compiler at hand to actually test the code at the moment. This is pretty much what Polymorphism is about as well, expect that this is a more common C way of doing things rather than C++.
Void pointers can be useful for writing more general functions, but keep in mind that you cannot dereference a void pointer. You need to convert it to something else before trying to read the value of the address (otherwise, the program won't know how many bytes are needed to interpret the value stored at that address).
Also note that if the value itself is const, it won't matter if you create a copy of the pointer pointing to the address of the value, as the value will still be const.
Edit: changed the first code snippet a little bit to make it somewhat more practical for the actual use-case
// Store relevant pointer types here enum ptr_types{ INT, BOOL }; // Define struct which contains arbitrary pointer type and what type it is struct t_ptr{ void* ptr; ptr_types ptr_type; }; int a = 42; bool b = True t_ptr ptr_a; t_ptr ptr_b; ptr_a.ptr = reinterpret_cast<void*>(&a); ptr_b.ptr = reinterpret_cast<void*>(&b); ptr_a.ptr_type = ptr_types::INT; ptr_b.ptr_type = ptr_types::BOOL; std::vector<t_ptr> ptr_list; // declares a common array for all your funky pointers ptr_list.append(ptr_a); ptr_list.append(ptr_b); int a2; bool b2; for(int i = 0; i < ptr_list.size(); i++) { switch(ptr_list[i].ptr_type) // The switch statement tells the code to continue to execute { case ptr_types::INT // If ptr_type is an int, convert the void* to an int* a2 = *reinterpret_cast<int*>(ptr_list[i]); // a2 should now be set to 42 break; // tells the code to exit the switch. Code will break otherwise case ptr_types::BOOL b2 = *reinterpret_cast<bool*>(ptr_list[i]); // b2 should now be set to true break; default break; // in case the ptr_list[i].ptr_type contains a ptr_type not listed } }
Void pointers can be useful for writing more general functions, but keep in mind that you cannot dereference a void pointer. You need to convert it to something else before trying to read the value of the address (otherwise, the program won't know how many bytes are needed to interpret the value stored at that address).
Also note that if the value itself is const, it won't matter if you create a copy of the pointer pointing to the address of the value, as the value will still be const.
const int a = 42; int* ptr_a = &a; int* ptr_b = ptr_a; *ptr_a = 1337; // This is not allowed *ptr_b = 1337; // This is also not allowed for the same reason int c = a; // This sets 'c' to 42 int* ptr_c = &c; *ptr_c = 1337; // This is allowed and sets 'c' to 1337. 'a' remains 42
Edit: changed the first code snippet a little bit to make it somewhat more practical for the actual use-case
[RM2K3] DynRPG Compiling Error
ptrB is already a pointer so there's no need to use the & operator when wanting to copy the address. You can change from one type to another using reinterpret_cast, but the results might not be too intuitive.
A better approach might be to get into "why" you want to do this, or what you want to achieve with this
For the concrete example
Note that there is a good chance that the third line will fail, since a bool will generally have 1 byte allocated to it, while an integer expects 4 bytes, meaning it might try to read 4 bytes of data, which can lead to a segmentation fault, or to some very peculiar errors if the memory has been allocated.
Better yet would be to do (I think there's a good chance that it will compile, but that int a will receive an undefined value. I just don't remember exactly how this would play out)
uint8 means an unsigned integer of 1 byte. That it is unsigned means that it can store no negative values (does not apply to float types) and int8 refers to 8 bits beings used for the integer.
Note however that uint8 can only store numbers from (and including) 0 to 255
A better approach might be to get into "why" you want to do this, or what you want to achieve with this
For the concrete example
bool b = true; bool* ptrB = &b; int* ptrA = reinterpret_cast<int*>(ptrB); int a = *ptrA; // if the step above works, 'a' might now be set to 1 (or something random)
Better yet would be to do (I think there's a good chance that it will compile, but that int a will receive an undefined value. I just don't remember exactly how this would play out)
bool b = true; bool* ptrB = &b; uint8* ptrA = reinterpret_cast<int*>(ptrB); uint8 a = *ptrA; // a should be set to 1
uint8 means an unsigned integer of 1 byte. That it is unsigned means that it can store no negative values (does not apply to float types) and int8 refers to 8 bits beings used for the integer.
Note however that uint8 can only store numbers from (and including) 0 to 255
[RM2K3] DynRPG Compiling Error
author=McBickThis would work (assuming namespace and class are both valid)author=KazesuiThis confuses me. To clarify, doing this would not work:
1. RPG::Battler is a class definition, not a variable. You cannot take the address of a class definitionNamespace::Class* Ptr;
RPG::Battler* battler_ptr_a; // this should work RPG::Battler* battler_ptr_b = battler_ptr_a; // this should also work RPG::Battler* battler_ptr_c = &RPG::Battler // this does not work int* battler_ptr_d = &battle_ptr_a // this does also not work int* battler_ptr_e = battle_ptr_a // nor should this
author=McBick
Would something like this be okay:battler* actor; //I'm pretty sure this will error. // NOTE: (Correct, battler is not a class definition, but an object of RPG::Battler. You cannot declare a variable as the type of another variable) int hp = actor->hp;
If you change the code to this, it should work (added callback for clarity)
bool onBattlerDrawn(RPG::Battler *battler, bool isMonster, int id) { RPG::Battler* actor; actor = battler; int hp = actor->hp; }
RPG::Battler* battler; RPG::Battler *battler;
author=McBickNo need for the extra layers or & and * since they negate each other. What I showed up there was to demonstrate the differences while also showing how they are kind of the inverse of each other.
If not, is there a good way to copy pointers? For example making PtrA reference the same address as PtrB? I am guessing I would have to do something like this:int n = 8; int* PtrA = &n; int* PtrB = &(*PtrA); //This should give PtrB the same address as PtrA?
int n = 8; int* ptrA = &n; // Again, these are variables, so they should start with a lowercase letter int* ptrB = ptrA; //This this copies the address of ptrA into ptrB
author=KazesuiIf that "anything" is not memory mapping, then no, you should not use this. You're only going to confuse yourself further without gaining much from it, and it will most certainly not cut down code length. If anything, it will add code length and complexity and severely decrease readability of the code, even when done right.
Now, if you're really bent on converting it to something else, what you could do isauthor=McBickThis looks interesting. I will have to experiment with this to see if I can use this for anything or cut some of my code down with it.
int* actor = reinterpret_cast<int*>(battler);
int actor_value = *actor;