天行健 君子当自强而不息

共4页: 1 2 3 4 
re: 创建游戏内核(1) lovedday 2008-03-26 16:55
啥牛人啊,大菜鸟一个,这些文章不过是自己看书时的摘要,写出来也是方便自己查阅的,没想到对大家还有用。
re: 几何检测(3) lovedday 2008-03-14 13:02
哪错呢?
re: 3D中的方位和角位移(5) lovedday 2008-02-28 09:12
你的理解是对的,可能是作者的疏忽吧,应该是顺指针120度。
这个例子应该说作者举错了,即使是顺时针240度,也不会和逆时针80度等价,而是和逆时针120度等价。
re: 我的快乐哪里去了? lovedday 2008-02-27 08:51
人活着总是有许多的无奈,快乐实在不是一件容易的事。
不过大多数情况下人还是喜欢自寻烦恼。
re: 3D中的方位和角位移(5) lovedday 2008-02-27 08:48
《3D数学基础:图形与游戏开发》
re: 创建3D图形引擎(3) lovedday 2008-01-22 19:52
据说《3D Game Engine Programming》不错,不过只有英文版的。
re: 庄子 lovedday 2008-01-21 22:37
good!
re: 生命不能承受之重 lovedday 2008-01-08 21:11
@419111344
很感谢你的关心,做了检查,问题不太大,可能是我过于担心了。

回到家里心情好多了,我很喜欢C++博客,这里有一群对技术痴迷的程序员,还有很多内心充实热爱生活关心他人的人,谢谢你们,让我们一起努力吧。

身体很重要,所有的技术都是身外之物。
这本书我还想多看几遍哩,不好意思啊。
最好划分出一个个单独的大模块,交给一个人独立完成,协作是很困难的。
程序这玩意,说实话,有时候人越多越麻烦。
re: 来自soso.com的攻击 lovedday 2007-12-27 18:46
树大招风啊!dudu辛苦了!
re: 灌水 lovedday 2007-12-17 22:44
精辟!
re: 读《程序设计总结》有感 lovedday 2007-12-09 13:08
有道理。
re: 复杂游戏的沉迷系统 lovedday 2007-12-05 21:38
别沉迷就好,不过有些游戏设计的你不得不沉迷,不沉迷就玩不下去。
所以不得不慎。。。。
游戏这玩意容易沉迷,特别是经过精心设计的游戏。
不错,受益匪浅。
re: 关于构造函数 lovedday 2007-11-30 20:17
运行应该不会出问题,到这是糟糕的代码。
为什么要相乘,这违背了函数功能的本意。

我觉得这样就好:

inline bool IsFloatZero(float x, float epsilon = 1e-6f)
{
return fabs(x) < epsilon;
}

中国现阶段缺乏的就是对大型游戏的源码剖析这样的文章,我想现在不少人手里都有一些大型游戏的源码,但是要看懂这么庞大的代码不是一件容易的事,支持博主的做法!
厉害,外行竟然可以研究到这种程度,佩服啊!
我坐好板凳听课了。 :)
So the most beautiful scene is nature, not human built scene.
But it just a nature photo, not painted by image porecessing software.
我不是医生,这个网站的草药效果不错,http://lxlzs.cn/gb2312/index.asp
有没有将UAC关了?

原文:Most operations described below require elevated privileges, so disabling UAC (Run->MSCONFIG.EXE->
Tools->Disable UAC) for the time being is recommended, Of course, it can be safely re-enabled after
all steps have been performed. Otherwise OEMTOOL.EXE and some SLMGR.VBS operations must be explicitly
run with adminstrative privileges.
简译:安装完毕后的第一件事情是首先应该先关闭掉UAC, 在START SEARCH里直接键入 MSCONFIG,然后在TOOL选 DISABLE UAC ,然后点击右下的LAUNCH,重新启动计算机。
不错,差不多就是这么个学习法。
re: c++晦涩语法背后的故事(一) lovedday 2007-11-11 17:45
@foobar

谢谢,我明白了作者的意思,但实际上正如文章所指出的那样,这是一个糟糕的设计,实际上这些都导致了含混不清的语义和容易出错的代码,所以我说不要去重载函数。

