Jump to content

  • Log In with Google      Sign In   
  • Create Account


Member Since 22 Aug 2001
Offline Last Active Mar 07 2016 04:10 AM

#5078370 Function addresses are not fixed relative to each other?

Posted by on 16 July 2013 - 10:13 PM

When you cast your function pointers to integers, I'd always preclude that with a static-assertion testing that the size of your function pointer type is smaller or equal to the size of your int type.


Of course, if I really have to use printf to output any kind of pointer, I'd just use %p in the first place...

#5078047 Problem with strings

Posted by on 15 July 2013 - 10:27 PM

Which is why a / should be used as a path separator whenever possible (yes, even on Windows). There are extremely few cases where it won't work.

#5077017 Organizing Source Files

Posted by on 11 July 2013 - 10:08 PM

I'd generally prefer the ProjectDir (which also seems to be the "default" as in "what your path is relative to if you don't specify anything). Nothing more frustrating than adding a project as a dependency to a different solution and having all your paths fall apart.

#5074338 Header Files

Posted by on 30 June 2013 - 10:25 PM

Ah, surprisingly I am often amazed that even many "professional" programmers have no idea how this works in detail. There will be a big step back to explain the two phases of making an executable.


Compiling: every .c/.cpp/.cc (whatever your source files are called) is compiled in complete isolation. It knows absolutely nothing about the content of any other source file. This will usually create one compiled object file for every source file.


Linking: this pieces together all the object files into one big executable binary. This is also the step where every function that is being called must exist in one (and exactly one) object file (or one of the linked libraries). Same goes for global or static member variables.


Another important distinction is "declaration" vs. "definition". A header should usually contain only declarations (or inline code). Declarations say "this thing exists somewhere", while a definition says "this right here IS the thing". For global variables, "extern" is used to tell a declaration from a definition. For functions this difference is having or not having a function body.



So headers are a) never compiled on their own and b) are completely irrelevant for linking. They are needed to be able to compile source files that are using or referencing stuff that is "somewhere else". However, these are only declarations. Also, linker errors will never ever be fixed by touching #includes (except maybe by removing them if your compiler is seriously trying to link stuff that is never actually used).


There is also the issue of circular includes. If your includes ever start going around in circles, this is a bug and no, inclusion guards have nothing to do with it and won't fix that. The only solution is to not them and use forward declarations to break them up (using forward declarations as much as possible in header files is generally preferable anyway, especially when it comes to compile times). This is also one big reason why not to spam includes all over the place in header files, just in case they _might_ be needed or out of sheer convenience (my favorite quote from a coworker "but this is way easier, so everyone including this header automatically gets all the other stuff".. uhm, yes, including all the stuff they don't need, that might result in conflicts and will blow up compile times by a few multitudes).



So random guesses:

-your header includes something, but not RakNetTypes.h

-your header is trying to include itself

-the header isn't found and you are not looking at the error messages starting at the top

-there is a typo in the identifier

#5073121 Static Initialization and Ctors

Posted by on 26 June 2013 - 09:38 PM

If you really and absolutely must have the map as a global, wrap it in a function so it is guaranteed to get initialized on the first call. Though "is there really no better way" should always be asked before turning to Singletons. But usually having to do this for every map should be deterrent enough.


map<unsigned, SceneElement*>& someMap()
    static map<...> myMap;
    return myMap;

#5072390 Bill-boarding oriented rectangle

Posted by on 23 June 2013 - 10:26 PM

Building the objects transformation matrix yourself sounds like the easiest approach, except that the two vectors to build the rotation part from are p2-p1 and (to make it face the camera) camera.position - p1 (or any other point on the line).


From there you just get the third vector with a cross product and after that use another cross product between the first and third vector to "fix" the second one (to be orthogonal). Normalize all vectors and you should be done. In your matrix, the first vector is the x-axis, the third one is the y-axis and the second is z. That choice is arbitrary and only depends on how your rectangle is modeled (I assume x being along the length, y being the width and z being the normal vector facing the camera).


There is no manual scaling going on unless what you mean is that is has to scale itself to cancel out the scaling you get from perspective projection.


When you create the geometry, do _not_ center it around the origin or you're just making it pointlessly complicated to move it into position. Just use (0,width,0), (0,-width,0), (length,width,0) and ((length,-width,0).


That approach has worked perfectly fine to have a ton of laser beams flying around. At least it's how I remember it, since the whole project seems to have disappeared.

#5066055 Strange problem with delete with VS 2012.

Posted by on 29 May 2013 - 11:32 PM

In case "pointer" is a member of the object, I would be extremely worried if the bug disappears, just because it's set to null after delete. In fact, I would strongly advice _against_ setting member pointers to null in your destructor, exactly because it can hide more severe bugs. Doing so should have absolutely zero effect on program execution, unless something else is wrong (like deleting the actual object twice). In that case, reliably crashing is the best that can happen, as it clearly shows that something is wrong (instead of causing weird and inexplicable behavior down the road).

