猫史档案馆


【从头教你做沙盒】地图的基础:区块——第一节

用户:ParseYPasyParseYPasy查看:4 回复:1 评论:4 创建时间:2022-04-28T15:48:17


在游玩Minecraft等沙盒游戏的时候,我们会接触到一个叫做“区块”的概念,它是一个游戏地图的基本单元,方便游戏进行动态加载地图。

我们将以C+喵基础,从头写出一个与Minecraft类似的终端交互式沙盒游戏,仅包括C++标准库内容,不使用图形控件。

我们假设在阅读这份文档前,你已经学习了大部分C++语法,并能熟练运用STLOOP编程。

好的,我们开始吧!

先上自己游戏的实现~

class chunk{
    private:
        long long id;//区块号
        world* related_world;//所属的世界
        block_t block[worldMaxinumHeight * chunkWidth];//地形信息
        std::vector<basic_entity>entity_list;//实体信息
    public:
        chunk(long long __id,world* __related_world);// 创建一个指定id与所属世界的chunk
        bool operator()(const chunk& op2) const;// 按照id排序
        long long getid() const;// 获取id
        block_t getblock(const position& inpos) const;// 按照position对象获取方块(仅当position在区块范围内)
        block_t getblockindex(long long index) const;// 直接通过下标获取方块
        void editblock(const position& inpos,block_t block_in,bool just_push = false);// 按照position对象修改区块内方块(仅当position在区块范围内)
        void applyBlockMerge();// 按照所在世界的方块操作序列修改自身方块信息
        void print() const;// 绘制整个区块的完整图像(使用标准的方块颜色)
        friend block_t getblock(world* target_world,const position& inpos);//按所给的坐标获取方块(仅在本区块内)
        friend int editblock(world* target_world,const position& inpos,block_t editid);//按照所给的坐标修改方块(仅在本区块内)
        friend void basic_worldgenerator::setRawTerrainX(chunk* inchunk,long long x,long long y);//生成单x坐标的地形
        friend void basic_worldgenerator::setRawTerrain(chunk* inchunk);//生成一级地形
        friend void basic_worldgenerator::setSecondaryTerrain(chunk* inchunk,world* _inworld);//生成二级地形
        friend void basic_worldgenerator::setTreeBranch(chunk* inchunk,world* _inworld,const position& pos1,const position& pos2,int size_branch,int type);//生成一个树的枝干
        friend void basic_worldgenerator::setTree(chunk* inchunk,world* _inworld,const position& inpos,int size_tree,int type);//生成树
        friend int ui_readfile();
};

倘若自己没做过这种游戏那也就没法教各位写沙盒游戏(bushi

我们拆分代码,逐个讲解类的原型:

private:
    long long id;//区块号
    world* related_world;//所属的世界
    block_t block[worldMaxinumHeight * chunkWidth];//地形信息
    std::vector<basic_entity>entity_list;//实体信息

遵循隐藏数据原则,我们规定区块号,地形信息等都是不可直接访问的,这能提高数据的安全性。

接着说明下前置的一些定义:

typedef short block_t;// 是方块存储的基础类型,在这里我们存储它的数字ID,等价于short
class world;// 一个世界类,区块通过related_world指针来表明自己所属的世界
class position;// 标准的坐标类,包括x,y坐标信息
class basic_entity;// 基础的实体类,现在还不需要知道怎么使用
class __worldgenerator;// 世界生成器类,这个是单独分出来的一个大型类,会在以后讲解,用于地形生成

我们一行一行解释。

long long id;//区块号

区块存储在世界里,必须有一个能表明其位置序号的数字,并且要保证唯一,因而我们的区块首先需要一个成员,表示它的id号。

world* related_world;

这是一个指向区块所属的世界类的指针,区块用它标明自己所属的世界是什么

block_t block[worldMaxinumHeight * chunkWidth];

区块当然要存储方块的信息,我们用两个常量定义区块的高度宽度

const long long worldMaxinumHeight = 512l;// 世界(区块)的高度
const long long chunkWidth = 16l;// 区块的宽度

两个常量相乘,就是一个区块所包含的方块数量:8192个

block_t前面提到过,它是short的别名,存储方块的id

实体的话我们等之后讲解相关内容时再叙述,现在我们着重于地形方面的实现。

public:
   chunk(long long __id,world* __related_world);// 创建一个指定id与所属世界的chunk

chunk类自然需要一个自行定义的构造函数,实现如下:

chunk::chunk(long long __id,world* __related_world){
    id = __id;
    related_world = __related_world;
    for(long long i = 0;i<worldMaxinumHeight * chunkWidth;i++)
        block[i] = id_block_air;
}

这个构造函数会为所有的方块赋值为空气(id_block_air是一个常量,代指空气方块的id)

现在相信各位可以写一个简单的区块了(我这份实现是服务于自己的沙盒游戏的,部分代码可能各位不熟悉,如果各位想写一份自己的,可以改动一些代码),示例如下:

class mychunk{
    private:
        long long id;
        short block[8192];
    public:
        mychunk(long long _id){
            id = _id;
            for(long long i = 0;i < 8912;i++)
                block[i] = 0;
        }
};

接下来,我们将开始接触一些方便其他功能函数调用的API:

long long getid() const{ return id; }

这个相信各位都懂,返回这个区块的id

block_t getblockindex(long long index) const{
    if(index >= 0 && index < worldMaxinumHeight * chunkWidth)
        return block[index];
    else
        return id_block_air;
}

我们可以直接通过这个函数访问区块的方块,如果你认为这个函数传入的参数不会有问题,可以缩成如下形式:

block_t getblockindex(long long index) const{ return block[index]; }

(当然不推荐为了省代码而这么做,否则会对开发的错误追踪造成麻烦)

我们自制的mychunk就可以写成这样:

class mychunk{
    private:
        long long id;
        short block[8192];
    public:
        mychunk(long long _id){
            id = _id;
            for(long long i = 0;i < 8912;i++)
                block[i] = 0;
        }
        long long getid() const{
             return id;
        }
        short getblockindex(long long index) const{
             if(index >= 0 && index < 8192)
                 return block[index];
             else
                 return 0;
        }
};

在之后的教程中,我们将开始使用标准的坐标类访问区块信息,这一节我们首先学习了应如何写出一个好的区块类,并添加它的功能,各位也可自行设计mychunk的其他功能和成员。

 


回复

上一页1 页 / 共 1下一页
yee089yee089

彳亍,可以,肥肠好()

点赞0


评论