编程启蒙——LOGO编程——28-程序:戳气泡小游戏

第28章:程序:戳气泡小游戏

ξ 28.1 需求描述


屏幕上随机生成一组气泡,可以设置数量;

气泡随机飘动,颜色随机变幻;

用户移动鼠标戳气泡,戳中则气泡消失;

提示用户气泡剩余数;

所有气泡都戳破后,显示所用时间。


ξ 28.2 设计思路


分解数据初始化随机飘移随机变色戳气泡显示完成时间

连接:初始化数据;定时飘移气泡、定时修改颜色、鼠标事件中处理戳气泡逻辑;显示所用时间。

递归

    数据初始化:气泡数、气泡大小、舞台大小,状态数据,设置气泡初始位置和飘移方向

    随机飘移——分解擦除气泡图案新位置重绘气泡图案

     ——连接:先擦除气泡图案,再在新位置重绘气泡图案

     ——递归

    擦除:画笔设为擦除模式,原位置重绘,即擦除

    重绘——分解设置飘移偏移量检查边界画气泡

           ——连接:先生成偏移量,再检查边界修正,最后画气泡

           ——递归

            设置飘移偏移量:在飘移方向上随机生成偏移量

            检查边界:检查新位置是否处于舞台边缘,或与其它气泡相遇,若是则反向飘移。

            画气泡:在新位置画气泡图形,即圆形


    随机改变颜色:定时器随机修改画笔颜色


    戳气泡——分解戳中气泡擦除气泡输出剩余气泡数

          ——连接:判断是否戳中,若是则擦除气泡,并输出剩余气泡数,否则不做处理

          ——递归

        戳中气泡:判断当前位置到各个气泡图形中心点的距离,小于半径为戳中

        擦除气泡:设置画笔为擦除模式,此时画气泡即为擦除

        输出剩余气泡数:剩余气泡数减一,输出文本

        显示完成时间——分解输出完成时间释放资源

            ——连接:先在屏幕上输出完成时间,再释放资源

            ——递归

                输出完成时间:程序从开始到戳破所有气泡两次记录毫秒数之差,屏幕输出

                 释放资源:关闭各个定时器,停止捕获鼠标事件


ξ 28.3 程序设计

 

定义两段程序

 

程序chuo_qipao:

        主程序

        参数shuliang,表示气泡总数


程序qipao_juli:

        计算到气泡的距离

        参数weizhi_yi, 表示当前位置

        参数weizhi_er,表示第二个位置

        参数qiu_banjing,表示气泡的半径


ξ 28.4 编程实现

 

代码

