精华内容
下载资源
问答
  • 基于MATLAB的拼图游戏设计 内容摘要:MATLAB强大的运算和图形展示功能,使图像处理变得更加的简单和直观。本博文基于MATLAB编程语言,详细介绍了如何利用MATLAB及其图像处理函数进行经典拼图游戏设计,并通过...

                                                                               基于MATLAB的拼图游戏设计

    内容摘要:MATLAB强大的运算和图形展示功能,使图像处理变得更加的简单和直观。本博文基于MATLAB编程语言,详细介绍了如何利用MATLAB及其图像处理函数进行经典拼图游戏设计,并通过具体方法步骤及相应代码逐步实现游戏的完美运行。(有详细步骤及代码解释,适合新手以及进阶的朋友参考)

    关键词:拼图游戏;MATLAB;数字图像处理
    本文为博主原创,引用请注明出处http://blog.csdn.net/qq_32892383

     1.前言 

          Matlab是MathWork公司推出的一套高性能的数值计算和可视化软件。它是一个高度集成的系统,集科学计算、图像处理、声音处理于一体,具有极高的编程效率。数字图像处理是一种通过计算机采用一定的算法对图形图像进行处理的技术。数字图像处理技术已经在各个领域上都有了比较广泛的应用。MATLAB强大的运算和图形展示功能,使图像处理变得更加的简单和直观。本文介绍了如何利用MATLAB进行经典拼图游戏设计。拼图游戏是一款非常经典的小游戏,因为它比较简单有趣,可变性很高且耐玩,有利于开发智力,帮助提高动手解决问题的能力。 

          拼图游戏的设计对一个MATLAB语言设计者进行语言提高和进阶都是一个很好的锻炼机会,说起来这个程序是笔者当年大学时完全自己构思摸索的第一个长的完整程序,作为一名刚接触编程语言的菜鸟,在痛苦与激动中整整花了一个星期才完成。如今我已是一名研究生,转眼再看过去写的那些程序,可能诸多不足但那些编程的锻炼确实让我感获良多,面对如今众多的研究课题时,入门编程让我可以从容地用编程语言去释放自己的思想,不必在有好想法时因为编程问题而浇灭灵感的火花。临近年关,辞旧迎新之际,外面的世界熙来攘往,早已沉浸着春节的热闹与喜悦中,我仍要挑个安静的时间总结反思过去一年各方面的得与失。一个想法划过脑海想把前面做过的程序做个整理和改进,分享出来希望能够给刚接触编程的朋友们一点帮助和启发,对于我也是一个总结与提高,期待我们今后一起能够继续学习和进步。

    2.MATLAB的图像处理 

          MATLAB的基本数据单位是矩阵,它的指令表达式与数学,工程中常用的形式十分相似,故用MATLAB来解算问题要比用C、FORTRAN等语言完相同的事情简捷得多。MATLAB支持五种图像类型,即索引图像、灰度图像、二值图像、RGB图像和多帧图像阵列。MATLAB中,一幅图像包含一个数据矩阵,RGB图像分别用红,绿,蓝三个亮度值为一组,代表每个像素的颜色。图像数组为M*N*3,M,N表示图像像素的行列数。MATLAB图像处理工具箱是由一系列支持图像处理操作的函数组成,可以进行诸如几何操作、线性滤波和滤波器设计、图像变换、图像分析与图像增强、二值图像操作以及形态学处理等图像处理操作。

          这里拼图游戏中的图像处理主要是对图像数组的操作,涉及矩阵分割、重组等步骤。本文将在后面几节结合代码进行详细介绍。

    3.设计步骤

          到此为止,前面的内容稍作了解即可,接下来的主要设计思路无需细看但了解大概的流程却是有必要的,毕竟编写程序前还是得清楚到底要做什么的,简洁清晰的设计方案能起到提纲挈领的作用。

          拼图游戏的主要思想是先读入准备好的图片,将存储图像的数据矩阵平均分为9个小的矩阵块,并用一个矩阵元素为1,2,3,4,5,6,7,8,0的3*3的数组矩阵标记每一个小矩阵块。仿照人工随机打乱拼图的方法,将标记矩阵打乱,根据标记矩阵拼接相应的拼图块并显示整个图像,通过设置图形窗口鼠标点击事件的回调函数的方式获得鼠标点击位置的坐标值,判断点击位置并移动相应的拼图块,当拼图顺序完全正确时提示游戏完成。图3.1和图3.2是拼图游戏的程序流程图。

                                                    

                                             图3.1 总体程序流程图(左图)               图3.2 回调函数程序流程图(右图)

          上面流程图的方式可能有点学术,但确实不失为一种好的叙述整个程序设计思想的表示方法。解释一下吧,为了使整个程序整洁清晰,图1中“打乱拼图矩阵”以及”按照标记矩阵显示拼图“步骤都写成了自定义函数,分别为disrupt( )、dramap( ),其功能及具体细节会在后面章节展开。接着需要得到点击鼠标的位置坐标,这里利用figure的WindowButtonDownFcn属性自行定义一个回调函数。此时每次当你在图上按下鼠标的时候,就会转而执行回调函数,整个程序处于监听鼠标事件与调用一次回调函数的循环之中,回调函数的流程如图2中所示。在回调函数中,计算鼠标点击坐标后,根据坐标移动拼图标记矩阵中的元素,这一步由自定义的函数movejig( )完成。然后根据标记矩阵刷新拼图图像,即调用dramap( )函数。最后判断拼图的标记矩阵中元素是否排列正确,如果顺序完全正确则提示游戏完成并结束程序,而不正确时则结束本次的回调函数继续等待鼠标点击。

    3.1 开始程序设计

          首先需要准备一张彩色图片,图片的尺寸最好为正方形(否则不易于后面的处理,而且可能不好看),这里我选择的图片是一张经过裁剪的长宽为300*300的图片,如下文件'jigsawImage.jpeg'

                                                                                         jigsawImage.jpeg

            在matlab中新建一个m文件,这里我命名的文件名为'jigsaw.m',为了方便两个文件放在同一文件夹下,如下图所示。

                                                                                         图3.1.1 文件存放情况

            准备好这些我们就可以正式开始编写程序了,所有代码编写在jigsaw.m文件中,下面将逐个介绍其中的代码及设计细节。

    3.2 分割拼图

          这里我们设计的是一个九宫格的拼图游戏,因此在打乱拼图前需要先将图片平均切割为相等的九份。首先我们来看看MATLAB中图片的储存与表示,执行命令”image=imread('jigsawImage.jpeg');“读入jigsawImage图片(若图片与m文件不在同一位置需输入绝对路径,如image=imread('C:\Users\Administrator\Desktop\jigsaw puzzle\jigsawImage.jpeg');)在MATLAB中的存储情况如图3.2.1所示。

                                                                                       图3.2.1 原图存放情况

          可以看出MATLAB中图片的存储是以矩阵的形式进行,image是个300*300*3的矩阵,300、300分别是矩阵的横纵尺寸。平均分割image矩阵,则第一块小拼图的数据矩阵可以为x1=image(1:100,1:100,:);这行代码的意思是选取image矩阵中横坐标从1到100,纵坐标也从1到100的那部分矩阵数据。可通过下面的代码验证,帮助简单理解

    image=imread('jigsawImage.jpeg'); %读入图片
    figure %产生一个图形窗口
    imshow(image) %显示原图
    axis on %显示坐标轴
    figure
    x1=image(1:100,1:100,:);%分割一个拼图块
    imshow(x1);
    axis on

    在命令窗口执行以上代码,可以看到如下运行结果

                                          

                                                                             图3.2.2 分割演示结果图

          将整幅图像平均分割成9块,为了方便每一块用一个数字表示,从左到右,从上到下开始将9个小拼图块分别标记为1,2,3,4,5,6,7,8,0;其位置及坐标系如图3.2.3所示

                                                                                              图3.2.3 拼图标记
          
          从上图中可以看到每块拼图在原图中的坐标位置,其实也是矩阵的索引范围,因此同样可以通过上面的方式引用标号为2,3,4,5,6,7,8,0的拼图块,代码如下
    x2=image(1:100,101:200,:);%拼图块2矩阵数据
    x3=image(1:100,201:300,:);%拼图块3矩阵数据
    x4=image(101:200,1:100,:);%拼图块4矩阵数据
    x5=image(101:200,101:200,:);%拼图块5矩阵数据
    x6=image(101:200,201:300,:);%拼图块6矩阵数据
    x7=image(201:300,1:100,:);%拼图块7矩阵数据
    x8=image(201:300,101:200,:);%拼图块8矩阵数据
    x0=image(201:300,201:300,:);%拼图块0矩阵数据
    

    按照上面的思路,现在自定义一个从原图中分割拼图并按照相应拼图块的标记截取小拼图的函数choose( ),输入参数为image,index,其中image为原图的数据矩阵,index为要选择的拼图块的标记;输出为x,x是标记为index的小拼图块的数据矩阵。代码如下

    function x = choose(image,index)
    %% 根据索引选择对应位置上的拼图块
    if index > 0 %标记为1,2,3,4,5,6,7,8的拼图块
        % 计算出行数row以及列数column
        row=fix((index-1)/3);
        column=mod(index-1,3);
        % 分割出对应拼图块数据
        x=image(1+row*100:100*(row+1),1+column*100:100*(column+1),:);
    else
        x=uint8(255*ones(100,100,3));%拼图块0矩阵数据
    end
          首先第3到第6行中当index为1,2,3,...,8时先计算出行数row以及列数column,行数可通过求除以3后的商确定,fix( )是MATLAB中的取整函数,而列数可通过求余数确定,mod( )是求余函数,返回index-1除以3的余数。为了便于按照上面的方法分割矩阵,这里的row、column相当于一个倍数,如x=image(1+row*100:100*(row+1),1+column*100:100*(column+1),:);则将行列数乘分割间隔100(因为选择的图片大小是300*300的,分成3*3的拼图块所以索引间隔为100,若为其他尺寸的图片应为长宽分别除以3后的结果)即可根据行列数row,column引用相应位置上的小拼图块的数据矩阵了。例如index=4时,经过第5,6行代码计算出的row=1,column=0,代入第8行代码中,则实际x=image(1+1*100:100*2,1+0*100:100*1,:);这与前面代码中写出的”x4=image(101:200,1:100,:);%拼图块4矩阵数据“作用一致。
          当index=0时则执行第9行else下的代码部分,你可能会奇怪,为什么拼图块0不是从imge矩阵中分割而是放到else中了?这是因为0这个位置比较特殊,留作空白处,拼图游戏进行时当空白处附近某个拼图块被点击时,该拼图块就会移动到这个空白位置。这里ones( )函数产生一个100*100*3的全1矩阵,乘255则像素灰度值最亮,显示为全白,最后uint8( )统一数据类型。因此当index=0时,执行else中的代码,输出x为一块全白的拼图块。
     

    3.3 按标记序号矩阵显示拼图

          前面一节介绍了可以通过标记序号分割原图获得小拼图块数据矩阵的方法,一幅拼图可由9块小拼图块拼接而成,因此用一个9个元素的标记矩阵,每个位置上的元素值作为一个标记序号表示相应位置的拼图块,就可以通过这个标记矩阵表示整个的拼图了。          

          这样原图就可以用矩阵 表示,而任意打乱的拼图也可以通过改变矩阵相应位置上的元素值表示了。现在我们编写一个根据标记矩阵显示对应拼图的函数drawmap( ),输入参数为A,A为一幅拼图的标记矩阵,A大小为3*3。代码如下

    function drawmap(A)
    %% 将运算数字与对应拼图对应显示图片
    origin=imread('jigsawImage.jpeg');
    image=origin;
    
    % 对要显示的拼图进行赋值
    for row=1:3
        for col=1:3
        image(1+(row-1)*100:100*row,1+(col-1)*100:100*col,:)=choose(origin,A(row,col));
        end
    end
    
    imshow(image)%显示拼图

          第3行代码读入图片并将原图数据矩阵存储在origin中;第4行中image是要显示的拼图数据矩阵,先预定义与origin相同。接下来对image进行逐个赋值,image每一块数据的赋值通过调用前面编写的choose( )函数完成;第9行中”choose(image,A(row,col))“返回标记矩阵A中第row行第col列的元素表示的那一块拼图块的数据矩阵,而前面的一半image(1+(row-1)*100:100*row,1+(col-1)*100:100*col,:)与3.2节中选取每个拼图块的作用类似,这里用于对行数row从1到3,列数col从1到3的拼图块矩阵上的元素逐个赋值。经过9次循环9处拼图块的数据赋值完成,最终显示图像image。可以通过下面的代码简单测试一下drawmap( )函数,设置一个标记矩阵Tag_A=[8 4 5;6 0 3;1 7 2],即Tag_A= ,按照该矩阵显示这幅拼图。

    function jigsaw()
    %% 主函数
    Tag_A=[8 4 5; 6 0 3; 1 7 2];
    drawmap(Tag_A);%按照标记矩阵显示拼图
    
    
    function x = choose(image,index)
    %% 根据索引选择对应位置上的拼图块
    if index>0 %标记为1,2,3,4,5,6,7,8的拼图块
        % 计算出行数row以及列数column
        row=fix((index-1)/3);
        column=mod(index-1,3);
        % 分割出对应拼图块数据
        x=image(1+row*100:100*(row+1),1+column*100:100*(column+1),:);
    else
        x=uint8(255*ones(100,100,3));%拼图块0矩阵数据
    end
    
    
    function drawmap(A)
    %% 将运算数字与对应拼图对应显示图片
    origin=imread('jigsawImage.jpeg');
    image=origin;
    % 对要显示的拼图进行赋值
    for row=1:3
        for col=1:3
        image(1+(row-1)*100:100*row,1+(col-1)*100:100*col,:)=choose(origin,A(row,col));
        end
    end
    imshow(image)%显示拼图

          运行结果如下图所示,对比每个拼图块的标记可以看出函数能实现根据矩阵的值显示拼图了,距离成功又近了一步。

                                                                                         图3.3.1 测试结果

    3.4 移动拼图

          这部分我们要解决一个逻辑问题,那就是怎么移动拼图。例如,在图3.4.1的拼图中,如果鼠标在空白块的左侧一个拼图块内点击一次,此时左侧的那个拼图块应该往空白处移动,但要怎样才能实现这一过程?

                                                          

                                                       图3.4.1 移动拼图过程(左图)                 图3.4.2 拼图行列数(右图)

          为了实现这一过程,这里同样定义一个函数,实现在当前的拼图中根据鼠标所在的行列数移动拼图块,命名为movejig( ) 。输入参数:tag(当前拼图的标记矩阵)、row(鼠标点击位置的行数)、column(鼠标点击位置的列数);输出参数:tag(移动后得到的标记矩阵)。行列数的规定按照图3.4.2的坐标系确定,图3.4.3简单示出了movejig( )函数的大致运行方式。

                                                                                        图3.4.3 函数功能示意图

          这里默认已经知道了鼠标坐标并经过计算得出了鼠标点击处的行列数row,col,至于如何计算将在后面介绍。 movejig( )函数的具体代码如下

    function tag=movejig(tag,row,col)
     %% 4个if分4种情况对不同位置处的点坐标与矩阵行列式统一
        num = tag(row,col);%鼠标位置与号码牌一致
        if (row > 1)&&(tag(row-1,col)==0)%点击位置在第二或第三行,空白块在点击位置的上一行
            tag(row-1,col) = num;%交换两个位置上的值
            tag(row,col) = 0;
        end
        if (row < 3)&&(tag(row+1,col)==0)%点击位置在第一或第二行,空白块在点击位置的下一行
            tag(row+1,col) = num;
            tag(row,col) = 0;
        end
        if (col > 1)&&(tag(row,col-1)==0)%点击位置在第二或第三列,空白块在点击位置的左边一列
            tag(row,col-1) = num;
            tag(row,col) = 0;
        end
        if (col < 3)&&(tag(row,col+1)==0)%点击位置在第二或第三列,空白块在点击位置的右边一列
            tag(row,col+1) = num;
            tag(row,col) = 0;
        end
          第3行根据点击处的行列号可取出点击位置处拼图块的标记,存为num。第4行至第19行分四种情况考虑可能出现的点击情况,第4行if中的条件row>1说明点击位置在第2行或第3行,并且要求tag(row-1,col)==0即点击处的上一行位置上的标记是0(也就是表示空白拼图块),这两个条件同时满足就是表示鼠标点击的拼图块上面一个拼图块是空白块。条件满足后第5,6行就是将点击处的拼图块和上面的空白块的标记值互换,表示点击拼图块上移。同理,后面三种情况空白处分别出现在点击下方、左边、右边同样交换两个拼图块实现移动。其他情况如点击了某个拼图块而这个拼图块相邻位置上没有空白则不满足条件是不会进行任何操作的。
          其实,上面的四个if条件在拼图时是不会有同时满足的情况的,上述代码中的形式需要判断四次条件虽然没错但显得有点多余,在编程时写成嵌套的if...elseif...end形式则更加合理,这里不这么写是为了防止可能有初学的朋友容易混淆而出错,熟悉的朋友可以自行改写。

          movejig( )函数实现的是标记矩阵中相应元素的移动,结合前面编写的显示函数drawmap( )将得到的移动后的标记作为输入就可以显示移动后的拼图了。

    3.5 打乱拼图

          游戏开始时需要将一幅完整的图片打乱,那又要怎么实现呢?读到这里您可能就知道了,整个拼图游戏的实现主要是通过标记矩阵进行操作的,即改变标记矩阵,然后按标记矩阵将拼图显示出来。对此前面已多有铺垫,通过打乱标记矩阵的元素的方法打乱拼图自然也就水到渠成。

          一个简单的想法是,生成一个由0-8的数字随机排列构成的3*3的矩阵作为标记矩阵如下面的矩阵Tag1

          然而这样存在的bug是随机产生的矩阵其实大多通过移动拼图是不能完成正确排序的,这在数学上有相关理论研究可得出结论,不研究数学的笔者就不多说了。这里我的想法是模仿人手动打乱拼图的方式,不断随机移动拼图直至拼图顺序完全打乱。前面介绍了移动拼图的函数,这里随机产生点击的行列数然后调用移动拼图函数movejig( ),重复一定次数则可完成拼图打乱。定义一个打乱拼图函数Disrupt( ),返回一个仿手动打乱之后得到的标记矩阵,MATLAB代码如下
    function y = Disrupt()
    %% 随机打乱原拼图排列顺序
    y =[1,2,3;4,5,6;7,8,0];
    for i = 1:360
        row=randi([1,3]);%产生一个范围在1到3的整数
        col=randi([1,3]);
        y=movejig(y,row,col);%按随机产生的动作打乱拼图
    end
          代码第3行,默认y是一个顺序正确的3*3的矩阵,在第5行for循环中设置移动的次数为360次,每次都产生一个行数row和列数col,其值为1,2,3中随机的一个数,然后第8行调用movejig( )移动拼图。这就仿佛一个人不断在拼图上随机地点击很多次,由于点击拼图块,相应位置上的拼图块就会不断移动。这样做虽然每次盲目产生的row和col不一定都有效,但次数多了无疑会起到打乱拼图的作用。
          接下来就可以测试一下了,新建一个m文件,命名为jigsaw.m,在文件中输入如下代码
    function jigsaw()
    %% 主函数
    Tag_A= Disrupt()%将图像的排列顺序打乱
    drawmap(Tag_A);%按照标记矩阵显示拼图
    
    
    function tag=movejig(tag,row,col)
     %% 4个if分4种情况对不同位置处的点坐标与矩阵行列式统一
        num = tag(row,col);%鼠标位置与号码牌一致
        if (row > 1)&&(tag(row-1,col)==0)%点击位置在第二或第三行,空白块在点击位置的上一行
            tag(row-1,col) = num;%交换两个位置上的值
            tag(row,col) = 0;
        end
        if (row < 3)&&(tag(row+1,col)==0)%点击位置在第一或第二行,空白块在点击位置的下一行
            tag(row+1,col) = num;
            tag(row,col) = 0;
        end
        if (col > 1)&&(tag(row,col-1)==0)%点击位置在第二或第三列,空白块在点击位置的左边一列
            tag(row,col-1) = num;
            tag(row,col) = 0;
        end
        if (col < 3)&&(tag(row,col+1)==0)%点击位置在第二或第三列,空白块在点击位置的右边一列
            tag(row,col+1) = num;
            tag(row,col) = 0;
        end
       
    
    function y = Disrupt()
    %% 随机打乱原拼图排列顺序
    y =[1,2,3;4,5,6;7,8,0];
    
    for i = 1:360
        row=randi([1,3]);%产生一个范围在1到3的整数
        col=randi([1,3]);
        y=movejig(y,row,col);%按随机产生的动作打乱拼图
    end
    
    
    
    function x = choose(image,index)
    %% 根据索引选择对应位置上的拼图块
    if index>0 %标记为1,2,3,4,5,6,7,8的拼图块
        % 计算出行数row以及列数column
        row=fix((index-1)/3);
        column=mod(index-1,3);
        % 分割出对应拼图块数据
        x=image(1+row*100:100*(row+1),1+column*100:100*(column+1),:);
    else
        x=uint8(255*ones(100,100,3));%拼图块0矩阵数据
    end
    
    
    function drawmap(A)
    %% 将运算数字与对应拼图对应显示图片
    origin=imread('jigsawImage.jpeg');
    image=origin;
    % 对要显示的拼图进行赋值
    for row=1:3
        for col=1:3
        image(1+(row-1)*100:100*row,1+(col-1)*100:100*col,:)=choose(origin,A(row,col));
        end
    end
    imshow(image)%显示拼图
        运行结果如图3.5.1所示

                                                     

                                                                                图3.5.1 打乱拼图测试

    3.6 拼图主函数

          主函数是完成拼图任务的核心,主函数的设计思路是首先将标记矩阵打乱,并按照标记矩阵中的排列显示拼图块,然后需要获得鼠标点击处的位置坐标以移动拼图,每次移动后判断拼图顺序是否已经正确,顺序正确后结束游戏。前面已经完成了标记矩阵的打乱和显示以及根据鼠标位置移动拼图的函数,那么现在的问题就剩下鼠标位置的获取了。

          MATLAB中获取鼠标坐标值有两种途径。第一种是利用ginput( )函数,该函数提供一个十字光标帮助更精确选择所需要的位置并返回坐标值,函数调用形式如[x y]=ginput(1),x,y分别为横纵坐标。这确实为一个简单实用的方法,开始时我就是采用的这种方式,在主函数中利用while循环重复调用ginput( )函数获取每次点击处的坐标值,结果证明是可行的,效果如下图3.6.1所示。

    图3.6.1 利用ginput( )的方式实现效果

          这样的类似方法网上提到很多,让我感觉不太好的一点是这个十字光标精确是精确,但是在这个拼图中显得有些多余,怎么删去这个光标寻找半天,未果。还有就是用while循环编写的代码每次关掉这个图形窗口都会甩出一个大大的类似下图那样的错误,这就让有点小小处女座的我不能忍了,转而编写了另外一个版本。

          第二种方法是利用figure的WindowButtonDownFcn属性定义一个坐标获取的回调函数。当在图上按下鼠标的时候,就会自动执行回调函数来获取坐标值。主函数命名为jigsaw( ),与文件名一致,其代码如下

    function jigsaw()
    %% 主函数
    Tag_A= Disrupt();%将标记矩阵的排列顺序打乱
    drawmap(Tag_A);%按照标记矩阵显示拼图
    
    global Tag;%Tag是标记矩阵,定义成全局变量,方便传递参数
    Tag=Tag_A;
    set(gcf,'windowButtonDownFcn',@ButtonDownFcn);%点击鼠标时调用ButtonDownFcn函数

          代码第3,4行调用前面的函数打乱和显示,不必多说;第6,7行意在将标记矩阵定义成全局变量并赋值为Tag_A,其目的在于在后面的回调函数中需要用到标记矩阵,这样方便传递参数,这里可以不必深究;第8行就是设置windowButtonDownFcn属性的回调函数,gcf表示当前图形窗口句柄,ButtonDownFcn是回调函数名,@ButtonDownFcn表示其函数句柄,整条代码就是设置当在当前图形窗口中点击鼠标时就会转而执行ButtonDownFcn函数。

    3.7 回调函数

          根据上一节的设置每次点击鼠标时就会执行一次回调函数,因此可以在回调函数中编写程序获取当前鼠标位置并据此移动一次拼图,然后判断拼图是否完成。定义回调函数ButtonDownFcn( ),输入参数src、event为系统约定变量,函数代码如下

    function ButtonDownFcn(src,event)
    %% 回调函数,鼠标点击事件发生时调用
    pt=get(gca,'CurrentPoint');%获取当前鼠标点击位置坐标
    xpos=pt(1,1);%鼠标点击处的横坐标实际值
    ypos=pt(1,2);%鼠标点击处的纵坐标实际值
       
    col = ceil(xpos/100);%将横坐标值转换为列数
    row = ceil(ypos/100);%将纵坐标值转换为行数
    
    global Tag; %全局变量声明
    
    if(col<=3&&col>0)&&(row<=3&&row>0)%鼠标点击位置在有效范围内    
        Tag=movejig(Tag,row,col);%按点击位置移动拼图
        
        drawmap(Tag)%显示拼图
        
        order = [1 2 3;4 5 6;7 8 0];%顺序矩阵
        zt = abs(Tag-order);%比较两个矩阵
        if sum(zt(:))==0 %顺序已经完全吻合
            image=imread('jigsawImage.jpeg');
            imshow(image) %游戏完成,补全拼图
            msgbox('You did a good job ,恭喜完成!!!') %提示完成信息
            pause(0.5);%延迟半秒
            close all %游戏结束,关闭所有图像窗口
        end
        
    else
        return
        
    end

          代码第3行利用get( )获取鼠标位置坐标,gca表示获取当前坐标系句柄即在当前坐标系中获取坐标值,CurrentPoint是当前点属性值,返回的pt为一行两列的数组,其元素分别为横纵坐标值。第4,5行是分别取出横纵坐标值,第7,8行代码求出行列数,因为图片的尺寸为300*300,分成3行3列,所以将鼠标坐标值除以100即可得出所在的行列数,如果选取的图片为其他尺寸应除以其他相应的数字。

          第10行声明全局变量Tag,在3.6节中定义过了,这里再度声明表示与前面定义的一致,Tag共享其数值,前面的标记矩阵这里就能使用了。

          第12行中,判断点击鼠标的位置是不是在拼图中,因为在图形窗口中点击时若点击位置不在图片上时,返回的坐标值会出现异常值,避免的方法是只有行列数在1到3内的点击才进行处理,不满足条件时跳至第27行返回,结束本次回调函数的运行。

          第13,15行按照点击的行列数移动拼图的标记矩阵,然后按照标记矩阵显示拼图。第17行定义一个顺序矩阵用于标记矩阵的比较,第18行将移动后的标记矩阵与顺序矩阵相减取绝对值,abs( )为取绝对值函数,可以知道如果两个矩阵完全一致则相减之后的结果每个位置上的元素都为0,反之不然。

          第19行中,if sum(zt(:))==0即如果zt中所有元素的和等于0,满足这个条件时表示游戏完成了,此时将拼图空白的那块补全,第20,21行读取原图然后显示,这一过程连续起来的瞬间就表现为拼图空白处被补全了。

          第22行弹出一个提示窗口,展示的信息为“You did a good job ,恭喜完成!!!”。第23行暂停0.5秒,第24行在暂停半秒之后关闭所有图形窗口,游戏结束。

    4.完整代码

          所有工作完成,完整的程序m文件以及图片文件已经上传大家可以点击链接下载基于MATLAB的拼图游戏,直接打开jigsaw.m文件即可运行程序。下面是完整的MATLAB代码,大家可以自行新建jigsaw.m文件,复制以下代码至文件中同样可以运行拼图程序。注意下载jigsawImage.jpeg图片文件,与jigsaw.m文件放在同一文件夹下。注意,如更换图片需要适当修改程序。

    %% 制作人:吴限
    % 2018年2月14日
    function jigsaw()
    %% 主函数
    Tag_A= Disrupt();%将标记矩阵的排列顺序打乱
    drawmap(Tag_A);%按照标记矩阵显示拼图
    
    global Tag;%Tag是标记矩阵,定义成全局变量,方便传递参数
    Tag=Tag_A;
    set(gcf,'windowButtonDownFcn',@ButtonDownFcn);%点击鼠标时调用ButtonDownFcn函数
    
    
    
    function ButtonDownFcn(src,event)
    %% 回调函数,鼠标点击事件发生时调用
    pt=get(gca,'CurrentPoint');%获取当前鼠标点击位置坐标
    xpos=pt(1,1);%鼠标点击处的横坐标实际值
    ypos=pt(1,2);%鼠标点击处的纵坐标实际值
       
    col = ceil(xpos/100);%将横坐标值转换为列数
    row = ceil(ypos/100);%将纵坐标值转换为行数
    
    global Tag; %全局变量声明
    
    if(col <= 3 && col >0)&&(row <= 3&&row > 0)%鼠标点击位置在有效范围内    
        Tag=movejig(Tag,row,col);%按点击位置移动拼图
        
        drawmap(Tag)%显示拼图
        
        order = [1 2 3;4 5 6;7 8 0];%顺序矩阵
        zt = abs(Tag-order);%比较两个矩阵
        if sum(zt(:))==0 %顺序已经完全吻合
            image=imread('jigsawImage.jpeg');
            imshow(image) %游戏完成,补全拼图
            msgbox('You did a good job ,恭喜完成!!!') %提示完成信息
            pause(0.5);%延迟半秒
            close all %游戏结束,关闭所有图像窗口
        end
        
    else
        return
        
    end
    
    
    
    
    function tag=movejig(tag,row,col)
     %% 4个if分4种情况对不同位置处的点坐标与矩阵行列式统一
        num = tag(row,col);%鼠标位置与号码牌一致
        if (row > 1)&&(tag(row-1,col)==0)%点击位置在第二或第三行,空白块在点击位置的上一行
            tag(row-1,col) = num;%交换两个位置上的值
            tag(row,col) = 0;
        end
        if (row < 3)&&(tag(row+1,col)==0)%点击位置在第一或第二行,空白块在点击位置的下一行
            tag(row+1,col) = num;
            tag(row,col) = 0;
        end
        if (col > 1)&&(tag(row,col-1)==0)%点击位置在第二或第三列,空白块在点击位置的左边一列
            tag(row,col-1) = num;
            tag(row,col) = 0;
        end
        if (col < 3)&&(tag(row,col+1)==0)%点击位置在第二或第三列,空白块在点击位置的右边一列
            tag(row,col+1) = num;
            tag(row,col) = 0;
        end
       
    
    
    function y = Disrupt()
    %% 随机打乱原拼图排列顺序
    y =[1,2,3;4,5,6;7,8,0];
    
    for i = 1:360
        row=randi([1,3]);%产生一个范围在1到3的整数
        col=randi([1,3]);
        y=movejig(y,row,col);%按随机产生的动作打乱拼图
    end
    
    
    
    function x = choose(image,index)
    %% 根据索引选择对应位置上的拼图块
    if index > 0 %标记为1,2,3,4,5,6,7,8的拼图块
        % 计算出行数row以及列数column
        row=fix((index-1)/3);
        column=mod(index-1,3);
        % 分割出对应拼图块数据
        x=image(1+row*100:100*(row+1),1+column*100:100*(column+1),:);
    else
        x=uint8(255*ones(100,100,3));%拼图块0矩阵数据
    end
    
    function drawmap(A)
    %% 将运算数字与对应拼图对应显示图片
    origin=imread('jigsawImage.jpeg');
    image=origin;
    
    % 对要显示的拼图进行赋值
    for row=1:3
        for col=1:3
        image(1+(row-1)*100:100*row,1+(col-1)*100:100*col,:)=choose(origin,A(row,col));
        end
    end
    
    imshow(image)%显示拼图

     

    5.反思与总结

     

          MATLAB大多用于数据处理以及工程计算,几乎很少有用MATLAB编写游戏的,这也符合实际情况因为编写游戏毕竟不是MATLAB的专长,其实MATLAB发展至今已经成为一个足够完善的编程语言许多java,c中的功能在MATLAB中同样也能实现。例如MATLAB具有高级图形处理功能,可以通过图形对象的属性完成许多复杂工作,前面鼠标位置的获取用的就是这一功能。

          整个拼图游戏的设计其实可以看成一个数学建模过程,代表拼图块的标记矩阵就是我们建立的模型,通过对这个模型矩阵元素排序问题的求解、分析最终完成这个拼图任务。更多数学建模的知识大家可以自行上网搜索。

          纵观整个拼图游戏的编写,在基本功能上可以改进与提高的地方如下

    一、增加自行挑选设置拼图所用图片的功能。

    二、增加拼图的难度,设计4*4或5*5甚至更复杂的拼图。

    三、利用MATLAB的GUI功能,为游戏设计一个好看的用户图形界面。

    四、设计一个一键完成拼图的算法,让程序以最优步数自行移动拼图完成拼图。实现上可采用原始的方法或者机器学习的算法。

    五、拼图块的形状与移动方式上也可不必局限这一种,稍作创新兴许一个新型的游戏就会被创造出来。

          关于上述的改进之处,有机会将在后面的博文中介绍。

     

    6. 结束语

          这就是利用MATLAB进行拼图游戏编写的全部内容了,虽然拼图游戏本身不足为奇,但利用MATLAB编写的完整程序不多,而且或多或少会有一点小bug,本博文介绍的方法在多次修改之下,其程序严谨没有错误。由于编者能力有限,代码即使经过了多次校对,也难免会有疏漏之处。希望您能热心指出其中的错误,以便下次修改时能以一个更完美更严谨的样子,呈现在大家面前。同时如果有更好的实现方法也请您不吝赐教。

    【公众号获取】
    本人微信公众号已创建,扫描以下二维码并关注公众号“AI技术研究与分享”,后台回复“JP20180210”即可获取全部资源文件。

     

    展开全文
  • 你是谁? 我是游戏设计师 不对,你不是 我是游戏设计师 你是哪种设计师? 我是游戏设计师 你是说你会玩游戏 我是游戏设计

        《游戏设计艺术(第2版)》的第一章《太初之时,有设计师》开篇就教给读者一个成为游戏设计师的咒语——“我是游戏设计师”,全书也围绕这个咒语展开;接着归纳了游戏设计师从动画、头脑风暴到数学、管理等必备技能;然后用了几乎整本书的篇幅详细讨论那些技能对游戏设计师提升游戏体验的奥秘。


        《游戏设计艺术》不但可以提高游戏设计师的个人能力,还教设计师如何与团队和玩家交流,本书第25章《设计师常与团队合作》就揭示了成功团队的秘诀——“如果你实在对游戏爱不起来,请热爱游戏的受众,这里的受众不仅仅指玩家,也指游戏设计团队的其他成员;第26章《团队有时通过文档进行沟通》则教给游戏设计师通过文档与其他设计、工程和玩家交流的技巧。


        除了设计外,《游戏设计艺术》在全书的最后还简要讲述了一点开发技巧(布娃娃物理系统)和营销技巧(成功推销的12建议),这可以使设计师与开发和销售交流时候不至于听不懂对方的术语而鸡同鸭讲。


        此外《游戏设计艺术》的作者博古通今,在文中旁征博引,既有名人名言也有奇闻轶事,虽然引经据典但没有掉书袋之嫌,让读者乐在其中。


        《游戏设计艺术》的英文版用我是游戏设计师”这个咒语激励了“免费打工仔”邸锐,让他走出了“方便面融资的窘境,成为了激励无数游戏设计师的《创游记》的作者。所以邸锐自告奋勇成了《游戏设计艺术(第2)》的中文译者,而作者也很高兴让此新版让中国的游戏设计师知道这句咒语——“我是游戏设计师

    展开全文
  • 连连看游戏设计

    千次阅读 2015-03-30 16:06:49
    连连看游戏设计               连连看是一种很受大家欢迎的小游戏。微软亚洲研究院的实习生 们就曾经开发过一个类似的游戏——Microsoft Link-up。   图 1-17 连连看游戏示意图   图 1-17 ...

    连连看游戏设计

     

     

     

     

     

     

     

    连连看是一种很受大家欢迎的小游戏。微软亚洲研究院的实习生 们就曾经开发过一个类似的游戏——Microsoft Link-up。

     

    图 1-17  连连看游戏示意图

     

    图 1-17 为Microsoft Link-up 的一个截图。如果用户可以把两 个同样的图用线(连线拐的弯不能多于两个)连到一起,那么这两个 头像就会消掉,当所有的头像全部消掉的时候,游戏成功结束。游戏 头像有珍稀动物、京剧脸谱等。Microsoft Link-up还支持用户输入 的图像库,微软的同事们曾经把新员工的漫画头像加到这个游戏中,让大家在游戏之余也互相熟悉起来。

     

    假如让你来设计一个连连看游戏的算法,你会怎么做呢?要求说 明:

     

    1.  怎样用简单的计算机模型来描述这个问题?

     

     

    2.  怎样判断两个图形能否相消?

     

     

    3.   怎样求出相同图形之间的最短路径(转弯数最少,路径经过的 格子数目最少)。

     

    4.   怎样确定目前是处于死锁状态,如何设计算法来解除死锁?


     

    分析与解法

     

    连连看游戏的设计,最主要包含游戏局面的状态描述,以及游戏 规则的描述。而游戏规则的描述就对应着状态的合法转移(在某一个 状态,有哪些操作是满足规则的,经过这些满足规则的操作,会到达 哪些状态)。所以,自动机模型适合用来描述游戏设计。

     

    下面是一个参考的连连看游戏的伪代码: 代码清单 1-22

    生成游戏初始局面

    Grid preClick = NULL, curClick= NULL; while(游戏没有结束)

    {

    监听用户动作

    if(用户点击格子(x, y),且格子(x,y)为非空格子)

    {

    preClick = curClick; curClick.Pos = (x, y);

    }

    if(preClick != NULL && curClick!= NULL

    && preClick.Pic == curClick.Pic

    && FindPath(preClick, curClick) != NULL)

    {

    显示两个格子之间的消去路径 消去格子preClick, curClick; preClick = curClick= NULL;

    }

    }

     

    从上面的整体框架可以看到,完成连连看游戏需要解决下面几个 问题:

     

    1. 生成游戏初始局面。

     

     

    2.   每次用户选择两个图形,如果图形满足一定条件(两个图形一 样,且这两个图形之间存在少于3个弯的路径),则两个图形都


     

    能消掉。给定具有相同图形的任意两个格子,我们需要寻找这

     

    两个格子之间在转弯最少的情况下,经过格子数目最少的路径。 如果这个最优路径的转弯数目少于3,则这两个格子可以消去。

     

    3.   判断游戏是否结束。如果所有图形全部消去,游戏结束。

     

     

    4. 判断死锁,当游戏玩家不可能再消去任意两个图像的时候,游 戏进入“死锁”状态。如图1-18,该局面中已经不存在两个相 同的图片相连的路径转弯数目小于3的情况。

     

    在死锁的情况下,我们也可以暂时不终止游戏,而是随机打乱局 面,打破“死锁”局面。

     

    图 1-18  连连看死锁的情况 首先思考问题:怎样判断两个图形能否相消?在前面的分析中,

    我们已经知道,两个图形能够相消的充分必要条件是这两个图形相同,

    且它们之间存在转弯数目小于 3 的路径。因此,需要解决的主要问题 是,怎样求出相同图形之间的最短路径。首先需要保证最短路径的转

    弯数目最少。在转弯数目最少的情况下,经过的格子数目也要尽可能

    地少。

     

    在经典的最短路径问题中,需要求出经过格子数目最少的路径。 而这里,为了保证转弯数目最少,需要把最短路径问题的目标函数修 改为从一个点到另一个点的转弯次数。虽然目标函数修改了,但算法 的框架仍然可以保持不变。广度优先搜索是解决经典最短路问题的一 个思路。我们看看在新的目标函数(转弯数目最少)下,如何用广度 优先搜索来解决图形 A(x1, y1)和图形 B(x2, y2)之间的最短路径 问题。

    首先把图形 A(x1, y1)压入队列。

    然后扩展图形 A(x1, y1)可以直线到达的格子(即图形A(x1, y1)


    可以通过转弯数目为 0 的路径(直线)到达这些格子)。假设这些格 子为集合 S0,S0 = Find(x1, y1)。如果图形 B(x2, y2)在集合 S0 中,则结束搜索,图形A 和 B 可以用直线连接。

     

    否则,对于所有 S0 集合中的空格子(没有图形),分别找到它们 可以直线到达的格子。假设这个集合为 S1。S1 ={Find(p)| p ∈S0}。 S1 包含了 S0,我们令 S1’= S1-S0,则 S1’中的格子和图形 A(x1, y1) 可以通过转弯数目为1 的路径连起来。如果图形 B(x2, y2)在 S1’中, 则图形 A 和 B 可以用转弯数目为 1 的路径连接,结束搜索。

     

    否则,我们继续对所有  S1’集合中的空格子(没有图形),分别 找出它们可以直线到达的格子,假设这个集合为 S2,S2 = Find{ Find

    (p)| p ∈S1’}。S2 包含了 S0 和 S1,我们令 S2’= S2 - S0 - S1 = S2

    - S0 - S1’。集合S2’是图形 A(x1, y1)可以通过转弯数目为 2 的 路径到达的格子。如果图形 B(x2, y2)在集合 S2’中,则图形 A 和 B 可以用转弯数目为 2 的路径连接,否则图形A 和 B 不能通过转弯小于

    3 的路径连接。

     

    在扩展的过程中,只要记下每个格子是从哪个格子连过来的(也 就是转弯的位置),最后图形 A 和 B 之间的路径就可以绘制出来。

     

    在上面的广度优先搜索过程中,有两步操作:S1’ = S1 - S0 和 S2’= S2 - S0 -S1。它们可以通过记录从图形 A(x1, y1)到该格子(x, y)的转弯数目来实现。开始,将所有格子(x, y)和格子 A(x1, y1) 之间路径的最少转弯数目 MinCrossing(x, y)初始化为无穷大。然 后,令 MinCrossing(A)= MinCrossing(x1, y1)= 0,格子 A 到自 身当然不需要任何转弯。第一步扩展之后,所有 S0 集合中的格子的 MinCrossing 值为 0。在 S0 集合继续扩展得到的 S1 集合中,格子 X 和 格子 A之间至少有转弯为 1 的路径,如果格子 X本身已经在 S0 中,那 么,MinCrossing(X)= 0。这时,我们保留转弯数目少的路径,也 就是 MinCrossing(X)= MinValue(MinCrossing(X), 1)= 0。 这个过程,就实现了上面伪代码中的 S1’= S1 - S0。S2’= S2 - S0–

    S1  的扩展过程也类似。

     

    经过上面的分析,我们知道,每一个格子 X(x, y),都有一个状 态值 MinCrossing(X)。它记录下了该格子和起始格子 A 之间的最 优路径的转弯数目。广度优先搜索,就是每次优先扩展状态值最 少的格子。如果要保证在转弯数目最少的情况下,还要保持路径 长度尽可能地短,则需要对每一个格子 X 保存两个状态值 MinCrossing(X)和 MinDistance(X)。从格子 X 扩展到格子Y 的


    过程,可以用下面的伪代码实现:

     

    if((MinCrossing(X) + 1 < MinCrossing(Y)) ||

    ((MinCrossing(X) + 1 == MinCrossing(Y)&& (MinDistance(X) + Dist(X,Y) < MinDistance(Y)))

    {

    MinCrossing(Y) = MinCrossing(X) + 1; MinDistance(Y) = MinDistance(X) + Dist(X, Y);

    }

    也就是说,如果发现从格子X 过来的路径改进了转弯数目或者路

    径的长度,则更新格子 Y。

     

    “死锁”问题本质上还是判断两个格子是否可以消去的问题。最 直接的方法就是,对于游戏中尚未消去的格子,都两两计算一下它们 是否可以消去。此外,从上面的广度优先搜索可以看出,我们每次都 是扩展出起始格子A(x1, y1)能够到达的格子。也就是说,对于每 一个格子,可以调用一次上面的扩展过程,得到所有可以到达的格子, 如果这些格子中有任意一个格子的图形跟起始格子一致,则它们可以 消去,目前游戏还不是“死锁”状态。

     

     

    扩展问题:

     

    1.在连连看游戏设计中,是否可以通过维护任意两个格子之间的 最短路径来实现快速搜索?在每一次消去两个格子之后,更新 我们需要维护的数据(任意两个格子之间的最短路径)。这样 的思路有哪些优缺点,如何实现呢?

     

    2. 在围棋或象棋游戏中,经过若干步操作之后,可能出现一个曾经 出现过的状态(例如,围棋中的打劫)。如何在围棋、象棋游戏 设计中检测这个状态呢?

    展开全文
  • DirectX 9 3D游戏设计入门

    千次下载 热门讨论 2012-03-05 13:15:32
    Introduction to 3D Game Programming with DirectX 9 DirectX 9 3D游戏设计入门
  • 本科游戏设计毕设经历

    千次阅读 2018-07-06 10:02:24
    大学毕设经历   以前其实还没听说过本科毕设有多难,研究生和博士生到是知道难度有些...  我的毕设是做个游戏APP,起初我本来选题是连连看APP游戏设计,但是后来遇到一点事情说题目重复了要求更换,于是我在4月...

    文章目录


    提供了必设源码:https://github.com/abcnull/IndependentPlaneGame
    欢迎大家 star 和 fork

      以前其实还没听说过本科毕设有多难,研究生和博士生到是知道难度有些大,在网上听很多人说本科的毕业设计很水,虽然目前为止我还没有答辩,还有一周,但是就我的毕设经历来讲,我觉得本科毕设真的不简单,也许是网友们实力太强或者是大学检查的很水,或者说我的实力太差了。
      我的毕设是做个游戏APP,起初我本来选题是连连看APP游戏设计,但是后来遇到一点事情说题目重复了要求更换,于是我在4月初的时候去换题目,结果是换成的俄罗斯方块游戏改进也重复了,我便在导师的要求下换了一个类似于“雷霆战机”那样的飞行射击类游戏APP,当时学校没什么事情,我就一直呆在家里,从四月份开始,要知道5月初就要中期检查了,5月中旬还要论文检查之类的,5月底要答辩了,所以说我做这个APP游戏还是时间很紧迫的,所以这段时间一直没有更新CSDN博客,时间都去做毕设了,今天开始的后几天可以连续写博客了。其实我以前只学过一点Android开发,而且忘了很多,Android游戏以前都没做过。
      这次的游戏APP题目是飞机游戏APP设计与实现,幸好我在寒假的时候没有太松懈,复习了Android的一些内容,学习了View的相关知识,还看了网上对于俄罗斯方块的实现(虽然忘了),同时仔细看了安卓游戏从零开始的入门,看了不少东西,对做这么一个题目也不能说完全没有信息。后来我在网上也查过许多的资料,终于在4月快结束的时候基本把项目弄好了。使用的是eclipse,View框架,因为我以前一直用eclipse没用过Android Studio,而且我也没系统的学习过一些游戏引擎,所以只能用View来做游戏,而且View足够用了,虽然逻辑部分可能很复杂。
      还记得我4月份在家做毕业设计,几乎连续12天早上睡醒就直接打开电脑码代码做毕业设计,就这样一直做,做到晚上11点多便去睡觉,除了上厕所偶尔出个门,连吃饭都是在电脑前。4月底终于把项目基本完成,后来我在5月份的时候给项目添加了许多新的功能,而且在5月份前几天先去给另一个老师进行中期检查,老师估计只看了不到一分钟,他直接看了在我手机上运行的游戏的效果,稍微问了几点问题,然后就行了,感觉中期检查好水啊~。当时中期检查我还担心看不看论文,因为我还没写论文,不过幸好中期检查根本不看论文。后来的几天我把论文补上了,一开时论文的格式问题非常让人头痛,什么设置页眉页脚,还有许多需要注意到的格式问题,我调了很久,我还记得我写了2天2夜,包括调整格式,写论文,修改论文,查重等,偶,对了忘了提及了,在写论文前,我添加了许多新功能。论文一开始写了2w多字,然后去查重,发现22%,这个在我意料之外,因为都是我自己写的,竟然这么多重复,后来我把很多句子改的比较刁钻,再一查16%,我还不满意,再改再去查只有5%了。后来我那论文给到时检查,结果导师说不合格,我其实一开始还信心满满的,结果像被破了一票冷的冷水,是我的行间距有问题,再加上由于我过于追求重复率低使得我改的某些句子有点读的不通顺。后来我只得再修改,现在把句子改通顺了,但是改的只剩下1w7的字了,查重是15%,接下来我尽量想办法改到10%以内。导师说10%以内会比较稳。
      现在我谈谈我的项目实现功能,这是一个飞行射击游戏,里头的图片我是从百度图片里头搞的,然后用美图秀秀来抠图(美图秀秀学了半天),游戏进入的界面我后来美化了一下也变得好看了,图片都是从网上弄得然后自己修改。游戏可以设置游戏难度,可以设置音乐,可以查看作者,可以查看玩法,进入游戏,你可以触屏移动控制战斗机,战斗机会一直发射子弹,默认是黄色单发子弹,游戏中有黄色的小敌机,绿色的中敌机,红色的大敌机还有章鱼一样的老板敌机,老板敌机可以发射火球来攻击战斗机,当然老板敌机比较难出现,它是每隔一定时间才会出现,并且界面上只能有一个老板敌机。在游戏中玩家可以获得5中道具,其中有3种是子弹道具,这些子弹道具都是蓝色子弹,子弹道具分别有双发的子弹道具,战斗机为不发射子弹的子弹道具,战斗机两侧发射子弹的子弹道具,还有炸弹道具和生命值恢复道具,在屏幕上点击两下,界面上所有的敌方单位都会爆炸,战斗机最初有3条生命,战斗机每被击中就会变白几帧,每次接收到回血道具就会变绿几帧。音乐是循环播放的,只有背景音乐,没有特效音乐。我还记得当时选音乐时候选了很久,想选一首好听的同时又比较适合的。游戏可以暂停可以重新开始,还可以查看FPS,我是小米5,可以发现非常稳定的维持在60帧/s。
      项目的一些部分是怎么实现的呢?我大致讲一下,因为我在其他博客中会写一点。项目主要是通过View来代表整个游戏界面,在onDraw()中绘制游戏界面,每执行一次绘制其实就是一帧画面,有postinvalidate()方法可以重绘,这个只要在必要时候写就行了。因为手机绘制一帧的画面是非常快的,只要能保证你会的每一帧中图片的位置都不同就行了,在游戏中有许多精灵对象,游戏分三种状态,我只要在游戏进行态时候,执行某一精灵对象的绘制方法,代表该精灵在这一帧中绘制出来了,其实精灵的绘制方法就是安卓graphics包下的drawBitmap之类的方法,将位图绘制在界面上即可,那有人会问,你怎么改变每一帧精灵的位置呢,其实精灵的绘制方法不是直接写drawBitmap之类的,而是分为三个方法,第一个方法负责移动精灵位置,第二个方法负责绘制精灵位置,第三个方法负责检查销毁之类的即可。在游戏进行态的时候,只要战斗机没有被销毁(因为我是根据战斗机是否被销毁来判定游戏是否在结束态),那么最后在执行postinvalidate()方法实现重绘,只要在游戏进行态,就会不断的循环。其中有许多的特殊功能,还不是很好说清楚,一些经验和特殊功能我会在其他博文中写清楚。
      我这个人有点强迫症,有点完美主义,做的不好就非常不安心。接下来的数天我还要改论文,项目做得是差不多了,我也的确做的很累了。项目以后再做些其他的游戏出来,就是通过这次毕设,使我对游戏制作变得非常感兴趣,有时间去学习一下unity3d,再去做做游戏。
      这次毕业设计真的是一个很难得的经历,确实学习到了不少东西。由于我非常怕遗忘,而且我认为经验非常重要,于是写下这篇博文给大家分享我的毕设经历。我码字太快了,一下子就码到这里来,可能有很多错别字还有语句不通的问题,希望提醒(#.#)。

    展开全文
  • 游戏设计分析——魔塔

    千次阅读 2019-09-01 20:02:11
    游戏设计分析游戏介绍故事背景游戏玩法与目标核心元素与特色人物的数值与战斗系统道具金币和经验值NPC系统隐藏物品和特殊触发游戏技术 游戏介绍   RPG游戏一直是受众面比较广的游戏类型之一,RPG游戏即是...
  • 游戏设计的第一步:设计体验

    千次阅读 2018-03-27 17:44:06
    游戏设计艺术》(The Art of Game Design)是卡耐基梅隆大学的教授Jesse Schell的著作。阅读过程中,我会记录并整理自己的思考。 下面是来自原文的两块透镜。所谓透镜,指的是检验设计的不同角度。因为对于设计...
  • 游戏设计的三大原则

    千次阅读 2019-10-16 15:48:37
    即使成为游戏设计师实际上是业内回报最高的工作之一。游戏设计也比人们意识到的更具挑战性。 了解所涉及的一切 从文档和布局到游戏玩法和平衡性,很少有哪个岗位比设计师参与到更多的游戏创建过程。 在游戏的整个...
  • 今天我们来说说智力类型的游戏设计,主要是涉及迷宫类型或者谜题猜测类型的游戏如何设计。 一、 来源 对于谜题类型的,相信有玩过仙剑单机系列的fans肯定可以体会到,仙剑里面有很多迷宫,而很多时候谜题或者...
  • 读《游戏设计进阶》

    千次阅读 2020-01-25 09:57:31
    作者推荐作法:系统性设计 这些“机器”是嵌套的——简单的机器在更复杂...这是一种对游戏设计的理解,如何去做游戏设计的方法论。 游戏一定要有交互吗? 多少或什么程度的交互是合适的? 139页,相关。 有交...
  • 猜硬币游戏设计

    千次阅读 2012-01-08 11:58:31
    猜硬币游戏设计 //最简单游戏的设计 //通过模块化的第一步进行(自顶向下分解) /*第一步顶层分解 *从主程序开始考虑。程序要做什么?程序要做两件事:显示指南;模拟玩游戏的过程。 *逐步细化的原则指出:一旦有了...
  • 基于Java的贪吃蛇游戏设计

    千次阅读 2019-12-08 15:06:38
    基于Java的贪吃蛇游戏设计引言:1. 需求分析2. 设计思路3. 代码部分简述3.1 主类StartGame3.2 类Data3.3 类GamePanel3.4 类GameJMenuBar4. 成果展示5. 总结(遇到的问题)(1)JFrame窗口的定位:(2)在JMenuBar...
  • 游戏设计的艺术:一本透镜的书.pdf

    千次下载 热门讨论 2011-10-12 21:13:51
    游戏设计的艺术:一本透镜的书(天之虹译) 游戏设计神书,可以说是游戏设计书籍中我看过最好的,直接探讨到了游戏设计的本质,对独立与同人游戏开发有很高的参考价值
  • 当我去设计一个游戏,一个玩法,包含规则,游戏对象等等一系列的游戏系统,用纸可以写下来,用嘴可以说出来,但是当我想要用程序去实现这一堆东西的时候,就有些无从下手。比如我们大家都会下五子棋,它有一个明确的...
  • 一起来读《游戏设计梦工厂》

    千次阅读 2020-09-20 22:27:41
    一起来读《游戏设计梦工厂》——游戏的结构 一起来读《游戏设计梦工厂》——游戏的结构 不同游戏中的共同点: 玩家 目标 程序 规则 资源 冲突 边界 结果 正规元素 什么给予了玩家上述元素的意义? 挑战 玩 ...
  • c# Windows窗体应用程序设计综合实例(一)匹配游戏设计 上次的计时器运行效果图如下: = ------------------------------------------------------------------------------ 今天来分享一个综合实例,设计一个匹配...
  • 游戏设计思路: 主界面点击开始游戏:进入打地鼠界面游戏中有12个地洞,游戏时间为30s(可以自己设置),每0.5s会有地鼠随机出现在一个地洞中,玩家触摸屏幕,打到地鼠加10分,否则不加分。30s后游戏结束,弹出窗口...
  • 游戏设计要素探秘之术语的呼唤

    千次阅读 2015-06-15 13:32:16
    通过创建游戏设计的真正术语,我们不仅可以让现有游戏创作者的条理更加清晰,也能给新手一个设计要则表,帮助他们开始思考和规划游戏设计。我们实际上提供了一个供新老游戏创作者沟通设计思想的工具,让所有游戏创作...
  • 如何编写设计文档
  • 体验引擎:游戏设计全景探秘

    千次阅读 2015-03-23 13:37:16
    体验引擎:游戏设计全景探秘(腾讯副总裁及魔方、蜜獾两大工作室老总作序推荐基于玩家体验设计游戏第一书同时覆盖规划、平衡性、界面、营销诸要素) 【美】Tynan Sylvester(泰南·西尔维斯特)著  秦彬 译 ISBN...
  • 《全景探秘游戏设计艺术》精华 用户体验 游戏平衡性 一本很好的游戏设计书籍,暂时关注的是用户体验部分,比如,用户喜欢什么,什么可以带来乐趣,以及游戏的平衡性 男性与女性的区别 男性喜欢的游戏要素...
  •  目前国内市场的游戏普遍为一些带有“快餐特色的RPG”游戏居多,并且这一类型的游戏设计思路已经发展成为游戏开发者们“月经”一样的存在,有很多人“取经”,也有很多人“传道”,设置有些人对于这一设计模式...
  • 游戏邦成立以来部分游戏设计观点回顾(五万字长文) 发布时间:2012-01-10 17:04:40 Tags:微博平台,游戏邦,部分游戏设计观点回顾 2010年底,游戏邦从数据分析的角度解析了当时手机游戏和社交游戏...
  • Android拼图游戏设计(包括游戏算法及数据库设计)

    千次阅读 热门讨论 2019-06-30 17:24:38
    拼图游戏设计可以分为如下几个部分:① UI设计;② 事件监听,事件处理;③ 游戏逻辑。 用户首先进入登陆注册界面,在登录注册模块可以实现注册登录功能,同时实现修改密码和注销用户的功能,这一功能模块需要...
  • 畅谈游戏设计理念

    千次阅读 2009-12-16 12:37:00
    星际2首席设计师畅谈游戏设计理念星际争霸2首席设计师Dustin Browder DustinBrowder的游戏设计生涯始于15年前,那时他为Activision公司设计制作《MechWarrior 2:Mercenaries》这一款游戏,然后他跳槽去了Westwood...
  • 贪吃蛇游戏设计

    千次阅读 2017-12-21 20:34:30
    从图中可以看出,整个游戏就是一个大的循环,当判断蛇的生命值为0时就跳出循环游戏结束,否则继续游戏。常用的结构是: While (1){ ………. //游戏内容 ………. If (……)break; //满足游戏结束的条件时跳出...
  • 这是一本游戏设计方面的好书 转自天:天之虹的博客:http://blog.sina.com.cn/jackiechueng 感谢天之虹的无私奉献 Word版可到本人的资源中下载   第一章定义游戏感  游戏感是没有一个标准的定义的。玩家和...
  • 游戏设计---游戏中战斗力计算方法(整理) 一、总结 一句话总结:用初始战斗力除以各项初始属性得到各属性的权重,然后加权得出战力计算公式 1、设计战斗力计算公式的两种思路? 主要是以属性投放为基础和真实...
  • 扫雷游戏设计原理

    千次阅读 2011-07-20 11:24:00
    扫雷游戏设计原理: 扫雷游戏分为几个步骤,由于比较多,所以在这里先列出来: 第一步,使用二维数组表示地图; 第二步,随机生成几个地雷; 第三步,点击方格的反应,计算每个非雷区方格点开后的数字; 第四步,当...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 47,965
精华内容 19,186
关键字:

游戏设计