我的编程空间,编程开发者的网络收藏夹
学习永远不晚

基于Matlab制作伪3D第一视角迷宫小游戏

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

基于Matlab制作伪3D第一视角迷宫小游戏

游戏效果

使用键盘上方向键↑向前移动

使用键盘左右方向键调整← →朝向

游戏原理说明

原理很简单,如效果图所示,主要就是以角色视角方向发射大量的直线模拟视线,并计算直线与墙壁交点,获取每一条视线方向下,角色到墙壁的距离,然后根据近大远小的原理绘制不同长度的竖向直线模拟墙壁。

第一代程序计算交点方法

第一代程序是使用的polyshape对象(二维多边形对象)制作墙壁,polyshape对象重载了函数intersect,可以直接求出直线与多边形的交集,程序编写更加简洁方便,给个检测直线和多边形交点的官方例子:

创建一个矩形多边形和一个线段:

poly1=polyshape([0 0 1 1],[1 0 0 1]);
lineseg=[-1 -1;1.5 1.5];

计算该多边形与线段的交集,并确定线段的哪些部分在多边形的内部,哪些在其外部。

[in,out] = intersect(poly1,lineseg);
plot(poly1)
hold on
plot(in(:,1),in(:,2),'b',out(:,1),out(:,2),'r')
legend('Polygon','Inside','Outside','Location','NorthWest')

我们可以把内部第一个点和最后一个点看作与多边形边缘的交点:

intersectPnt=[in(1,:);in(end,:)]

intersectPnt =
0 0
1 1

但是!:这样的计算方法较缓慢,而且polyshape对象推出时间较晚(至少需要R2017B),

于是该方案被舍弃!!

于是该方案被舍弃!!

于是该方案被舍弃!!

第二代程序计算交点方法

假设角色当前位置为p0=(x0, y0) ,角色当前面向方向为θ0,将所有的墙壁边缘离散成点集合,其点到角色位置方向向量为:

每个视线方向向量

做内积:

那么INN矩阵的每个数值都是角色到一个墙壁点方向向量与角色某一视线方向做内积,要考虑到视线为单方向射线,因此将内积为负数的值置为无穷大:INN(INN<0)=inf,之后因为明显和视线越垂直算出的距离越短,但这不是我们想要的,因此要添加新的约束,就是内积值和实际的点到角色的距离差值要小于一定阈值1e-5,添加这个约束后,找到INN矩阵每一列的最小值即可找到每一视线方向最近的墙壁点。

距离转换为线段长度

使用的如下公式:

其中α为常数,L为墙壁点到角色距离,θ为视线和角色面朝方向的夹角。

完整代码

function maze2_5D_v2
% @author : slandarer
% @公众号 : slandarer随笔
% @知乎   : hikari
help maze2_5D

%% ========================================================================
% figure窗口创建
fig=figure();
fig.Position=[50,60,1200,600];
fig.Name='maze 2.5D by slandarer';
fig.NumberTitle='off';
fig.MenuBar='none';
% 俯视图axes坐标区域
ax2D=axes('Parent',fig);
ax2D.XTick=[];ax2D.XColor='none';
ax2D.YTick=[];ax2D.YColor='none';
ax2D.XLim=[0,15];
ax2D.YLim=[0,15];
ax2D.Color=[0,0,0];
ax2D.Position=[0,0,1/2,1];
hold(ax2D,'on')
% 伪3D图axes坐标区域
ax3D=axes('Parent',fig);
ax3D.XTick=[];ax2D.XColor='none';
ax3D.YTick=[];ax2D.YColor='none';
ax3D.XLim=[0,10];
ax3D.YLim=[0,10];
ax3D.Color=[0,0,0];
ax3D.Position=[1/2,0,1/2,1];
hold(ax3D,'on')
%% ========================================================================
% 左侧俯视地图初始化
mazeMat=[1 1 1 1 1 1 1 1 1 1 1 1 1 1 1;
         1 0 0 0 0 0 1 0 1 0 1 0 0 0 1;
         1 1 1 1 1 0 1 0 0 0 1 1 1 0 1;
         1 0 0 0 1 0 1 0 1 0 1 0 0 0 1;
         1 0 1 1 1 0 0 0 1 0 0 0 1 1 1;
         1 0 0 0 0 2 1 1 1 0 1 1 1 0 1;
         1 0 1 0 1 1 1 0 1 0 0 0 1 0 1;
         1 0 1 0 0 0 0 0 1 1 1 0 1 0 1;
         1 0 1 1 1 1 1 1 1 0 1 0 0 0 1;
         1 0 1 0 0 0 0 0 0 0 1 0 1 0 1;
         1 0 1 1 1 1 1 0 1 0 1 0 1 0 1;
         1 0 1 0 1 0 1 0 1 0 0 0 1 0 1;
         1 0 1 0 1 0 1 0 1 1 1 1 1 0 1;
         1 0 0 0 0 0 0 0 1 0 0 0 0 0 1;
         1 1 1 1 1 1 1 1 1 1 1 1 1 1 1];
[rowList,colList]=find(mazeMat==1);
sqX=[-1;0;0;-1];sqY=[-1;-1;0;0];
LSList=linspace(-1,0,250)';
NMList=-ones(size(LSList));
FLList=[[LSList,NMList];[LSList,NMList.*0];[NMList,LSList];[NMList.*0,LSList]];

