幻想森林

 找回密码
 立即注册
搜索
热搜: 活动 交友 discuz
查看: 12668|回复: 14

[通用编程] [第一部分]游戏的简易框架,觉得还是写点砖头,希望有玉

[复制链接]

50

主题

742

帖子

402

积分

版主

自定义头衔

Rank: 7Rank: 7Rank: 7

积分
402
发表于 2006-11-3 22:52:06 | 显示全部楼层 |阅读模式
(前文,偶妹妹感情问题,偶很难过,然后就特别想写点什么,跑到这里来算是胡乱发表意见好了,权当作发泄……)

写最近自己的一个BALL的开发的构思好了:开发前和朋友好好讨论过游戏的开发,发觉讨论的时候,特别是自己有了一点想法,往往很容易就能够有一个整体策划计划,但是很少,只需要半张纸,也没有你想象的那么多文字,大概还没有从开头写到现在这么多字- -

AC游戏是开源的,偶也很乐意和入门的朋友们分享自己的心得(学网络用语,新手入门,高手免看好了……),这个游戏也觉得比较适合入门观摩(STL部分可能各位会郁闷,因为偶也是刚刚入STL门乱试验的- -)

首先你要有一套引擎(偶只会一点C++,所以其它语言就……不过差不多拉,主要是说说思路),可以是HGE、Y2GE、HMGE、XXGE等等,偶觉得Y2GE很好用,而且是偶的好朋友写得,如果有问题可以直接问作者,方便~,XXGE要到什么够呢?先不要觉得要什么特效都有,只需要能够显示一个PIC就可以了,顶多能够RESIZE或者ROTATE……

于是,你有了:AUDIO SOUND RENDERER ,这些比较适合用一个通用的GAMEEG来静态包装,这样当你使用的时候只需要:
GameEG:raw( hpic, x, y ) 就这样(参数分别是 图片ID,XY坐标)
GameEG:lay( hmusic ) 播放声音

接下来你知道你要开始做游戏,这会是一个方块(嗯,AC游戏是一个方块游戏)假设你有了图片……嗯……这会很麻烦?联系偶,偶能够做一个比较幼稚等级的方块……

请参考你自己的设计,什么地方会是突破口呢?我做AC游戏的时候是从main这里开始的(请大家不要像我写得这么花哨)
一句话整个游戏……OTZ……
  1. auto_ptr<Manager> mgr( new Manager(hInstance) ) ;
复制代码
大家还是自己编写init + while(loop()) + end比较好……偶纯粹看看STL的autoptr是怎么用的…… [s:8]

那么init loop end应该做什么呢?你会想知道,其实你已经知道了……
你看到了manager,这在AC的计划中是一个游戏的流程管理对象(很深奥吗?说白了,你游戏怎么执行,根据这个对象提供的函数,至于对象有什么作用,简单说,就是你不要把游戏看做一个过程,而是一个游戏对象,对,就是这个AC游戏,它,依次执行了INIT 到 END的过程,好了你觉得还是过程理解好,那就过程好了……)

我知道写太多很多人会不看了……不知道这行大家看到了没^^?

manager下面是player因为考虑到会有两个player玩,所以分了player来表示具体的玩家,你知道AC游戏的player做什么用吗?就是真正和你打交道的那个对象……不懂对象还真的郁闷啊……再多说巴……就是说你在 和 程序交流,通过某个中介,player对象就是这个中介:

  你的输入 -- player对象 --  游戏的流程、游戏的绘制

用代码来说:

  manager通过EG获得输入 -- player获得输入 -- 传递给player内部的对象(又是对象啊- -) [s:8]

player内部的对象就是你要绘制的单位,比如球、人、其它。。。
通用的属性是图片ID、X、Y等,通过这些你直接用EG就可以表现出来了,这个步骤通常就是渲染……
[s:5]

但是这样很乱?是的,你得自己慢慢整理过,偶的AC是MOVE表示一次移动,然后一次渲染,什么FPS,你管它啊…… [s:5]

好了,就啰嗦到这里,并拜谢看到这里的朋友,偶写得是很烂……

pS:顺便再打个广告,偶AC开源,放在GOOGLEPAGE上面,地址在:

http://littlewaterxp.googlepages.com/   

图片常常链接失效就不贴了= = [s:8]
Style-C
回复

使用道具 举报

136

主题

1751

帖子

548

积分

版主

Rank: 7Rank: 7Rank: 7

积分
548
发表于 2006-11-3 23:24:41 | 显示全部楼层
是这样的吧
main

