|
Organizing All Your Files In A Project
#393694
02/06/12 12:47
02/06/12 12:47
|
Joined: Sep 2003
Posts: 353
Mahonroy
OP
Senior Member
|
OP
Senior Member
Joined: Sep 2003
Posts: 353
|
Hello, I recently started messing with A7 some more, and getting into the c-scripting, and had a couple questions.
1. How do you go about organizing your functions through multiple files? I started splitting everything up into multiple .c files, but am constantly running into problems with functions not being able to "see" other functions from other files due to their #define order at the top of my main file. Normally you would prototype all of your functions in a header file so that everything can see everything right? Do I need to make .h files with my prototypes? I have some global definitions (variables, entities, panels, etc.) that a lot of functions need access to, so do I just put all of that above my #defines? Or in another file? Would be cool if someone could show me the ways of organizing all this stuff.
2. Quick question regarding entity definition for a gun model (for a first person shooter weapon). What I had done in the past was create the "shotgun_onscreen", give it an albedo value, then I would do a "sun_angle.pan = my.pan;" in the player code. This way when you rotate, the shadows move around on your weapon thats on screen. This only works for indoor levels though, as the sun position is moving all over the place. Is there a better way of doing this? What are some methods you guys do to make your FPS guns look good?
Thanks, and any help is greatly appreciated!
|
|
|
Re: Organizing All Your Files In A Project
[Re: Mahonroy]
#393696
02/06/12 13:15
02/06/12 13:15
|
Joined: Jul 2001
Posts: 6,904
HeelX
Senior Expert
|
Senior Expert
Joined: Jul 2001
Posts: 6,904
|
Hi, here are some remarks for handling .c/.h files: 1) Make a .h file for each .c file and put only the functions into the .c file, all other stuff belongs into the .h file. Make a prototype for each function. 2) Then, in all .c files, only include .h files, which are necessary for the code in your .c file, like called functions, types, etc. In the correspponding .h file, only include .h files as well for the stuff which is necessary in the header file; this is mostly done for self defined types. 3) To enforce the right order of headers, add safe guards. If your file e.g. is named "myFile.h", this is it:
#ifndef myFile_h
#define myFile_h
//...
#endif /* myFile_h */
This ensures, that header files are only included once and at the very first position in your compiled code, when it is needed. 4) You might wonder where you include the .c files? Yes, I didn't mentioned that. That is a bit tricky, though. In Visual Studio, all .c files are compiled automatically, but in Lite-C only stuff will be compiled, that was included. So, since you only include in .c and .h files header files (.h), here is solution which works for me pretty well: each header includes the .c file at the very bottom, to ensure, that the code is inserted after the header data and prototypes: myFile.c:
#ifndef myFile_c
#define myFile_c
#include "myFile.h"
//...
#endif /* myFile_c*/
myFile.h:
#ifndef myFile_h
#define myFile_h
//...
#include "myFile.c"
#endif /* myFile_h */
This way, the code is included at the very first point in your code, where you need it. If the code itself needs code, it is included beforehand. And since I have different guards around the header and the code, neither code nor headers will be duplicated. [EDIT] For globals, try to maintain a clear syntax that points out, that they are globals. I always put a "g_" before the name of the global variable, like int g_lifes = 42; or so. This doesn't look pretty after all - you might ask "why don't writing "lifes" instead? ... Well, this is a valid question and I made the experience, that you often name local variables very "intuitively" and in some rare cases you might use the same name as a global variable and try to process both, which apparently doesn't work, because you use the local variable instead of the global one. This is very frustrating and rare, but you'll be glad if you can circumvent this.
Last edited by HeelX; 02/06/12 13:22.
|
|
|
Re: Organizing All Your Files In A Project
[Re: Mahonroy]
#393746
02/06/12 18:47
02/06/12 18:47
|
Joined: Jan 2002
Posts: 4,225 Germany / Essen
Uhrwerk
Expert
|
Expert
Joined: Jan 2002
Posts: 4,225
Germany / Essen
|
This is so important for beginners, it should become a part of the manual or the wiki.
Always learn from history, to be sure you make the same mistakes again...
|
|
|
Re: Organizing All Your Files In A Project
[Re: Mahonroy]
#393808
02/07/12 07:52
02/07/12 07:52
|
Joined: Jul 2001
Posts: 6,904
HeelX
Senior Expert
|
Senior Expert
Joined: Jul 2001
Posts: 6,904
|
Hi, the main.c includes, like all the other .c files only headers for the stuff needed in the main.c file. All included .h files include their code and all other dependencies become resolved; the list of .c/.h files will be generated automatically by the construction I posted above. Maybe this answers also your other question. If you have for example a function A() in a.c and a function B() in b.c and A() calls B(), then you'll write #include b.h at the top of a.c, after #include "a.h". Even if B() calls A() as well, this imposes no problem: include a.h at the top of b.c after including b.h. In the end, a.h and b.h are included before a.c and b.c and everything is fine. So, include the header of the .c file first, then include all other headers that are required for the .c file, nothing more. If you need other .h files for types, globals, definitions, etc., include them as well, but always after including the header of the .c file. The only thing that belongs in .c files are functions. You should also comment your functions carefully, you should write at least a brief (!) comment in the header what a function does. When you look up later function names, this is really helpful. What I prefer is to write the same brief comment to the function in the .c file as well, plus an extensive comment afterwards that explains to me what a function does, if it is complex. Sure, if that is an easy function, you can waive that, but sometimes you do really badass stuff and even some days later you wonder what you did there - and then you well appreciate a nice comment then. How you document parameters and return values and so on is a matter of taste, you'll have to find your own way. What I prefer at the moment are prose comments that tell you how things work like you are talking with a person, like
// stores the object space position of a terrain entity vertex (defined via row & col) in
// 'p'. If p == NULL, a temporary vector will be returned. If row/col is outside the
// terrain entity, it will be clamped to the nearest border vertex
//
VECTOR* hmp_entgetvertex (ENTITY*, int row, int col, VECTOR* p);
or
// saves the deformation of a terrain entity back into the file it was loaded from. It
// only works for entities which were loaded from a physically existant .hmp file! It
// doesn't work for dynamically created terrain entities and entities, which were
// loaded from a WRS resource
//
BOOL hmp_entsave (ENTITY*);
Even if there is only one parameter like in the second case, functions can have several boundary conditions, default cases and whatelse, so it is very important to write it down. Others prefer lists, one line for each parameter and one for the return value, like
// My function does...
//
// Param: int a blabla
// float b blabla
//
// Return: true/false upon success
which is also very popular, but for my personal taste it is wasting so much space, especially if the parameter list is long and if the description is long - because sometimes, parameters speak for themselves (e.g. by the type, or by the naming).
Last edited by HeelX; 02/07/12 07:52.
|
|
|
Moderated by mk_1, Perro, rayp, Realspawn, Rei_Ayanami, rvL_eXile, Spirit, Superku, Tobias, TSG_Torsten, VeT
|