#5062193 c++ include define DIR

Posted by on 15 May 2013 - 10:03 PM

As mentioned above, there's a whole bunch of methods that are all better than abusing the preprocessor for this.


a) If stuff is versioned, why not use a version control system instead of folder names?

b) Failing that, the -I option exists for exactly that kind of thing (ie. it belongs in your project settings or Makefile, not the actual source code)

c) Use a symlink that points to whatever version you want to use (yes, Windows finally has them too)

#5062192 My ever-evolving coding style

Posted by on 15 May 2013 - 09:51 PM

Whenever writing a million getters and setters gets annoying, I usually ask myself two things:


a) if I just go and write trivial set/get methods for everything, why not just stop pretending and make it public?


b) why not be lazy and wrap it in a template that handles it?


class ...



   Property<int> stuff;



int value = obj.stuff();


obj.stuff( obj.stuff() + 5 );


Not calling it get and set allows to use the template for all trivial cases and do custom implementations where needed without requiring a different syntax.


Still, if a class has a dozen members and trivial accessors for all of them, encapsulation probably just went out the window. So it's more of a convenient way to remain consistent.

#5061418 tictac toe marks

Posted by on 12 May 2013 - 10:09 PM

Generally by giving them names and making them constants, but that only applies to numbers that _must_ be defined in the program and won't change at runtime. The resolution or window size for a PC application should not be a magic number or a constant, because you don't know what hardware people are using.


In your case: by learning how to use structs, arrays, loops and functions.


Just doing a find/replace and creating thousands of constants like "block1TopLeftX" and "block3BottomRightY" might get rid of magic numbers, but is also insanely silly, because a sane person would never want to hard code everything for every single block in every single level of a game like Breakout (which will be thousands or even a lot more). Always tell yourself "there will probably be a bug in this code, I don't want to fix the same bug in 10000 copies of this". In fact, writing the same snippet more than twice (at most) is usually a bad sign.


Force yourself to keep things flexible. Plan for change, write code that will work no matter if your game board is 3x3, 5x5 or any other size (somewhat limited by screen size) and don't assume you will always need 3-in-a-row. Make board and required row size a variable and don't use magic numbers or constants. Remove the option to just hard code everything and force yourself to think in algorithms instead of a huge list of if-elses.

#5060761 tictac toe marks

Posted by on 09 May 2013 - 10:50 PM

Sorry, I don't see any of these attempts of an "easy way out" working. Looking at this code and the breakout code, no amount of switching language, UML drawings or doing apps instead of games will allow avoiding to take a huge step back and learn some basic and fundamental programming first. That means understanding and knowing how and when to apply them, not "research" as in "I skimmed over a tutorial and compiled the code".


The code is an insane mess of copy/paste, arrays are used, but then stuff is just copied and hard coded for every field in the array, showing a complete lack of understanding WHY an array is used in the first place. 


Data that should be grouped in a class or struct is instead spread over a bunch of different arrays, functions are just doing all kinds of stuff. 


There's endless if/else-copy/paste replacing a simple division. 


Despite making the same mistake in the breakout thread, this function is again presenting an entire frame when it should just set a value (so I doubt that it was even understood what those magical D3D functions are actually doing). 


There is also no recognizable understanding of the difference between game logic and graphics. Graphical representation isn't the game, it's what you put ON TOP of the game, so a player can see what he's doing. The "core" of the game doesn't care about graphics, sprites, 2D/3D, keyboards or mice. Inputs are used to trigger functions of the game and graphics are used to display the state of the game.


You can't buy a Spanish dictionary, learn how to pronounce two or three words and then try to write an entire novel. You need to learn the grammar and rules, have a decent vocabulary and know common phrases and idioms.


In this case: you need to learn programming. The language here isn't C++ (or C#, Basic or any other specific language), it's basic programming concepts. Not just knowing what a loop looks like, but how to use them. Forget about GUI and 3D (or even 2D). Running requires knowing how to walk first. Otherwise you're not getting far and keep hurting yourself.


Planning for TicTacToe or a calculator by using ULM and flow charts is overkill. Maybe a nice practice, but if you need a flow chart to understand the game logic behind TicTacToe (of which 95% should be covered by a standard game loop), you are clearly overcomplicating a very simple thing. Frankly, at this point it seems more like avoiding the real issue rather than tackling it. Like constantly "taking a break from programming" it won't magically make you write better code.

#5059082 Code Review: Pong

Posted by on 03 May 2013 - 10:21 PM

One book had a very nice way to define comments in code. "Comments are the documented failure of a programmer to write clean and readable code".


That doesn't mean that some comments aren't justified. Explaining _why_ something is done in a way that seems weird is often useful ("working around a bug in compiler x", "doing it like this for performance reasons"). Mentioning what the code does on a _higher level_ ("using optimized algorithm from <some link>").


