我开始了一个业余爱好项目,这是我在C语言中做的第一件事,目的是让别人看到我。我已经练习了一段时间,但实际上我是个初学者,我还没有用C/C++编写过真正的软件。
我想知道从我的代码中什么是好的,什么是错误的,为什么,如果它是清晰的/可读的,你能告诉我的一切都会很好。我从来没有向任何人展示过我的代码,我也不知道我是否做得很好,或者它不会更糟--后者是我认为最有可能的。所以我想知道有C/C++经验的人的原因,以及你认为我可以改进/删除什么,等等。
这段代码是我刚刚开始的,关于“我的世界”-like游戏中的一个小体素系统。
基本想法是:
等等。我有很多想法,但我仍然很少写一些代码,我想知道其他人的意见在继续之前,所以我可以改进这个项目,而不是必须修复它以后。
这是项目文件的链接(只有一个.h和一个.cpp,刚刚开始)在谷歌代码
下面是.h的一些内容,这样您就可以在不打开链接的情况下给自己一个想法:
typedef struct _GVOXEL_RULE
{
GVOXELRULE_ID nRuleID;
INT32 nRuleValue; // this value is left for use by the rule function, not needed right now
} GVOXEL_RULE;
// here I'm planning to store the description of the voxel types
typedef struct _GVOXEL_DATA
{
GVOXEL_TYPE nVoxelType;
dword nRuleCount;
GVOXEL_RULE* pVoxelRules; // I'm thinking this should be separated to a "voxel rule manager" class or something similar
dword nVoxelCount; // store here the amount of voxels applying this reference (so we stop looking when the limit is reached)
} GVOXEL_DATA;
typedef struct _GVOXEL_STATE_1_0
{
GVOXEL_ID nVoxelID; // This id will be equal to the voxel index which may be handy
GVOXEL_TYPE nVoxelType; // This number will reference the table with voxel descriptions
word nMetadata; // This was described below.
byte nLightX; // This stores how much light (from 0 to 255) is receiving the face pointing to +X
byte nLightXN; // Same from below but for -X face
byte nLightY; // etc.
byte nLightYN; // etc..
byte nLightZ; // etc...
byte nLightZN; //
} GVOXEL_STATE_1_0, GVOXEL_STATE;
typedef struct _GVOXELCHUNK_DATA_1_0 //
{
volatile long nRefCount; // <-- This gives me the chills
dword nChunkID; // some chunk ID that makes sense in some other reference table. or not.
dword nWidth; // size of the array in the X dimension
dword nHeight; // size of the array in the Y dimension
dword nDepth; // size of the array in the Z dimension
GVOXEL_STATE_1_0* pVoxelStateList; // The count of voxel states will be nWidth*nHeight*nDepth
dword nExtendedDataSize; // size of optional data, if found in the file, to be loaded to the "pExtendedData" pointer.
void* pExtendedData; // If bExtendedData is 0, this variable should be set to 0 (null).
} GVOXELCHUNK_DATA_1_0, GVOXELCHUNK_DATA;
void gvCreateChunkData10( GVOXELCHUNK_DATA_1_0** ppChunkData );
void gvAcquireChunkData10( GVOXELCHUNK_DATA_1_0* pChunkData );
void gvFreeChunkData10( GVOXELCHUNK_DATA_1_0** ppChunkData );
#define gvCreateChunkData gvCreateChunkData10
#define gvFreeChunkData gvFreeChunkData10
#define gvAcquireChunkData gvAcquireChunkData10
// wchar_t* pFilename: Name of the source file to load chunk data from
// dword *nMaxChunks: if ppChunkData is NULL, the function returns here the number of chunks in the file. else stores the
// GVOXELCHUNK_DATA** ppChunkData:
INT32 gvLoadChunkFromFileW( wchar_t* pFilename, dword *inout_nMaxChunks, GVOXELCHUNK_DATA** ppChunkData );
//
INT32 gvSaveChunkToFileW( wchar_t* pFilename, dword nChunkCount, GVOXELCHUNK_DATA** ppChunkData );
#ifdef _TODO
INT32 gvLoadChunkFromFileA( char* pFilename, dword nMaxChunks, GVOXELCHUNK_DATA** ppChunkData );
INT32 gvSaveChunkToFileA( char* pFilename, dword nChunkCount, GVOXELCHUNK_DATA** ppChunkData );
#endif
#define gvLoadChunkFromFile gvLoadChunkFromFileW
#define gvSaveChunkToFile gvSaveChunkToFileW 发布于 2011-12-02 14:46:49
看起来你有一个设计,但是并不是所有的代码都是可见的。不管怎么说,我对你真正想要做的模特儿有些模糊,所以让我们来看看。
nVoxelType .某个类型数组的索引没有显示?好吧,我们显然需要在体素实例和它的类型之间建立某种连接,不管实现方式如何。如果你试着画一个游戏事件的草图,它可能有助于澄清一些事情:从坐标到体素实例很容易,但是一旦你有了它,你会对它做些什么呢?
您说您可能需要C而不是C++,但是您可以在这两种语言中使用类似的多态性,所以设计交互仍然比选择语言更重要。
例如:C++
class VoxelType
{
public:
// common interface for all types
virtual void hitMeWithAPickaxe(Voxel *self) = 0;
virtual void setFireToMe(Voxel *self) = 0;
};
class DirtVoxelType: public VoxelType
{
public:
// specific implementation for this type
void hitMeWithAPickaxe(Voxel *self);
virtual void setFireToMe(Voxel *self);
};或用C语:
struct VoxelType {
int type;
void (*hitMeWithAPickaxe)(struct Voxel *self);
void (*setFireToMe)(struct Voxel *self);
};
void hitDirtWithAPickaxe(struct Voxel *);
void setFireToDirt(struct Voxel *);
struct VoxelType VoxelTypeArray[] = {
{ DirtType, hitDirtWithAPickaxe, setFireToDirt },
...
};显然,您也可以使用这两种语言中久经考验的大量切换/用例声明--关键是C或C++的选择不是设计背后的驱动力,而是实现背后的驱动力。
volatile long nRefCount; // <-- This gives me the chills,我不怪你--即使你已经知道你的游戏会被多线程化,我也看不出这有什么用。要么预先设计并发和同步,然后正确地完成它,要么完全忽略它,准备在某个线程确实不够好的情况下稍后再做一些重新设计工作。
以增加主观性的近似顺序
#define gvSaveChunkToFile gvSaveChunkToFileW是怎么回事?这是为了方便一些跨平台的东西以后,还是你只是从其他地方复制它?它是丑陋和潜在的混乱,所以我会删除它,除非它增加了一些真正有价值的东西,我在这里看不到。
同样,对于所有的GVOXEL_STATE_1_0, GVOXEL_STATE内容--除非您真的计划在运行时拥有和处理多个不兼容版本的相同结构(这听起来很可怕),否则您可以将任何向后兼容逻辑隔离到(反)序列化层,并删除主代码中的重复名称。
您正在使用很多(我认为是)特定于平台的类型,以防您在意。也许byte、dword等在该平台上是惯用的,所以有很大的一致性好处,但我不清楚它们相对于标准类型(如char、int8_t或uint8_t )还有什么优势。
主观上,我不太喜欢这里使用的匈牙利符号:您只是在复制类型,而没有添加任何语义信息。
最后,在主观上,我不喜欢ALL_UPPER_CASE类型的名称或_LEADING_UNDERSCORE_UPPER_CASE符号,它们与__RESERVED_NAMES非常接近,看起来很难看。我也不认为需要对每个结构进行类型标注;struct VoxelState *而不是GVOXEL_STATE_1_0 *似乎更清晰、更容易阅读
https://codereview.stackexchange.com/questions/6419
复制相似问题