如何看地图 游戏中逆战左上角小地图的地图怎么用

《MFC游戏开发》笔记十 游戏中的碰撞检测进阶:地图类型&障碍物判定 - 推酷
《MFC游戏开发》笔记十 游戏中的碰撞检测进阶:地图类型&障碍物判定
本系列文章由七十一雾央编写,转载请注明出处。
作者:七十一雾央 新浪微博:
& & & 在这个教程中主要内容是2D游戏,关于3D游戏,雾央也还在努力学习之中,等以后有时间,一定会把自己学到的知识分享给大家,所以这一节中主要讲解的就是2D游戏中的障碍物判定了,45度地图以后要有时间雾央会讲。
& & & 上一节中讲解了近似的矩形判定,这是一种比较常用的判定方式,很适合于两个移动的物体之间,比如很多跳跃类游戏中移动的台阶和人物之间的碰撞,但是在地图障碍物判定上就显得有些力不从心了。这一节雾央将会给大家讲解几种新的碰撞检测方法,对于新手朋友们可能内容略多,不过只要认真阅读,多思考思考,应该是不难理解的,如果有什么问题,欢迎大家留言讨论。
在玩游戏的时候,有些河流断崖等地方是不能通过的,高处跳跃落下的时候是不会穿过地平线的,石头挡着的地方是绝对不能路过的…………这些检测都属于地图障碍物判定的范围。
& & & 大家在开发游戏的时候,地图的结构类型不同,采用的障碍物判定一般也就不同,地图类型和障碍物检测联系密切,因此雾央会介绍一下不同地图类型可以采取的方法。
& & & 在介绍之前,雾央必须要说明一个前提:在雾央的教程里,做碰撞检测时,人物都是使用最小外接矩形进行的。大家当然可以逐像素进行,即遍历整个人物矩形,当检测到人物图形和背景图片在同一位置都具有像素且是障碍物的时候,即发生碰撞。这样去掉了人物图片透明处带来的误差,但是太过于低效,雾央觉得大家初学游戏没有必要追求这么高的精确度,同时也可以大大简化问题。
一、TileMap
& & & 现在在家的同学请回头看一下背后,嗯,什么诡异的事情都没有发生,呵呵,开个玩笑了。我们要看的其实是地面,大家看到的是不是像下面这样?
& & & 这个地面是雾央在网上找的一张图,大家想象一下,如果将其中的某些块瓷砖画上石头,画上树木、房屋等,在把瓷砖之间的分界线给隐藏起来,比如下面这样,那么它像什么?
& & & 应该说它就是一张2D游戏中的地图!
& & & 这种类型的地图叫“TileMap”,Tile就是瓷砖的意思,每一块瓷砖我们可以认为是一种地图元素,使用几种不同的地图元素,我们就可以拼出不同的地图,制造地图的过程一般通过地图编辑器进行,这种地图的特征就是网格形。
& & & 不知道大家还记不记得小时候在小霸王学习机上玩过的坦克大战?它支持自定义地图,那个部分如果拆分出来就是一个地图编辑器,我们可以选择土墙、钢铁墙、草丛、河流等很多种元素然后自己确定摆放位置,制造出一张地图来进行游戏,这就是TileMap,PS:雾央记得那时候最喜欢用钢铁墙将路封死,只留一个入口,然后守在哪里,呵呵。
& & & 这种地图比较简单,程序实现障碍物判定也很容易。因为我们用地图编辑器生成地图的时候,可以保存一个二维数组,指明某个方块的信息。在程序中读取这个二维数组,显示地图,进行障碍物判定。
& & & 在TileMap中进行障碍物判定是非常容易的事情,人物每次移动时,都检测前方是否是障碍物即可。人物的移动并不一定要是按网格移动,仍然是可以按像素移动的,当然按网格移动是最简单的,比如推箱子这种游戏。
& & & TileMap要求的就是障碍物比较规则,并且是网格大小的整数倍,否则就会出现比较假的情况。
& & & 下面给出一个TileMap的例子,看起来是不是很挫的感觉~~(╯﹏╰)b
& & & 下面的图像也是通过TileMap实现的,看起来是不是好了很多?
& & & TileMap对于游戏在表现力上强烈的需求,灵活的操作性来说有点力不从心,制造出的地图很多看起来都有四四方方的感觉,因此最适合于简单休闲的小游戏,比如坦克大战,推箱子,泡泡堂等,在有些大型游戏中也可能会使用到。但是TileMap也有自己独特的优点,仅仅使用几种有限的图元就可以组合出无穷多的各异的地图,并且很省内存空间,毕竟只需要加载几种小图元即可,比如说在沙漠、草原等整个场景风格近似的地图等。某种程度上来说,TileMap是把像素放大了几十倍,相比于逐像素处理来说,现在只需要按网格处理了,因此更便于操作。
二、横版台阶地图
& & & 雾央也不知道那种普普通通常见的地图叫什么,就暂且叫做横版台阶地图好了。这里雾央说的是那种障碍物可以随意摆放的地图,并不要求处在特定网格中,这样在游戏中的灵活性也就高了许多。比如下面这种
& & & 在这样的地图中,要实现障碍判定,有多种方式。
& & & 一种可行的是记录下每个台阶所在的矩形区域坐标范围,然后在程序中判断,情况同TileMap差不了太多,都比较简单可行,但是可能需要遍历每个台阶,比较麻烦。
& & & 另一种通过蒙版图进行,这个要方便了很多,但是有一个很大的缺憾,要求障碍物固定,对于那些移动的台阶就无能为力,或者需要额外添加判定。
& & & 雾央首先介绍一下蒙版图的概念,举个例子大家就明白了。
& & & 比如下面是一张背景图片
& & & 下面这张图就是它的蒙版图
& & & 大家应该明白了吧?就是将图中的障碍物地方用黑色表示,可以通行的地方用白色表示。那么我们在程序中只需要判定人物要移动到的位置是不是黑色,如果是黑色就不可以通过,否则就可以经过了。事实上可以认为,它是一种特殊的TileMap,只不过每个Tile的大小是一个像素,每个Tile用1表示可以通过,0表示不可通行而已。
& & & 明白了这个原理后,雾央相信写成代码应该不是难事,大家可以自己尝试下,雾央待会会附上使用蒙版图判定的详细代码,在障碍物判定上,同样分水平方向和垂直方向,雾央只会以垂直方向示例,水平方向同理,留待大家自己完成。
& & & 对了,大家之前一直使用的是CImage贴图,这个类功能很强大,它的一个成员函数GetPixel(x,y)可以获取xy处的像素,返回值为
类型, 它是32-bit 整型数值,代表了一种颜色。你可以使用 RGB 宏生成颜色变量来和它进行比较,注意x的范围是0到width,y的范围是0到height,包括起始点,但不包括终点,超过范围是会弹出错误框框的哦。在雾央的程序里面,是没有对人物离开地图范围进行判定的,所以大家如果操纵人物离开了窗口范围,再进行上下移动是会看到错误框的,这个由大家自己加上,比较简单。
& & & 判断是否可以通行的代码可以如同下面这样:
//是否可以通行的判断
bool CChildView::CanPass()
//水平方向的雾央省略了,留给大家自己完成
if(MyHero.direct==LEFT || MyHero.direct==RIGHT )
for(int x=MyHero.x;x&MyHero.x+MyHero.x++)
//检测的宽度是人物的宽度
//雾央在这里偷了个懒,只检测了人物下一时刻要到达的位置,即MyHero.y-5处
//万一障碍物很薄,只有2个像素宽之类的,就会失效
//主要是因为以后人物的移动方式不会是这种位移直接增加的方式,所以雾央在这里主要是介绍一下思想
//在流畅动画那一节中,雾央会重新讲解,以后会给出新的demo
if(MyHero.direct==UP)
//方向向上时
if(m_bgblack.GetPixel(x,MyHero.y-5)==RGB(0,0,0))
//遇到黑色像素返回false
else if(MyHero.direct==DOWN)
//方向向下时
//向下时,记得加上人物的宽度,因为人物的xy位置是它的左上角坐标
if(m_bgblack.GetPixel(x,MyHero.y+MyHero.height+5)==RGB(0,0,0))
//遇到黑色像素返回false
现在我们来看看运行的效果吧
& & 向上走,走不了啊 &
& & 那往下走吧,还是走不了。。。
& & 呼,写到这里,雾央发现已经比以前写的内容似乎都要多,不知道大家觉得怎么样?雾央本来还打算讲解一下游戏中斜坡的情况,有时间还想讲解一下45度地图的情况,现在看来只好放到下一讲去了,那之前说好的流畅动画等又得往后推一推了,~~(╯﹏╰)b
三、源代码
// ChildView.h : CChildView 类的接口
#pragma once
#define SNOW_NUMBER 100
//雪花例子的数量
// CChildView 窗口
class CChildView : public CWnd
CChildView();
//人物结构体
struct charcter
//保存人物的图像
//保存人物的位置
//人物的方向
//运动到第几张图片
//图片的宽度和高度,用于碰撞判定
//保存客户区大小
//背景图片
CImage m_ //背景蒙版图
CDC m_cacheDC;
CBitmap m_cacheCB//缓冲位图
protected:
virtual BOOL PreCreateWindow(CREATESTRUCT& cs);
virtual ~CChildView();
// 生成的消息映射函数
protected:
afx_msg void OnPaint();
DECLARE_MESSAGE_MAP()
bool CanPass();
afx_msg void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags);
afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
afx_msg void OnTimer(UINT_PTR nIDEvent);
afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
//-----------------------------------【程序说明】----------------------------------------------
// 【MFC游戏开发】笔记十 障碍判定进阶 配套源代码
// VS2010环境
// 更多内容请访问雾央CSDN博客 http://blog.csdn.net/u/article/category/1497651
// 雾央的新浪微博: @七十一雾央
//------------------------------------------------------------------------------------------------
// ChildView.cpp : CChildView 类的实现
#include &stdafx.h&
#include &GameMFC.h&
#include &ChildView.h&
#include &mmsystem.h&
#pragma comment(lib,&winmm.lib&)//导入声音头文件库
#ifdef _DEBUG
#define new DEBUG_NEW
//定时器的名称用宏比较清楚
#define TIMER_PAINT 1
#define TIMER_HEROMOVE 2
//四个方向
#define DOWN 0
#define LEFT 1
#define RIGHT 2
#define UP 3
//窗口大小
#define WINDOW_WIDTH 800
#define WINDOW_HEIGHT 600
// CChildView
CChildView::CChildView()
CChildView::~CChildView()
mciSendString(&stop bgMusic &,NULL,0,NULL);
BEGIN_MESSAGE_MAP(CChildView, CWnd)
ON_WM_PAINT()
ON_WM_KEYDOWN()
ON_WM_LBUTTONDOWN()
ON_WM_TIMER()
ON_WM_CREATE()
END_MESSAGE_MAP()
//将png贴图透明
void TransparentPNG(CImage *png)
for(int i = 0; i &png-&GetWidth(); i++)
for(int j = 0; j &png-&GetHeight(); j++)
unsigned char* pucColor = reinterpret_cast&unsigned char *&(png-&GetPixelAddress(i , j));
pucColor[0] = pucColor[0] * pucColor[3] / 255;
pucColor[1] = pucColor[1] * pucColor[3] / 255;
pucColor[2] = pucColor[2] * pucColor[3] / 255;
// CChildView 消息处理程序
BOOL CChildView::PreCreateWindow(CREATESTRUCT& cs)
if (!CWnd::PreCreateWindow(cs))
return FALSE;
cs.dwExStyle |= WS_EX_CLIENTEDGE;
cs.style &= ~WS_BORDER;
cs.lpszClass = AfxRegisterWndClass(CS_HREDRAW|CS_VREDRAW|CS_DBLCLKS,
::LoadCursor(NULL, IDC_ARROW), reinterpret_cast&HBRUSH&(COLOR_WINDOW+1), NULL);
//-----------------------------------游戏数据初始化部分-------------------------
//加载背景
m_bg.Load(&bg.png&);
m_bgblack.Load(&bgblack.png&);
//加载英雄图片
MyHero.character.Load(&heroMove.png&);
TransparentPNG(&MyHero.character);
MyHero.width=80;
MyHero.height=80;
//初始化英雄状态
MyHero.direct=UP;
MyHero.frame=0;
//设置英雄初始位置
MyHero.x=80;
MyHero.y=400;
//打开音乐文件
mciSendString(&open background.mp3 alias bgMusic &, NULL, 0, NULL);
mciSendString(&play bgMusic repeat&, NULL, 0, NULL);
return TRUE;
void CChildView::OnPaint()
//获取窗口DC指针
CDC *cDC=this-&GetDC();
//获取窗口大小
GetClientRect(&m_client);
//创建缓冲DC
m_cacheDC.CreateCompatibleDC(NULL);
m_cacheCBitmap.CreateCompatibleBitmap(cDC,m_client.Width(),m_client.Height());
m_cacheDC.SelectObject(&m_cacheCBitmap);
//————————————————————开始绘制——————————————————————
//贴背景,现在贴图就是贴在缓冲DC:m_cache中了
m_bg.Draw(m_cacheDC,0,0,WINDOW_WIDTH,WINDOW_HEIGHT,0,0,WINDOW_WIDTH,WINDOW_HEIGHT);
MyHero.character.Draw(m_cacheDC,MyHero.x,MyHero.y,80,80,
MyHero.frame*80,MyHero.direct*80,80,80);
//最后将缓冲DC内容输出到窗口DC中
cDC-&BitBlt(0,0,m_client.Width(),m_client.Height(),&m_cacheDC,0,0,SRCCOPY);
//————————————————————绘制结束—————————————————————
//在绘制完图后,使窗口区有效
ValidateRect(&m_client);
//释放缓冲DC
m_cacheDC.DeleteDC();
//释放对象
m_cacheCBitmap.DeleteObject();
//释放窗口DC
ReleaseDC(cDC);
//是否可以通行的判断
bool CChildView::CanPass()
//水平方向的雾央省略了,留给大家自己完成
if(MyHero.direct==LEFT || MyHero.direct==RIGHT )
for(int x=MyHero.x;x&MyHero.x+MyHero.x++)
//检测的宽度是人物的宽度
//雾央在这里偷了个懒,只检测了人物下一时刻要到达的位置,即MyHero.y-5处
//万一障碍物很薄,只有2个像素宽之类的,就会失效
//主要是因为以后人物的移动方式不会是这种位移直接增加的方式,所以雾央在这里主要是介绍一下思想
//在流畅动画那一节中,雾央会重新讲解,以后会给出新的demo
if(MyHero.direct==UP)
//方向向上时
if(m_bgblack.GetPixel(x,MyHero.y-5)==RGB(0,0,0))
//遇到黑色像素返回false
else if(MyHero.direct==DOWN)
//方向向下时
//向下时,记得加上人物的宽度,因为人物的xy位置是它的左上角坐标
if(m_bgblack.GetPixel(x,MyHero.y+MyHero.height+5)==RGB(0,0,0))
//遇到黑色像素返回false
//按键响应函数
void CChildView::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
//nChar表示按下的键值
switch(nChar)
//游戏中按下的键当然应该不区分大小写了
MyHero.direct=RIGHT;
MyHero.x+=5;
MyHero.direct=LEFT;
MyHero.x-=5;
MyHero.direct=UP;
if(CanPass())
MyHero.y-=5;
MyHero.direct=DOWN;
if(CanPass())
MyHero.y+=5;
//鼠标左键单击响应函数
void CChildView::OnLButtonDown(UINT nFlags, CPoint point)
char bufPos[50];
sprintf(bufPos,&你单击了点X:%d,Y:%d&,point.x,point.y);
AfxMessageBox(bufPos);
//定时器响应函数
void CChildView::OnTimer(UINT_PTR nIDEvent)
switch(nIDEvent)
case TIMER_PAINT:OnPaint();
//若是重绘定时器,就执行OnPaint函数
case TIMER_HEROMOVE:
//控制人物移动的定时器
MyHero.frame++;
//每次到了间隔时间就将图片换为下一帧
if(MyHero.frame==4)
//到最后了再重头开始
MyHero.frame=0;
int CChildView::OnCreate(LPCREATESTRUCT lpCreateStruct)
if (CWnd::OnCreate(lpCreateStruct) == -1)
return -1;
在此添加您专用的创建代码
//创建一个10毫秒产生一次消息的定时器
SetTimer(TIMER_PAINT,10,NULL);
//创建人物行走动画定时器
SetTimer(TIMER_HEROMOVE,100,NULL);
& 雾央今天听到一首很好听的歌,吴琼的《故人叹》,就作为背景音乐了,希望大家喜欢咯。
《MFC游戏开发》笔记九到这里就结束了,更多精彩请关注下一篇。如果您觉得文章对您有帮助的话,请留下您的评论,点个赞,能看到你们的留言是我最高兴的事情,因为这让我知道我正在帮助曾和我一样迷茫的少年,你们的支持就是我继续写下去的动力,愿我们一起学习,共同努力,复兴国产游戏。
& & &对于文章的疏漏或错误,欢迎大家的指出。
已发表评论数()
请填写推刊名
描述不能大于100个字符!
权限设置: 公开
仅自己可见
正文不准确
标题不准确
排版有问题
主题不准确
没有分页内容
图片无法显示
视频无法显示
与原文不一致扫二维码浏览器手机版
打开微信,扫一扫我吧
当前位置: >
梦幻西游手游怎样查看大地图 怎样确定自己的位置
梦幻西游手游剧情任务虽然可以自动寻路,地图切换也是手机点击就可以解决的问题。就是这样所以有些新手就不知道怎样看大地图,怎样确定自己的位置,下面就和小编一起来看下梦幻西游手游怎样观看地图和确定自己的位置吧!梦幻西游手游怎样查看大地图在梦幻西游手游主界面左上角中有玩家当前所处地区以及坐标信息,玩家看了还是无法确定自己的位置可以在一次点击它们,就能出现梦幻西游手游的大地图了!怎样确定自己的位置:上图就是梦幻西游手游中的世界地图了!左上角的转换图标就可以切换世界地图和小地图了。而玩家的小头像则代表玩家当前所处位置!通过对比就很容易知道玩家当前所处位置啦!相关推荐:更多梦幻西游手游攻略,尽在
【责任编辑:W,Dear】
相关推荐标签:无王者荣耀游戏里面不能滑动看周围的地图了,怎么回事?_王者荣耀吧_百度贴吧
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&签到排名:今日本吧第个签到,本吧因你更精彩,明天继续来努力!
本吧签到人数:0可签7级以上的吧50个
本月漏签0次!成为超级会员,赠送8张补签卡连续签到:天&&累计签到:天超级会员单次开通12个月以上,赠送连续签到卡3张
关注:3,082,494贴子:
王者荣耀游戏里面不能滑动看周围的地图了,怎么回事?
绝对不是内存不够
我个人对新地图的理解...
变大,雕像也越来越好,来...
好像是已经走到尽头了~~...
66级王者地图过四章,想...
我用盖伦带个蓝别人骂我...
常识完全没有,新人一只...
缺牙要及时修复,揭秘种植牙如何做到几十年不掉?
为什么啊啊啊啊啊
游戏在左下角左手控制行走
左上角是大地图
右下角右手控制是三个技能按钮
右上角就是空白。我用之前手机在这个空白的地方用手滑动 屏幕也会跟着走。现在换手机了 滑动屏幕完全不会动
没有人能告诉我么
我该怎么办
我也是,不过我是原来有那个,后来卸载了,重新安装就没了,感觉不好用啊,好不爽。求解怎么弄回来,我QQ
键盘滑动就行了
贴吧热议榜
使用签名档&&
保存至快速回贴

我要回帖

更多关于 伊苏8地图左上角 的文章

 

随机推荐