C++的复杂很大一部分原因是因为其糟糕的设计。
re: c++晦涩语法背后的故事(一) lovedday 2007-11-11 17:05
#include <stdio.h>

class Base
{
public:
virtual void f(int x)
{
printf("call base f function\n");
}
};

class Derived: public Base
{
public:
virtual void f(double pd)
{
printf("call derived f function\n");
}
};

int main()
{
Base* pb = new Derived;
pb->f(10.5);

return 0;
}

输出:

call base f function

你说只要函数名称相同子类就可以覆盖父类函数的行为,但很显然,这个例子说明了仅函数名称相同是无法覆盖的。如果你没看懂,是不是说明还没把多态搞清楚?
re: c++晦涩语法背后的故事(一) lovedday 2007-11-11 17:00
@foobar

很怀疑你是不是C++没学好。
re: c++晦涩语法背后的故事(一) lovedday 2007-11-11 16:38
在c++里,子类通过函数名字隐藏父类函数,而不是通过函数签名!

这个分析应该没什么问题
子类确实通过函数名字隐藏了父类的函数

-------------------------------------------------------

你的这个论断显然是错的。

#include <stdio.h>

class Base
{
public:
virtual void f(int x)
{
printf("call base f function\n");
}
};

class Derived: public Base
{
public:
virtual void f(double pd)
{
printf("call derived f function\n");
}
};

int main()
{
Base* pb = new Derived;
pb->f(10.5);

return 0;
}

输出:

call base f function
re: c++晦涩语法背后的故事(一) lovedday 2007-11-11 15:37
C++里还有函数重载和参数默认值,实际上这两个机制是滋生bug的温床,如果配合多态,将会导致十分难以理解的行为,所以别用函数重载和参数默认值。

看看这个例子,绝对让你抓狂,猜猜看输出的i和j值是多少?

#include <stdio.h>

class PARENT
{
public:
virtual int doIt( int v, int av = 10 )
{
return v * v;
}
};

class CHILD : public PARENT
{
public:
int doIt( int v, int av = 20 )
{
return v * av;
}
};

int main()
{
PARENT *p = new CHILD();

int i = p->doIt(3);
printf("i = %d\n", i);

CHILD* q = new CHILD();

int j = q->doIt(3);
printf("j = %d\n", j);

return 0;
}
re: c++晦涩语法背后的故事(一) lovedday 2007-11-11 15:34
ps,说这些没别的意思,只是说在实际项目中不应该这么使用运算符重载,当然sherrylso只是为了说明C++语法而编写这些代码。
re: c++晦涩语法背后的故事(一) lovedday 2007-11-11 15:29
个人认为尽量少重载运算符,比如printf就比<<好用,实在没有什么必要去重载<<,使用函数更好。
re: c++晦涩语法背后的故事(一) lovedday 2007-11-11 15:25
#include <iostream>
using namespace std;
namespace Koenig
{
class MyArg
{
public:
ostream& print(ostream& out) const
{
out<<"this is MyArg."<<endl;
}
};

inline ostream& operator<<(ostream& out, const MyArg& myArg)
{
return myArg.print(out);
}
}

int main()
{
Koenig::MyArg myArg;
cout<<myArg;
return 0;
}

这种代码基本上属于滥用运算符重载,实际上C++的不少机制都会导致被滥用,结果就是产生晦涩难懂且充满bug的垃圾代码,当然这种代码做为反面教材还是不错的,但若是在项目中使用这种代码,那将是恶梦。
re: c++晦涩语法背后的故事(一) lovedday 2007-11-11 15:16
关于

class Base
{
public:
virtual void f(int x);
};
class Derived: public Base
{
public:
virtual void f(double* pd);
};
int main()
{
Derived* pd = new Derived();
pd->f(10); //compile error!!!
}

很显然编译报错是对的,因为函数原型不一样,所以不构成overwrite。

既然不构成overwrite,那么你调用的就是Derived中的f函数,编译器检查后发现没有匹配的函数,当然报错。

至于后面的解释个人认为不着调。
c++折腾到这种份上,完全本末倒置。
这种做法比直接将声明放在private更糟糕,简单问题复杂话,如果确实需要仅提供接口,搞个纯虚基类不就可以呢?
re: 老史要发狠了? lovedday 2007-11-04 20:51
挺佩服老史的,向他学习。
#include <iostream>
#include <string>