BLOCK.pntSet=zeros(2,0);
for n=1:length(rowList) 
    fill(ax2D,sqX+colList(n),sqY+size(mazeMat,1)+1-rowList(n),[1,1,1].*0.9);
    BLOCK.pntSet=[BLOCK.pntSet;FLList+repmat([colList(n),size(mazeMat,1)+1-rowList(n)],[size(FLList,1),1])];
end
% -------------------------------------------------------------------------
% 角色创建
[trow,tcol]=find(mazeMat==2);
ROLEP.xpos=tcol-0.5;
ROLEP.ypos=size(mazeMat,1)+0.5-trow;
ROLEP.theta=pi/2;
ROLEP.triX=cos([pi/3,pi,-pi/3]).*0.15;
ROLEP.triY=sin([pi/3,pi,-pi/3]).*0.15;
[tX,tY]=rotateData(ROLEP.triX,ROLEP.triY,ROLEP.theta);
ROLEP.pfill=fill(ax2D,tX+ROLEP.xpos,tY+ROLEP.ypos,[1,1,1]);
ROLEP.pshape=polyshape(tX+ROLEP.xpos,tY+ROLEP.ypos);
ROLEP.viewRange=size(mazeMat,1)*sqrt(2);
%% ========================================================================
% 线条创建
% plot(ax3D,[1,1].*10.*i./length(thetaListV),[5-tLen/2,5+tLen/2],...
% 'LineWidth',1.5,'Color',[1,1,1]./10.*tLen,'Tag','blockLine');
% plot(ax2D,[RP.xpos,RP.xpos+cos(thetaList(i))*abs(minList(i))],[RP.ypos,RP.ypos+sin(thetaList(i))*abs(minList(i))])
lineNum=300;

for n=1:lineNum
    PLINE.plotLine3(n)=plot(ax3D,[1,1].*10.*n./lineNum,[-1,-1],'LineWidth',1.5);
    PLINE.plotLine2(n)=plot(ax2D,[-1,-1],[-1,-1],'Color',lines(1));
end


draw3D(ROLEP,BLOCK,PLINE,lineNum)
%% ========================================================================
% 角色移动函数
set(fig,'KeyPressFcn',@key)
function key(~,event)
    %按键函数
    switch event.Key
        case 'uparrow'
            ROLEP.xpos=ROLEP.xpos+cos(ROLEP.theta).*.2;
            ROLEP.ypos=ROLEP.ypos+sin(ROLEP.theta).*.2;
        case 'leftarrow'
            ROLEP.theta=ROLEP.theta+pi/20;
        case 'rightarrow'
            ROLEP.theta=ROLEP.theta-pi/20;
    end
    [tX,tY]=rotateData(ROLEP.triX,ROLEP.triY,ROLEP.theta);
    ROLEP.pfill.XData=tX+ROLEP.xpos;
    ROLEP.pfill.YData=tY+ROLEP.ypos;
    ROLEP.pshape=polyshape(tX+ROLEP.xpos,tY+ROLEP.ypos);
    draw3D(ROLEP,BLOCK,PLINE,lineNum)
end
%% ========================================================================
% 视角检测及伪3D图绘制
    function draw3D(RP,BK,PLINE,LN)
    % delete(findobj('Tag','blockLine'))
    thetaListV=linspace(pi/3,-pi/3,LN);
    thetaList=thetaListV+RP.theta;
    % 内积法计算距离
    cutoff=1e-5;
    cosList=cos(thetaList);
    sinList=sin(thetaList);
    vecList=BK.pntSet-[RP.xpos,RP.ypos];
    disMat=vecList*[cosList;sinList];
    disMat(disMat<0)=inf;
    normList=vecnorm(vecList')';
    diffMat=abs(disMat-repmat(normList,[1,size(disMat,2)]));
    disMat(diffMat>cutoff)=inf;
    minList=min(abs(disMat));
    % 图像重绘
    for i=1:length(thetaList)
        tLen=10/abs(minList(i))/abs(cos(thetaListV(i))).*0.6;tLen(tLen>10)=10;
        PLINE.plotLine3(i).Color=[1,1,1]./10.*tLen;
        PLINE.plotLine3(i).YData=[5-tLen/2,5+tLen/2];
        PLINE.plotLine2(i).XData=[RP.xpos,RP.xpos+cos(thetaList(i))*abs(minList(i))];
        PLINE.plotLine2(i).YData=[RP.ypos,RP.ypos+sin(thetaList(i))*abs(minList(i))];
    end
end
%% ========================================================================
% 数据旋转角度
function [X,Y]=rotateData(X,Y,theta)
    rotateMat=[cos(theta),-sin(theta);sin(theta),cos(theta)];
    XY=rotateMat*[X;Y];
    X=XY(1,:);Y=XY(2,:);
end
end

以上就是基于Matlab制作伪3D第一视角迷宫小游戏的详细内容,更多关于Matlab迷宫游戏的资料请关注编程网其它相关文章!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

基于Matlab制作伪3D第一视角迷宫小游戏

下载Word文档到电脑,方便收藏和打印~

下载Word文档

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录