to chuo_qipao :shuliang ;戳气泡

    ;参数shuliang:气泡数量

    if :shuliang < 2 [ make "shuliang 2 ] ;数量最少是2

    if :shuliang > 10 [ make "shuliang 10 ] ;数量最多是10

    make "daxiao 25 ;气泡半径大小25像素

    ;舞台大小400像素,表示横轴(-400,400),纵轴(-400,400)

    make "wutai_daxiao 400

    ;气泡数组,元素是气泡状态,气泡状态也是数组,有5个元素

    make "qipao_zu (array :shuliang)

    ;下面的循环语句为每个气泡状态设置初值

    for [ i 1 :shuliang 1 ] [

        ;单双数序号的气泡,状态值中的飘浮方向不一样

        test (remainder :i 2) = 0

        ;气泡状态,有5个元素,

        ;按顺序分别是:横坐标、纵坐标、

        ;竖直飘移方向(1:向上,0:向下)、

        ;水平飘移方向(1:向右,0:向左)、

        ;是否已删除(1:是,0:否)。

        ift [ setitem :i :qipao_zu { 0 0 1 1 0 } ]

        iff [ setitem :i :qipao_zu { 0 0 -1 -1 0 } ]

     ]

    make "kaishi_shijian timemilli ;开始时间毫秒数

    ;当前时间毫秒数,这个变量会在后面的代码中随着时间修改

    make "dangqian_shijian timemilli

    setpensize [ 1 1 ] ;设置画笔宽度为1

    make "yanse 0 ;画笔颜色,会在定时器代码中随机修改

    make "yanse_zu { 0 1 2 3 4 5 6 8 9 10 11 12 13 14 15 } ;画笔颜色数组

    ;定时器,ID是1,间隔时间是1秒,用于动态改变画笔颜色

    settimer 1 60 [

        ;在颜色数组中随机选择一种颜色

        make "yanse (item (random (count :yanse_zu)) + 1 :yanse_zu)

        ;更新当前时间变量的值

        make "dangqian_shijian timemilli

    ]

    ;舞台上剩余的气泡数量

    make "shengyu_shu :shuliang

    ;循环检查时,上次的舞台剩余气泡数

    make "shengyu_shu_shangci :shuliang

    make "x 0 ;气泡中心点的x坐标

    make "y 0 ;气泡中心点的y坐标

    make "x_pianyi 0 ;气泡下个位置的x坐标轴的偏移

    make "y_pianyi 0 ;气泡下个位置的y坐标轴的偏移

    ;气泡下个位置在x坐标轴偏移的方向,1就正向,-1是反向

    make "x_biaozhi 0

    ;气泡下个位置在y坐标轴偏移的方向,1就正向,-1是反向

    make "y_biaozhi 0

    make "shanchu 0 ;删除标值,1:已删除;0:未删除

    ;是否已为气泡组中所有气泡生成初始位置的值

    make "fenbu 0

    make "juli_dong 0 ;气泡移动时计算与其它气泡的距离

    make "shu_weizhi [ 0 0 ] ;鼠标的位置

    make "juli_shu 0 ;气泡移动时计算与气泡的距离

    make "qipao_shu [] ;当前气泡,用于处理鼠标事件

    ;定义鼠标事件,在按下鼠标左键时,

    ;判断是不是点在气泡上,

    ;若是,则将气泡的删除标识设置为1

    mouseon [

        make "shu_weizhi mousepos ;鼠标位置

        ;循环处理每个气泡

        for [ i 1 :shuliang 1 ] [

            make "qipao_shu (item :i :qipao_zu) ;当前气泡

            ;调用qipao_juli程序,获取当前气泡到鼠标位置的距离

            make "juli_shu (qipao_juli :qipao_shu :shu_weizhi :daxiao) ;如果距离小于气泡的半径,则认为戳中了气泡

            if :juli_shu < :daxiao [

                ;则将气泡的删除标识设置为1

                setitem 5 :qipao_shu 1

            ]

        ]

     ] [ ] [ ] [ ] [ ]

    ht ;隐藏箭头

    make "zhuangtai_biaoqian [] ;游戏进度状态标签

    ;当前气泡项的状态值,用于处理气泡移动

    make "qipao_dong []

    while [ :shengyu_shu > 0 ] [

        make "shengyu_shu 0 ;剩余气泡数

        ;循环处理每个气泡

        for [ i 1 :shuliang 1 ] [

            pu ;抬笔

            ;移动到当前气泡中心位置

            setxy (item 1 (item :i :qipao_zu)) (item 2 (item :i :qipao_zu))

            pe ;设置画笔为擦除状态

            pd ;落笔

            circle :daxiao ;擦除气泡

            ;取出气泡的删除标识

            make "shanchu (item 5 (item :i :qipao_zu))

            ;若删除标识为0,表示气泡未删除,

            ;要在新位置重绘,

            ;否则表示该气泡已删除,不用再画

            if :shanchu = 0 [

                ;重新统计剩余气泡数量

                make "shengyu_shu :shengyu_shu + 1

                ;取出横轴偏移方向

                make "x_biaozhi (item 3 (item :i :qipao_zu))

                ;取出纵轴偏移方向

                make "y_biaozhi (item 4 (item :i :qipao_zu))

                test :fenbu = 0 ;判断是否已生成初始位置

                ;若还未生成,则在此处生成

                ift [

                    ;横坐标,舞台大小范围的随机数

                    make "x (random :wutai_daxiao * 2) - :wutai_daxiao

                    ;纵坐标

                    make "y (random :wutai_daxiao * 2) - :wutai_daxiao

                ]

                ;若已生成,则动态生成偏移量,气泡移动位置

                iff [

                    make "x_pianyi (random 10) ;x轴偏移量

                    make "y_pianyi (random 10) ;y轴偏移量 ;取出x坐标位置

                    make "x (item 1 (item :i :qipao_zu))

                    ;修改x坐标,即加上偏移量

                    make "x :x + :x_pianyi * :x_biaozhi

                    ;取出y坐标位置

                    make "y (item 2 (item :i :qipao_zu))

                    ;修改y坐标,即加上偏移量

                    make "y :y + :y_pianyi * :y_biaozhi

                    ;x值超出舞台右边缘、

                    ;或超出舞台左边缘,则修改气泡移动方向

                    if or (:x > :wutai_daxiao - :daxiao/2) (:x < -:wutai_daxiao + :daxiao/2) [

                        ;偏移方向,乘-1即反向

                        make "x_biaozhi (:x_biaozhi * (-1))

                        ;校正超出的位置

                        ifelse :x > :wutai_daxiao - :daxiao/2 [

                            make "x :wutai_daxiao - :daxiao/2

                        ] [

                            make "x -:wutai_daxiao + :daxiao/2

                        ]

                    ]

                    ;y值超出舞台上边缘、

                    ;或超出舞台下边缘,则修改气泡移动方向

                    if or (:y > :wutai_daxiao - :daxiao/2) (:y < -:wutai_daxiao + :daxiao/2) [

                        ;偏移方向,乘-1即反向

                        make "y_biaozhi (:y_biaozhi * (-1))

                        ;校正超出的位置

                        ifelse :y > :wutai_daxiao - :daxiao/2 [

                            make "y :wutai_daxiao - :daxiao/2

                        ] [

                            make "y -:wutai_daxiao + :daxiao/2

                        ]

                    ]

                    ;在气泡相遇时,做出反弹的效果,

                    ;逐一判断是否与其它气泡相遇

                     for [ j 1 :shuliang 1 ] [

                        if not (:i = :j) [

                            ;排除当前气泡自身

                            ;排除已做删除标记的气泡

                            if (item 5 (item :j :qipao_zu)) = 0 [

                                ;调用qipao_juli程序,

                                ;获取当前气泡到其它气泡的距离

                                make "juli_dong (qipao_juli (list :x :y) (item :j :qipao_zu) :daxiao)

                                ;如果距离小于气泡半径加10像素的值,则认为两个气泡相遇

                                if (:juli_dong < :daxiao * 2 + 10) [

                                    ;将当前气泡x轴偏移方向反向

                                    make "x_biaozhi (:x_biaozhi * (-1))

                                    ;将当前气泡y轴偏移方向反向

                                    make "y_biaozhi (:y_biaozhi * (-1))

                                ]

                            ]

                        ]

                    ]

                ]

                ;重置当前气泡状态数据

                make "qipao_dong (array 5)

                setitem 1 :qipao_dong :x ;横坐标

                setitem 2 :qipao_dong :y ;纵坐标

                ;横轴偏移方向

                setitem 3 :qipao_dong :x_biaozhi

                ;纵轴偏移方向

                setitem 4 :qipao_dong :y_biaozhi

                setitem 5 :qipao_dong :shanchu ;删除标记

                ;修改当前气泡状态数据

                setitem :i :qipao_zu :qipao_dong

                ppt ;设置画笔为绘画状态

                setpc :yanse ;设置画笔颜色

                pu ;抬笔

                ;移动到新位置

                setxy (item 1 (item :i :qipao_zu)) (item 2 (item :i :qipao_zu))

                pd ;落笔

                circle :daxiao ;在新位置画气泡

            ]

        ]

        make "fenbu 1 ;修改已初始化气泡位置变量值为1

        wait 1 ;延时六十分之一秒

        ;如果前次剩余气泡数与当前不相等,即又戳中了新气泡

        if not (:shengyu_shu_shangci = :shengyu_shu) [

            if :shengyu_shu > 0 [;如果当前剩余气泡数大于0

                pu ;抬笔

                 ;移动位置到舞台右侧中间位置

                setpos (list :wutai_daxiao :shengyu_shu * 20)

                seth 90 ;设置方向为水平向右

                 ;要显示的文本

                make "zhuangtai_biaoqian (word "还有 :shengyu_shu "个)

                ppt ;设置画笔为绘画状态

                ;在舞台右侧中间位置显示剩余气泡数

                label :zhuangtai_biaoqian

            ]

        ]

        ;修改剩余气泡数变量的值

        make "shengyu_shu_shangci :shengyu_shu

     ]

    mouseoff ;关闭鼠标事件

    cleartimer 1 ;关闭定时器

    ppt ;设置画笔为绘画状态

    pu ;抬笔

    setxy 0 0 ;移动到舞台中央

    pd ;落笔

    setpensize [ 3 3 ] ;设置画笔宽度

    seth 90 ;设置方向为水平向右

    ;显示游戏完成所用时间

    label (word "完成!用时 ((:dangqian_shijian - :kaishi_shijian) / 1000) "秒)

    setpensize [ 1 1 ] ;恢复画笔宽度

end

to qipao_juli :weizhi_yi :weizhi_er :qiu_banjing

    ;计算两个位置间的距离

    ;参数weizhi_yi:第一个位置

    ;参数weizhi_er:第二个位置

    ;参数qiu_banjing:气泡的半径

    ;取出第二个位置的x坐标值

    make "x_shu (item 1 :weizhi_er)

    ;取出第二个位置的y坐标值

    make "y_shu (item 2 :weizhi_er)

    ;取出第一个位置的x坐标值

    make "x_dangqian (item 1 :weizhi_yi)

    ;取出第一个位置的y坐标值

    make "y_dangqian (item 2 :weizhi_yi)

    ;调用平方差公式,计算距离,保存到jieguo变量

    make "jieguo (sqrt ((:x_shu - :x_dangqian) * (:x_shu - :x_dangqian) + (:y_shu - :y_dangqian) * (:y_shu - :y_dangqian)))

    op :jieguo ;返回计算结果

end

 

运行程序

 

chuo_qipao 8


运行效果



下一篇

附录:指令速查索引

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容