从零开始重写KOK1(万王之王1) —— (2)优化地图加载

本来想在第2篇说明物体遮挡与寻路的开发过程,但是因为我把这问题想简单了,现在已经完成了遮挡与寻路,但是中间的过程非常多,第一篇文章的系统结构需要做一些修改才可以,这里先说一下地图加载的相关问题。

 

首先是效果图:

KOK1 DEMO寻路

 

可直接运行版本下载:>>点击进入下载页<<

 

在第一篇文章《从零开始重写KOK1(万王之王1) —— (1)让人物可在地图上使用鼠标跑动》中,地图是这样的过程加载的:

1. 在Map对象初始化时将每个小图个加载到一个整体的大地图中,如图:

老地图管理器原理

2. 在玩家位置作出修改后,也修改屏幕矩形左上角的位置,因为玩家是在中间,所以要维持屏幕的x,玩家的x - 1/2屏幕宽,纵向同理。

以下是Player类的Move()中的代码,用来调整屏幕矩形的位置:

3. 要限制住玩家的位置,不能够使得屏幕矩形超出世界地图。在老的地图管理器是这样做的,限制玩家的目的坐标,不可以小于屏幕宽的一半,不可以大于世界地图宽度 - 屏幕宽的一半,纵向同理。这样就不会出现屏幕画地图外的情况了。但这样做就使得实际地图的内容小于了现在世界地图的大小,因为要在世界地图四周补上一圈黑色的贴图,这样玩家才知道到达了地图的边界。文字上可能不好理解,请看下图:

老地图管理器边界

这个图假定玩家走到了地图的右下角,因为屏幕矩形(蓝色框)不能超过世界地图,所以要在世界地图里面加这么一圈灰色的作为边界的纹理,所以也就说,实际的地图就比这个地图Data存放的要小了,这显然不是我们想要的。而且最重要的问题是,当地图非常之大时,这个超大的地图表面将占用巨大的显存或内存。

 

那么我们想要的地图管理器的目标就是:

——整个地图Data就是实际的地图,不包括边界纹理,当因为玩家的移动而导致屏幕矩形超出了地图范围时,自动补黑色。

 

要实现这种效果可以想到这种方法:地图表面大小= 屏幕大小,每一帧重画应当出现的地图块。但问题也随之而来,我们要在每1帧都去画一遍视窗内的地图,效率不高。那不如我们每次画一个区域的地图,当屏幕在这个区域内就不重画,而是裁剪适当的位置,当超出这个区域时,重新生成新区域,并且剪裁适当的地图,如下图:

新地图管理器

总结一下:

1. 首先确定屏幕矩形在当前地图表面内,在则不重画,直接剪裁适当位置,如果不在,进入2。

2. 重新绘制地图表面,根据屏幕矩形,计算地图表面中的每个小块:

    2.1 如果不在世界地图中,不处理,因为默认就是黑色。

    2.2 如果在,则计算是哪块世界地图,将适当的地图块话在这里。

3. 重新绘制后,剪裁适当的位置,画在离屏表面上。

 

下面贴出代码:

Map.h

 

Map.cpp

 

下面给出整个项目源码,因为最近的研究是一系列的,所以这个版本的源码已经有了遮挡、寻路等功能,但是后面的功能不影响Map的代码。

下载地址:>>点击进入下载页<< 资源分是1,有兴趣的朋友下吧:)

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 7
    评论
优化这段代码#include<stdio.h> #include<stdlib.h> #define MAXSIZE 6 //最大长度 typedef int QElemType; typedef struct { QElemType *base; //初始化的动态分配存储空间 int front; int rear; //下标 }SqQueue; enum Status{ERROR,OK}; //循环队列初始化 Status InitQueue(SqQueue &Q) { Q.base=new QElemType[MAXSIZE]; if(!Q.base) return ERROR; Q.front=Q.rear=0; //队空 return OK; } //入队 Status EnQueue(SqQueue &Q,QElemType e) { //添判断语句,如果rear超过max,则直接将其从a[0]重新开始存储,如果rear+1和front重合,则表示数组已满 if ((Q.rear+1)%MAXSIZE==Q.front) { return ERROR; } Q.base[Q.rear]=e; Q.rear=(Q.rear+1)%MAXSIZE; return OK; } //出队 Status DeQueue(SqQueue &Q,QElemType &e) { //如果front==rear,表示队列为空 if(Q.front==Q.rear) return ERROR; e=Q.base[Q.front]; //front不再直接 +1,而是+1后同max进行比较,如果=max,则直接跳转到 a[0] Q.front=(Q.front+1)%MAXSIZE; return OK; } //循环队列长度 int QueueLength (SqQueue Q) { return (Q.rear-Q.front+MAXSIZE)%MAXSIZE; } int main() { QElemType e; SqQueue Q; InitQueue(Q); printf("开始入队\n"); for(int i=0;i<MAXSIZE-1;i++) { scanf("%d",&e); EnQueue(Q,e); } printf("出一个队列元素:\n"); DeQueue(Q,e); printf("%d \n",e); printf("再入一个元素\n"); scanf("%d",&e); EnQueue(Q,e); printf("全部出队列\n"); for(i=0;i<MAXSIZE-1;i++) { DeQueue(Q,e); printf("%d ",e); } printf("此时循环队列长度为 :%d\n",MAXSIZE-1-QueueLength(Q)); return 0; }
最新发布
06-01

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值