using namespace std;

void trim(string& str)
{
str.erase(str.find_last_not_of(' ')+1, string::npos);
str.erase(0, str.find_first_not_of(' '));
}

int main()
{
string str = " hello world! ";

trim(str);

cout << "after trim:" << endl;
cout << str << endl;

return 0;
}
#include <string.h>
#include <stdio.h>

#pragma warning(disable : 4996)

char* rtrim(char* s)
{
if(s == NULL)
return NULL;

// set tail white space as '\0'
for(size_t i = strlen(s)-1; i >= 0 && s[i] == ' '; i--)
s[i] = '\0';

return s;
}

char* ltrim(char* s)
{
if(s == NULL)
return NULL;

char* p;

// skip head white space
for(p = s; *p == ' '; p++)
;

if(p != s) // if address p is not same as address s
{
size_t length = strlen(p);

if(length > 0) // so p is not null
{
memmove(s, p, length);
s[length] = '\0';
}
}

return s;
}

char* trim(char* s)
{
if(s == NULL)
return NULL;

rtrim(s);

return ltrim(s);
}

int main()
{
char s[10];
strcpy(s, " ab cde ");

trim(s);

printf("after trim:\n");

if(*s != '\0')
printf("%s, length = %d\n", s, strlen(s));
else
printf("s is null\n");

return 0;
}
re: 老史要发狠了? lovedday 2007-11-04 00:45
haha
哈哈,献丑了。
我做了个试验,试验条件是XP + VS 2005,在Release版本下测试,结果相当令人吃惊。

malloc版本:

#define ITEM_TIMES 1000000

#include <malloc.h>

#define NULL 0

typedef struct UPDATE_ITEM
{
bool down_succeeded;
} *UPDATE_ITEM_PTR;

typedef struct DOWN_ITEM
{
UPDATE_ITEM_PTR update_item;
bool pack;

DOWN_ITEM* next;
} *DOWN_ITEM_PTR;

DOWN_ITEM_PTR create_down_item(bool pack, bool down_succeeded)
{
DOWN_ITEM_PTR down_item = (DOWN_ITEM_PTR) malloc(sizeof(DOWN_ITEM));
down_item->pack = pack;

down_item->update_item = (UPDATE_ITEM_PTR) malloc(sizeof(UPDATE_ITEM));
down_item->update_item->down_succeeded = down_succeeded;

down_item->next = NULL;

return down_item;
}

void free_all_down_item(DOWN_ITEM_PTR root_down_item)
{
DOWN_ITEM_PTR down_item_ptr = root_down_item;

while(down_item_ptr)
{
if(down_item_ptr->update_item)
free(down_item_ptr->update_item);

DOWN_ITEM_PTR temp_ptr = down_item_ptr;
down_item_ptr = down_item_ptr->next;

free(temp_ptr);
}
}

int main()
{
DOWN_ITEM_PTR first, last, ptr;

for(int i = 0; i < ITEM_TIMES; i++)
{
if(i == 0)
{
first = create_down_item(true, false);
last = first;
}
else
{
ptr = create_down_item(true, false);
last->next = ptr;

last = ptr;
}
}

while(1)
;

free_all_down_item(first);

return 0;
}

vector版本:

#include <vector>

using namespace std;

typedef struct UPADTE_ITEM
{
bool down_succeeded;

UPADTE_ITEM()
{
down_succeeded = false;
}
} *UPADTE_ITEM_PTR;

typedef struct DOWN_ITEM
{
UPADTE_ITEM_PTR update_item;
bool pack;

DOWN_ITEM()
{
update_item = NULL;
pack = false;
}

DOWN_ITEM(UPADTE_ITEM_PTR _update_item, bool _pack)
{
update_item = _update_item;
pack = _pack;
}
} *DOWN_ITEM_PTR;

int main()
{
vector<DOWN_ITEM> down_item_vec;

UPADTE_ITEM_PTR update_item_list = new UPADTE_ITEM[ITEM_TIMES];

for(int i = 0; i < ITEM_TIMES; i++)
down_item_vec.push_back(DOWN_ITEM(&update_item_list[i], true));

while(1)
;

delete[] update_item_list;

return 0;
}

改变ITEM_TIMES的值以改变迭代次数。