Avoid comments where possible, because most of the time they are outdated by the time you finish typing them, will be confusing more than helping after two weeks and turn into flat out nonsense another few weeks later. Unless your team exists of super disciplined programmers that will always also maintain the comments, no matter how closely that deadline is looming above them.


I'm also not a fan of aligning your assignments. It's not about looking pretty or creating an excel sheet. If stuff is indented so far that you need to bring a ruler to find out which value belongs where, then things just got counter productive. I find it much more useful to insert a blank line to separate blocks that logically belong together.


Besides, having big blocks of assignments is often indicating a different problem. Not getting over the C habit of declaring everything at the start of a function.


For reset or init of simple classes (mostly data, nothing fancy in constructor/destructor), it can often be more convenient to just assign a default constructed object ("object = Object()"). It's also a lot more robust, since you can't forget variables, don't have to touch multiple sections of code when adding new variables and it's immediately obvious to someone reading the code.

#5056554 isNearZero( Vector)

Posted by on 24 April 2013 - 10:21 PM

If it's just for assertions, why pepper the code with a ton of if's, instead of just doing "return dot(v,v) < eps"? I'd imagine a dot product and one comparison to be not just shorter and easier to read, but also a good bit faster. Only thing to keep in mind is that this returns the squared length, but that shouldn't really matter much.

#5056266 Multiple types in a map container C++

Posted by on 23 April 2013 - 10:34 PM

I'm confused. You say it's _exactly_ 9 slots and they are _consecutively_ numbered 0-8? At which point did that make you think "map<int, ptr>" instead of "array<ptr, 9>"?


Why fill it with dummy instances and loop through all the pointers and call functions on them, instead of just checking them for 0?


And why even do that, instead of just adding a simple "numItems" variable to box that keeps track of the next free slot?



class Box
    Box() : numItems(0) {}
    void addItem(shared_ptr<Item> item)
         if (numItems < 9)
              items[numItems++] = item;
   std::array<shared_ptr<Type>, 9>;


Why pass a shared_ptr? Because in your code you never check if the item was successfully added. You ownership is completely unknown at this point. If you delete it at the calling site and it was added -> access violation. If you don't delete it and it wasn't added -> memory leak.


Why a shared_ptr? Without knowing the usage of that box, it is safer to allow code that is currently using an item from the box to keep it alive, just in case it gets removed from the box in between. Using a smart pointer also means there is no need to explicitly delete an object in the box before replacing it (if that is even a use case).



Your main function (as explained above) also has a big issue.



int main()
     Box myBox; //This has no business being a pointer in the first place
     myBox.addItem(make_shared<ItemA>("Steve", 0, "is a man", 4, 6, 7, 17, 8, 3.4f);



The real problem is of course trying to stuff two completely unrelated types into the same container. Why? It will just result in a huge mess of if/else and dynamic_casts or getType(). Put them in two different arrays and let the box class hide that fact. Of course if you ever want to access an item in the box, you're back to the same problem. What type should that function return?


Generally you want to hide all members and use a _common_ interface for A and B. Depending on what they are supposed to do, try to abstract that. You want them to print their data? Have a virtual function "print" in both of them (and the base class). Don't even think about placing that code outside the classes and have it rip the data from their guts.

#5053330 Is this overkill? Potentially error-prone?

Posted by on 14 April 2013 - 09:54 PM

This should not be. The data and functionality should be only related to the character, nothing more. I might be reading the 'functionality and data related...' part to literally though. What I gather from this is you have functionality in the character class that operates on things that are not the character. If so, then you need to break this into another function that takes the character and the thing it is acting on into a completely different function.


Should have been more specific, This isn't what I meant.  I just meant that a character can do a whole lot of things, the current character class contains methods that do things like attack, buying and selling items, moving from one place to another on the world map, moving from one tile to another on the battle map, talking to an npc, etc.  My meaning was that my characters have a lot of functionality that, while certainly should be owned by the Character class, is often dependent on very distinct parts of the game.  But the class is BIG, and that's ultimately the problem I'm trying to solve.


Those are actually very good examples of things that should probably not be in the character class. Generally you want to minimize your dependency on other classes and modules, doing everything at such a specific level is achieving the opposite. Why does your character need more than functions to add/remove gold and add/remove items? The whole process of buying or selling definitely does not need to be in the character class.


Moving around the world? If you just talk about changing position, then the position should be set from the outside. What if you want other objects to move around that aren't characters? Will you copy/paste the whole code? And if it includes path finding, that is again a generic and reusable thing that doesn't belong in a character class.


A conversation is also a thing of its own and while it might need references to two characters, I don't see why it should all be handled in a character class. Not everything that involves a character should be dumped in there. Especially in C++ one should seriously reconsider the urge to put every function into a class in the first place. Global functions that manipulate objects through their interface are not only "acceptable", but the best way to be modular and extendable, as you can add a whole ton of functionality without touching existing code (buyItem(Character& character, Shop& shop)).


Everytime you ask yourself "should this be part of class X or class Y, because it involves both of them" you should consider that the answer might be "neither".