初始化设备;
游戏循环;
释放设备;
え~え~お!!!
回复 支持 反对

使用道具 举报

50

主题

742

帖子

402

积分

版主

自定义头衔

Rank: 7Rank: 7Rank: 7

积分
402
 楼主| 发表于 2006-11-4 13:22:37 | 显示全部楼层
对的,初始化部分往往是 EG的INIT,RESOURCE的LOAD,一般所有的资源应该被全部加载到内存(除非大型游戏……)
中间部分是逻辑处理为主,偶觉得还是写得太乱了……
RELEASE部分就是指把你的EG的东西卸载掉,别忘了还有资源……不然泄漏了(虽然SYSTEM会负责善后,但是负责的程序员会一点不忘卸载所有的资源……)

另外这篇文章感觉有点虎头蛇尾了……偶有空想想后面部分应该怎么写
Style-C
回复 支持 反对

使用道具 举报

1

主题

12

帖子

161

积分

③业余

积分
161
发表于 2006-11-4 14:07:38 | 显示全部楼层
我也来说一下流程吧.
一般框架型的引擎.会提供一个BaseAppFrameWork 用来封装游戏主体框架.自己写的时候只用继承这个类,并重载所要的函数即可.
不过我这里说的是我的红魔夜的流程.还是用的传统的写法,因为我的Y2GE本身不是一个框架
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd )
{
    EnableMemoryLeakCheck();
    Game::InitGame(hInstance);
    Game::RunGame();
    Game::ShutGame();
    return 0;
}
而Game本身是一个static类.就是里面的函数和成员都是static 的.当然这个可以用Singleton来实现.但是我直接写了.
Game里面保存着几个对游戏有整体作用的变量.除了控制游戏主体运行的ObjManager
以外.还有一个非常重要的变量state,作为游戏的主体状态机的状态.
typedef enum
{
    GAME_STATE_INIT,
    GAME_STATE_END,
    GAME_STATE_STARTMENU,
    GAME_STATE_CHOOSEDIFFICULTY,
    GAME_STATE_CHOOSEPLAYER,
    GAME_STATE_STARTLEVEL,
    GAME_STATE_RUN,
    GAME_STATE_PAUSE,
    GAME_STATE_NEWlEVEL,
    GAME_STATE_CONTINUE
}GAME_STATE;
class Game
{
// Interface
public:
    static void InitGame(HINSTANCE hinstance);
    static void RunGame();
    static void ShutGame();
    static bool _func(DWORD a);
    static ObjectMap & GetObjectMap();
protected:
    static int _GameStateInit();
    static int _GameStateEnd();
    static int _GameStatestartMenu();
    static int _GameStateChooseDifficulty();
    static int _GameStateChoosePlayer();
    static int _GameStateStartLevel();
    static int _GameStateRun();
    static int _GameStatePause();
    static int _GameStateNewLevel();
    static int _GameStateContinue();
// Variables
private:   
    static ObjectMap om;
    static HINSTANCE hinstance;
    static int state;
    static int level;
};
Init和Shut 分别负责引擎初始化资源加载 和 资源释放引擎关闭
重点在Run上面.
void Game::RunGame()
{
    engine.Sys_Start(Game::_func,0);
}
这里用我的Y2GE进行游戏循环.
bool Game::_func(DWORD a)
{
    static bool restore = false;

    // game state run
    if (!engine.Video_BeginScene(Color::black()))
    {
        if (restore == false)
        {
            om.ReleaseFont();
            restore = true;
        }
        return true;
    }
    if (restore == true)
    {
        om.RestoreFont();
        restore = false;
    }
    switch (state)
    {
    case GAME_STATE_INIT:
        state = _GameStateInit();
        break;
    case GAME_STATE_END:
        state = _GameStateEnd();
        return false;
        break;
    case GAME_STATE_STARTMENU:
        state = _GameStatestartMenu();
        break;
    case GAME_STATE_CHOOSEDIFFICULTY:
        state = _GameStateChooseDifficulty();
        break;
    case GAME_STATE_CHOOSEPLAYER:
        state = _GameStateChoosePlayer();
        break;
    case GAME_STATE_STARTLEVEL:
        state = _GameStateStartLevel();
        break;
    case GAME_STATE_RUN:
        state = _GameStateRun();
        break;
    case GAME_STATE_PAUSE:
        state = _GameStatePause();
        break;
    case GAME_STATE_NEWlEVEL:
        state = _GameStateNewLevel();
        break;
    case GAME_STATE_CONTINUE:
        state = _GameStateContinue();
        break;
    }
    engine.Video_EndScene();
   
    return true;
}
也就是说每一个状态都有一个对应的函数进行处理.该函数返回下一个应该出现的状态.
然后就可以在主要的state 里面使用ObjManager(就是ObjectMap)来进行游戏主体运行了
int Game::_GameStateRun()
{
    engine.Event_GetKeyboardState();

    if (!Level::ExecuteScript())
        return GAME_STATE_NEWlEVEL;
    om.ProcessInput();
    om.MoveObjects();
    om.ProcessHitEvents();
    if (engine.keyboard.IsKeyDown(DIK_RETURN) || engine.keyboard.IsKeyDown(DIK_ESCAPE))
    {
        Global:laySe(SE_CANCEL);
        return GAME_STATE_PAUSE;
    }
    if(!om.IsPlayerAlive())
    {
        return GAME_STATE_CONTINUE;
    }
    om.RenderObjects();
    return GAME_STATE_RUN;
}
简单的游戏框架就是这样了.
代码写的很烂,请大家多包涵..
回复 支持 反对