内存消耗比较:

迭代1000次: malloc - 868k vector - 796K
迭代10000次 : malloc - 1784k vector - 916k
迭代100000次 : malloc - 10956k vector - 2000k
迭代1000000次 : malloc - 102648k vector - 10008k

vector版本内存消耗更少,我想应该是多次malloc导致内存消耗剧增,而vector只在必要的时候才重新分配内存。
而malloc版本在代码中所涉及的指针操作也相当烦琐。
似乎也涉及到内存的两次分配,免不了了,STL的push_back必然需要拷贝一次原始对象,从这种意义上说,可以不用vector,哈哈。
正确的做法应该是:

downList.push_back(stDownItem(&item1, true));
downList.push_back(stDownItem(&item2, false));
你的代码中涉及到内存的两次分配。

  stDownItem downItem1(&item1, true); // 第一次分配
stDownItem downItem2(&item2, false);

downList.push_back(downItem1); // 第二次分配
downList.push_back(downItem2);

---------------------------------------------------------------------------------------------------------

而C风格仅涉及到一次内存分配。

DOWN_ITEM_PTR down_item1 = create_down_item(true, false); // 就一次内存分配
DOWN_ITEM_PTR down_item2 = create_down_item(false, false);

down_item1->next = down_item2;
也可能这么写:

#include <stdio.h>
#include <malloc.h>

typedef struct UPDATE_ITEM
{
bool down_succeeded;
} *UPDATE_ITEM_PTR;

typedef struct DOWN_ITEM
{
UPDATE_ITEM_PTR update_item;
bool pack;

DOWN_ITEM* next;
} *DOWN_ITEM_PTR;

DOWN_ITEM_PTR create_down_item(bool pack, bool down_succeeded)
{
DOWN_ITEM_PTR down_item = (DOWN_ITEM_PTR) malloc(sizeof(DOWN_ITEM));
down_item->pack = pack;

down_item->update_item = (UPDATE_ITEM_PTR) malloc(sizeof(UPDATE_ITEM));
down_item->update_item->down_succeeded = down_succeeded;

down_item->next = NULL;

return down_item;
}

void free_all_down_item(DOWN_ITEM_PTR root_down_item)
{
DOWN_ITEM_PTR down_item_ptr = root_down_item;

while(down_item_ptr)
{
if(down_item_ptr->update_item)
free(down_item_ptr->update_item);

DOWN_ITEM_PTR temp_ptr = down_item_ptr;
down_item_ptr = down_item_ptr->next;

free(temp_ptr);
}
}

int main()
{
DOWN_ITEM_PTR down_item1 = create_down_item(true, false);
DOWN_ITEM_PTR down_item2 = create_down_item(false, false);

down_item1->next = down_item2;

DOWN_ITEM_PTR down_item_ptr = down_item1;

while(down_item_ptr)
{
down_item_ptr->update_item->down_succeeded = true;
down_item_ptr = down_item_ptr->next;
}

free_all_down_item(down_item1);

return 0;
}
不过我可能会这么写:

#include <malloc.h>
#include <vector>

using namespace std;

typedef struct UPADTE_ITEM
{
bool down_succeeded;

UPADTE_ITEM()
{
down_succeeded = false;
}
} *UPADTE_ITEM_PTR;

typedef struct DOWN_ITEM
{
UPADTE_ITEM_PTR update_item;
bool pack;

DOWN_ITEM()
{
memset(this, 0, sizeof(*this));
}
} *DOWN_ITEM_PTR;

int main()
{
vector<DOWN_ITEM> down_item_vec;

UPADTE_ITEM item1;
UPADTE_ITEM item2;

DOWN_ITEM downItem1;
downItem1.update_item = &item1;
downItem1.pack = true;

DOWN_ITEM downItem2;
downItem2.update_item = &item2;
downItem2.pack = false;

down_item_vec.push_back(downItem1);
down_item_vec.push_back(downItem2);

for (vector<DOWN_ITEM>::const_iterator it = down_item_vec.begin(); it != down_item_vec.end(); ++it)
{
it->update_item->down_succeeded = true;
}

return 0;
}
共4页: 1 2 3 4 

公告

导航

统计

常用链接

随笔分类(178)

3D游戏编程相关链接

搜索

最新评论