游戏地图掩码相关(msk)

本文详细介绍了游戏开发中地图的设计原理及服务器端如何解析地图数据。通过将地图划分为小格子并用特定的字节表示每个格子的状态,如是否可通行、是否有遮挡等,进而构建地图的整体结构。此外还探讨了地图数据结构的设计。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

      在游戏的世界里,玩家在地图上的某点,是否能够走动,是否遇到障碍,是否是走到了阴影处,是否水层等等先关信息都要我们前后端知道。

那么服务器是如何进行实现的呢。下面主要给大家讲讲。

     首先,我们知道图片是以像素为主要为单位进行计量,但是我们后端又不能使用这个东西,在二维的世界观里,我们是以坐标(x,y)具体的表现出其某个东西,所在的位置。因此,我们就要通过这个像素来表达出地点。

     

      想象一下啊,当我们确定到一个坐标的时候,但我们将其慢慢变大,那个小点就开始显示长宽。因此我们也用其原理。因此,我们是以将地图划分为很多个小格子,这些小格子,其实就代表了所谓的一个点,那么这个小格子是多大呢,这里我们一不超过50的为单位,作为长和宽。

      那这个小格子怎么样去表达具体的信息呢,处,每个因此,我们约定,用1个字节来表其信息,一个字节八位0000 0000,每个位具体可以表示什么含义,比如,第一位如果0表示可行走,1表示障碍。第二位0表示无遮掩,1表示遮掩。等,这里我就不一一举出。不同游戏有不同的具体表达信息。

       好,那么我们划分了很多歌小格子,每一行都有相同的小格子,那么我们就知道了这个地图,长有多少个各自,高有多少个格子。

设计一个结构体,头

struct tagMapHead
{
    int     m_width;//地图的宽
    int     m_height;地图的高
    short   m_tileSize;//小格子的变长
};


在这里,我们用了正方形表达,其实我们可以用长方形,我还见过菱形的,各个游戏不一样 。然后,头信息主要是这些,然后,将通过地图编辑器,把每个格子根据地图的基本信息,画图。然后通过工具具体生成。

头+包体。就生成了msk文件。

 

当前端生成了msk后,我们后端开始对其进行数据解析了。

服务端的具体存数据是

struct TMapMask
{
	int		m_iSize;
    int   m_lWidthMasks;
    int   m_lHeightMasks;
    int   m_lMaskPixelWidth;
    int   m_lMaskPixelHeight;

	MASK_BIT_TYPE   m_pMaskData[1];
};


 

根据msk二进制文件,后端进行解析,因为,我们每个地图,还有个基本的信息配置表,因此,我们就根据其掩码信息,将其一些数据附加到地图的结构体里。

比如,地图最大坐标,地图大小,按照我们的规定,这个地图有哪些动态区域。(动态区域,以后回去讲解),等等数据信息,供以后我们在地图上使用。

在这里地图掩码主要讲解完毕。

以后会将,我们是如何在地图上,看到玩家的。

 

 

