re: 創(chuàng)建游戲內(nèi)核(1) lovedday 2008-03-26 16:55
啥牛人啊,大菜鳥(niǎo)一個(gè),這些文章不過(guò)是自己看書(shū)時(shí)的摘要,寫(xiě)出來(lái)也是方便自己查閱的,沒(méi)想到對(duì)大家還有用。
re: 幾何檢測(cè)(3) lovedday 2008-03-14 13:02
哪錯(cuò)呢?
re: 3D中的方位和角位移(5) lovedday 2008-03-05 09:30
re: 3D中的方位和角位移(5) lovedday 2008-02-28 09:12
你的理解是對(duì)的,可能是作者的疏忽吧,應(yīng)該是順指針120度。
這個(gè)例子應(yīng)該說(shuō)作者舉錯(cuò)了,即使是順時(shí)針240度,也不會(huì)和逆時(shí)針80度等價(jià),而是和逆時(shí)針120度等價(jià)。
re: 我的快樂(lè)哪里去了? lovedday 2008-02-27 08:51
人活著總是有許多的無(wú)奈,快樂(lè)實(shí)在不是一件容易的事。
不過(guò)大多數(shù)情況下人還是喜歡自尋煩惱。
re: 3D中的方位和角位移(5) lovedday 2008-02-27 08:48
《3D數(shù)學(xué)基礎(chǔ):圖形與游戲開(kāi)發(fā)》
re: 創(chuàng)建3D圖形引擎(3) lovedday 2008-01-22 19:52
據(jù)說(shuō)《3D Game Engine Programming》不錯(cuò),不過(guò)只有英文版的。
re: 莊子 lovedday 2008-01-21 22:37
good!
re: 生命不能承受之重 lovedday 2008-01-08 21:11
@419111344
很感謝你的關(guān)心,做了檢查,問(wèn)題不太大,可能是我過(guò)于擔(dān)心了。
回到家里心情好多了,我很喜歡C++博客,這里有一群對(duì)技術(shù)癡迷的程序員,還有很多內(nèi)心充實(shí)熱愛(ài)生活關(guān)心他人的人,謝謝你們,讓我們一起努力吧。
身體很重要,所有的技術(shù)都是身外之物。
最好劃分出一個(gè)個(gè)單獨(dú)的大模塊,交給一個(gè)人獨(dú)立完成,協(xié)作是很困難的。
程序這玩意,說(shuō)實(shí)話(huà),有時(shí)候人越多越麻煩。
re: 來(lái)自soso.com的攻擊 lovedday 2007-12-27 18:46
樹(shù)大招風(fēng)啊!dudu辛苦了!
re: 灌水 lovedday 2007-12-17 22:44
精辟!
re: 復(fù)雜游戲的沉迷系統(tǒng) lovedday 2007-12-05 21:38
別沉迷就好,不過(guò)有些游戲設(shè)計(jì)的你不得不沉迷,不沉迷就玩不下去。
游戲這玩意容易沉迷,特別是經(jīng)過(guò)精心設(shè)計(jì)的游戲。
re: C++中extern “C”含義深層探索 lovedday 2007-12-04 15:34
不錯(cuò),受益匪淺。
re: 關(guān)于構(gòu)造函數(shù) lovedday 2007-11-30 20:17
運(yùn)行應(yīng)該不會(huì)出問(wèn)題,到這是糟糕的代碼。
為什么要相乘,這違背了函數(shù)功能的本意。
我覺(jué)得這樣就好:
inline bool IsFloatZero(float x, float epsilon = 1e-6f)
{
return fabs(x) < epsilon;
}
中國(guó)現(xiàn)階段缺乏的就是對(duì)大型游戲的源碼剖析這樣的文章,我想現(xiàn)在不少人手里都有一些大型游戲的源碼,但是要看懂這么龐大的代碼不是一件容易的事,支持博主的做法!
厲害,外行竟然可以研究到這種程度,佩服啊!
我坐好板凳聽(tīng)課了。 :)
re: 凈化心靈,遠(yuǎn)離喧嘩和墮落。 lovedday 2007-11-19 00:19
So the most beautiful scene is nature, not human built scene.
re: 凈化心靈,遠(yuǎn)離喧嘩和墮落。 lovedday 2007-11-19 00:16
But it just a nature photo, not painted by image porecessing software.
我不是醫(yī)生,這個(gè)網(wǎng)站的草藥效果不錯(cuò),
http://lxlzs.cn/gb2312/index.asp。
有沒(méi)有將UAC關(guān)了?
原文: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.
簡(jiǎn)譯:安裝完畢后的第一件事情是首先應(yīng)該先關(guān)閉掉UAC, 在START SEARCH里直接鍵入 MSCONFIG,然后在TOOL選 DISABLE UAC ,然后點(diǎn)擊右下的LAUNCH,重新啟動(dòng)計(jì)算機(jī)。
不錯(cuò),差不多就是這么個(gè)學(xué)習(xí)法。
re: c++晦澀語(yǔ)法背后的故事(一) lovedday 2007-11-11 17:45
@foobar
謝謝,我明白了作者的意思,但實(shí)際上正如文章所指出的那樣,這是一個(gè)糟糕的設(shè)計(jì),實(shí)際上這些都導(dǎo)致了含混不清的語(yǔ)義和容易出錯(cuò)的代碼,所以我說(shuō)不要去重載函數(shù)。
C++的復(fù)雜很大一部分原因是因?yàn)槠湓愀獾脑O(shè)計(jì)。
re: c++晦澀語(yǔ)法背后的故事(一) 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
你說(shuō)只要函數(shù)名稱(chēng)相同子類(lèi)就可以覆蓋父類(lèi)函數(shù)的行為,但很顯然,這個(gè)例子說(shuō)明了僅函數(shù)名稱(chēng)相同是無(wú)法覆蓋的。如果你沒(méi)看懂,是不是說(shuō)明還沒(méi)把多態(tài)搞清楚?
re: c++晦澀語(yǔ)法背后的故事(一) lovedday 2007-11-11 17:00
@foobar
很懷疑你是不是C++沒(méi)學(xué)好。
re: c++晦澀語(yǔ)法背后的故事(一) lovedday 2007-11-11 16:38
在c++里,子類(lèi)通過(guò)函數(shù)名字隱藏父類(lèi)函數(shù),而不是通過(guò)函數(shù)簽名!
這個(gè)分析應(yīng)該沒(méi)什么問(wèn)題
子類(lèi)確實(shí)通過(guò)函數(shù)名字隱藏了父類(lèi)的函數(shù)
-------------------------------------------------------
你的這個(gè)論斷顯然是錯(cuò)的。
#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++晦澀語(yǔ)法背后的故事(一) lovedday 2007-11-11 15:37
C++里還有函數(shù)重載和參數(shù)默認(rèn)值,實(shí)際上這兩個(gè)機(jī)制是滋生bug的溫床,如果配合多態(tài),將會(huì)導(dǎo)致十分難以理解的行為,所以別用函數(shù)重載和參數(shù)默認(rèn)值。
看看這個(gè)例子,絕對(duì)讓你抓狂,猜猜看輸出的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++晦澀語(yǔ)法背后的故事(一) lovedday 2007-11-11 15:34
ps,說(shuō)這些沒(méi)別的意思,只是說(shuō)在實(shí)際項(xiàng)目中不應(yīng)該這么使用運(yùn)算符重載,當(dāng)然sherrylso只是為了說(shuō)明C++語(yǔ)法而編寫(xiě)這些代碼。
re: c++晦澀語(yǔ)法背后的故事(一) lovedday 2007-11-11 15:29
個(gè)人認(rèn)為盡量少重載運(yùn)算符,比如printf就比<<好用,實(shí)在沒(méi)有什么必要去重載<<,使用函數(shù)更好。
re: c++晦澀語(yǔ)法背后的故事(一) 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;
}
這種代碼基本上屬于濫用運(yùn)算符重載,實(shí)際上C++的不少機(jī)制都會(huì)導(dǎo)致被濫用,結(jié)果就是產(chǎn)生晦澀難懂且充滿(mǎn)bug的垃圾代碼,當(dāng)然這種代碼做為反面教材還是不錯(cuò)的,但若是在項(xiàng)目中使用這種代碼,那將是惡夢(mèng)。
re: c++晦澀語(yǔ)法背后的故事(一) lovedday 2007-11-11 15:16
關(guān)于
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!!!
}
很顯然編譯報(bào)錯(cuò)是對(duì)的,因?yàn)楹瘮?shù)原型不一樣,所以不構(gòu)成overwrite。
既然不構(gòu)成overwrite,那么你調(diào)用的就是Derived中的f函數(shù),編譯器檢查后發(fā)現(xiàn)沒(méi)有匹配的函數(shù),當(dāng)然報(bào)錯(cuò)。
至于后面的解釋個(gè)人認(rèn)為不著調(diào)。
這種做法比直接將聲明放在private更糟糕,簡(jiǎn)單問(wèn)題復(fù)雜話(huà),如果確實(shí)需要僅提供接口,搞個(gè)純虛基類(lèi)不就可以呢?
re: 老史要發(fā)狠了? lovedday 2007-11-04 20:51
挺佩服老史的,向他學(xué)習(xí)。
re: 求C++中:去掉字符串首尾空格的方法. lovedday 2007-11-04 19:44
#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;
}
re: 求C++中:去掉字符串首尾空格的方法. lovedday 2007-11-04 19:10
#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: 老史要發(fā)狠了? lovedday 2007-11-04 00:45
haha
我做了個(gè)試驗(yàn),試驗(yàn)條件是XP + VS 2005,在Release版本下測(cè)試,結(jié)果相當(dāng)令人吃驚。
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的值以改變迭代次數(shù)。
內(nèi)存消耗比較:
迭代1000次: malloc - 868k vector - 796K
迭代10000次 : malloc - 1784k vector - 916k
迭代100000次 : malloc - 10956k vector - 2000k
迭代1000000次 : malloc - 102648k vector - 10008k
vector版本內(nèi)存消耗更少,我想應(yīng)該是多次malloc導(dǎo)致內(nèi)存消耗劇增,而vector只在必要的時(shí)候才重新分配內(nèi)存。
而malloc版本在代碼中所涉及的指針操作也相當(dāng)煩瑣。
似乎也涉及到內(nèi)存的兩次分配,免不了了,STL的push_back必然需要拷貝一次原始對(duì)象,從這種意義上說(shuō),可以不用vector,哈哈。
正確的做法應(yīng)該是:
downList.push_back(stDownItem(&item1, true));
downList.push_back(stDownItem(&item2, false));
你的代碼中涉及到內(nèi)存的兩次分配。
stDownItem downItem1(&item1, true); // 第一次分配
stDownItem downItem2(&item2, false);
downList.push_back(downItem1); // 第二次分配
downList.push_back(downItem2);
---------------------------------------------------------------------------------------------------------
而C風(fēng)格僅涉及到一次內(nèi)存分配。
DOWN_ITEM_PTR down_item1 = create_down_item(true, false); // 就一次內(nèi)存分配
DOWN_ITEM_PTR down_item2 = create_down_item(false, false);
down_item1->next = down_item2;
也可能這么寫(xiě):
#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;
}
不過(guò)我可能會(huì)這么寫(xiě):
#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;
}