使用道具 举报

50

主题

742

帖子

402

积分

版主

自定义头衔

Rank: 7Rank: 7Rank: 7

积分
402
 楼主| 发表于 2006-11-4 14:35:45 | 显示全部楼层
看到yuki的这篇,感觉文字少了点,但是很清晰,偶要学学这种 西法 ~

不过这个GAME是一个全static的类……
Style-C
回复 支持 反对

使用道具 举报

50

主题

742

帖子

402

积分

版主

自定义头衔

Rank: 7Rank: 7Rank: 7

积分
402
 楼主| 发表于 2006-11-4 14:40:09 | 显示全部楼层
case GAME_STATE_RUN:
state = _GameStateRun();

这句话恐怕不知道脚本驱动的人会还是云里雾里巴^^
Style-C
回复 支持 反对

使用道具 举报

1

主题

12

帖子

161

积分

③业余

积分
161
发表于 2006-11-4 14:50:24 | 显示全部楼层
引用第4楼lw2006-11-04 14:35发表的:
看到yuki的这篇,感觉文字少了点,但是很清晰,偶要学学这种 西法 ~

不过这个GAME是一个全static的类……
怎么好用就怎么用啊.不过Game类必须要有一个static函数就是_func.Level类也是全static 的.因为要和lua交互.
lw是版主吗.刚看到.
回复 支持 反对

使用道具 举报

50

主题

742

帖子

402

积分

版主

自定义头衔

Rank: 7Rank: 7Rank: 7

积分
402
 楼主| 发表于 2006-11-4 14:57:54 | 显示全部楼层
不过Game类必须要有一个static函数就是_func
因为Y2GE必须调用一个NOMEMEBER FUNCTION哈^^

和LUA交互的时候能不能放到某个level对象中?比如不同的对象 和LUA的不同功能、模块相互交互?当然还会有中间层……
例如:
[LUA_SHOT]     -- lua parser -- shot flowfunc
[LUA_PLAYER]  -- lua parser -- player flowfunc
[LUA_ENEMY]   -- lua parser -- enemy flowfunc
等,PS:偶基本不懂lua怎么用的……
[s:8]
Style-C
回复 支持 反对

使用道具 举报

1

主题

12

帖子

161

积分

③业余

积分
161
发表于 2006-11-4 15:08:50 | 显示全部楼层
lua 必须要调用static 的func.把这个func 在lua里面注册了以后.就可以在脚本里面调用.
函数原形必须这样
int _cdecl func (lua_State * ls);
可以从ls里面取得lua传过来的参数.也可以把要返回的值压进去.
回复 支持 反对

使用道具 举报

50

主题

742

帖子

402

积分

版主

自定义头衔

Rank: 7Rank: 7Rank: 7

积分
402
 楼主| 发表于 2006-11-5 11:53:17 | 显示全部楼层
偶大概这样写:
class LUAParser
{
public: static int func(lua_State *ls); ...
};

class LUA_Shoter : public LUAParser
{
public:
    HRESULT do_LUAOnShot() {}
};

class LUA_Enemy : public LUAParser
{
public:
    HRESULT do_LUAOnEnemy() {}
};

... 等等 [s:4]
Style-C
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver|手机版|小黑屋|幻想森林

GMT+8, 2024-3-29 16:30 , Processed in 0.026690 second(s), 20 queries .

Powered by Discuz! X3.4

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表