制作标注数据集,标注的步骤是先利用arcmap合并河网数据,将河网数据转换成栅格数据,再利用Python程序对栅格数据进行切割输出多块图片,实现对大块的栅格数据自动裁剪,输出多个chip图片,程序自动检测数据边界,只需要输入数据集尺寸大小就行,标注的数据从https://www.hydrosheds.org/网站下载,自动裁剪的Python程序中涉及到rasterio库,自动裁剪程序如下:import os import rasterio from rasterio import windows import numpy as np def chip_it(image, mask, n_channels=5, size=256, stride_x=256, stride_y=256, out_dir='trainoutput'): os.makedirs(os.path.join(out_dir, 'images/positive'), exist_ok=True) os.makedirs(os.path.join(out_dir, 'images/background'), exist_ok=True) os.makedirs(os.path.join(out_dir, 'masks/positive'), exist_ok=True) os.makedirs(os.path.join(out_dir, 'masks/background'), exist_ok=True) with rasterio.open(image) as src: nodata_img = src.nodata # 获取源图像的nodata值 with rasterio.open(mask) as msk: nodata_msk = msk.nodata # 获取掩码的nodata值 img_width, img_height = src.width, src.height for row in range(0, img_height, stride_y): for col in range(0, img_width, stride_x): window = windows.Window(col_off=col, row_off=row, width=size, height=size) if col + size > img_width or row + size > img_height: continue chip_data = src.read(window=window, boundless=True) mask_data = msk.read(1, window=window, boundless=True) # 检查nodata并跳过包含nodata的窗口 if np.any(chip_data == nodata_img) or np.any(mask_data == nodata_msk): continue chip_data = chip_data.astype(np.float32) chip_data = np.clip(chip_data, 0, 1)#记得把tif归一化 if np.all(np.isfinite(chip_data)) and chip_data.shape == (n_channels, size, size): if np.any(mask_data == 1): chip_type = 'positive' else: chip_type = 'background' chip_name = f'{os.path.splitext(os.path.basename(image))[0]}_{col}_{row}.tif' with rasterio.open(os.path.join(out_dir, f'images/{chip_type}', chip_name), 'w', driver='GTiff', width=size, height=size, count=n_channels, dtype=chip_data.dtype) as dst: dst.write(chip_data) with rasterio.open(os.path.join(out_dir, f'masks/{chip_type}', chip_name), 'w', driver='GTiff', width=size, height=size, count=1, dtype=mask_data.dtype) as dst: dst.write(mask_data, 1) chip_it(r'E:\arcgisdata\2025.05.28\river_raster.tif', r'E:\arcgisdata\2025.05.28\river_mask.tif', out_dir='chip11') 程序最后的两个文件分别是什么文件,应该如何通过处理Arcmap得到?
06-16
#include <bits/stdc++.h> using namespace std; typedef long long ll; #define INF 0x7ffffff #define rep(i,s,t) for(register ll i = s;i <= t;++i) #define per(i,t,s) for(register ll i = t;i >= s;--i) const ll N = 25; const ll M = 1e5 + 5; struct node { ll x; ll y; ll rnk; bool operator < (const node& u) const { return rnk < u.rnk; } }; ll n; ll m; ll len; ll msk; ll ans = INF; ll dx[4] = {-1,0,1,0}; ll dy[4] = {0,1,0,-1}; vector <node> s; char a[N][N] = {}; bool vis[N][N][M] = {}; inline ll read() { ll x = 0; ll y = 1; char c = getchar(); while(c < '0' || c > '9') { if(c == '-') y = -y; c = getchar(); } while(c >= '0' && c <= '9') { x = (x << 3) + (x << 1) + (c ^ '0'); c = getchar(); } return x * y; } inline void write(ll x) { if(x < 0) { putchar('-'); write(-x); return; } if(x > 9) write(x / 10); putchar(x % 10 + '0'); } inline void bfs() { queue <tuple <ll,ll,ll,ll> > q; q.push({s[0].x,s[0].y,msk,0}); vis[s[0].x][s[0].y][msk] = true; while(!q.empty()) { auto [x,y,cur,stp] = q.front(); q.pop(); if(a[x][y] == '@') { ans = stp; break; } rep(i,0,3) { ll nx = x + dx[i]; ll ny = y + dy[i]; if(nx < 1 || nx > n || ny < 1 || ny > m || a[nx][ny] == '#') continue; ll cx = x; ll cy = y; bool flag = false; rep(i,0,len - 3) { cx += dx[(cur >> (i << 1)) & 3]; cy += dy[(cur >> (i << 1)) & 3]; if(nx == cx && ny == cy) { flag = true; break; } } if(flag) continue; ll pos = (i + 2) % 4; if(len > 2) { ll tmp = (1 << ((len - 2) << 1)) - 1; pos |= (cur & tmp) << 2; } if(!vis[nx][ny][pos]) { vis[nx][ny][pos] = true; q.push({nx,ny,pos,stp + 1}); } } } } int main() { cin >> n >> m; rep(i,1,n) { rep(j,1,m) { cin >> a[i][j]; if(a[i][j] >= '1' && a[i][j] <= '9') s.push_back({i,j,(ll)(a[i][j] - '0')}); } } sort(s.begin(),s.end()); len = s.size(); rep(i,1,len - 1) { ll nx = s[i].x - s[i - 1].x; ll ny = s[i].y - s[i - 1].y; rep(j,0,3) { if(nx == dx[j] && ny == dy[j]) { msk |= (j << ((i - 1) << 1)); break; } } } bfs(); if(ans == INF) cout << -1; else cout << ans; return 0; }请详细解释上述代码每一行每一个操作的直接作用和整体功能,特别是位运算的原理
最新发布
07-18
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值