查看: 61|回复: 0

[转载发布] Sprite_Vision 地图视野

[复制链接]
  • TA的每日心情
    开心
    4 天前
  • 签到天数: 37 天

    连续签到: 3 天

    [LV.5]常住居民I

    2028

    主题

    32

    回帖

    7260

    积分

    管理员

    Rank: 9Rank: 9Rank: 9

    VIP
    0
    卡币
    5184
    OK点
    16
    积分
    7260
    发表于 同元一千年八月六日(秋) | 显示全部楼层 |阅读模式
    RUBY 代码
    [code]#======================================   
    # Sprite_Vision 地图视野   
    # 作者: viktor   
    # 原创脚本。仅供讨论使用,不可以用于商用。转载请注明出处/暂时不对脚本进行更多的解释了。   
    # 设置视野方法:使用地图标记,原则是地图标记越大,高度越高。   
    #   
    # 最低的地面:0   
    # 墙:比下方的地面高1   
    # 竖直墙的顶部:比下方的墙高1   
    # 高地:与在高地下侧的竖直墙顶部高度相同。这样在高地上可以看到下面的东西   
    # 背后可通行的障碍物(如树木):可通行的部分与周围地面相同,底部+1   
    #   
    # 例如:   
    # 样例中的地面(浅绿草地):0   
    # 石头墙:1   
    # 石头墙顶部:2   
    # 高地(绿草地):2   
    # 高地上的树:树根3 树冠2   
    # 山顶的草:3   
    #======================================   
    #$Call_fillshadow = Win32API.new("bmp", "fill_shadow", 'lllli', 'i')   
    $width = 640if$width == nil  
    $height = 480if$height == nil  

    class Sprite_Vision < Sprite  
    # 配置   
    # 脚本开关   
    SWITCH = 30  
    # 渐变速率   
    STEP = 0.1  
    # 平滑开关   
    SMOOTH = true  
    # 可变配置   
    def init_param  
        # directional lighting   
        # [前 侧 后]方向的最大亮度   
        @lighting=[255, 160, 64]  
        @directional = [[0, 1, 1, 2],  
                        [1, 0, 2, 1],  
                        [1, 2, 0, 1],  
                        [2, 1, 1, 0]]  
        # 由近到远的亮度变化率。1表示不改变(可以看到前方无限远)   
        @rate = 1.0  
        # 阈值:小于此亮度的格子不可见   
        @threshold = 0  
        # 视野阴影的z值。如果遮挡了窗口需要调整这个。   
        self.z=10  
    end  
    # 直接修改init_param中的参数的方法。每秒至多调用一次因为有refresh   
    def set_param(param, value)  
      self.instance_variable_set(param, value)  
      refresh  
    end  
    # 经验公式。设置视野范围 0..1 为近..远 每秒至多调用一次因为有refresh   
    def set_range(param)  
      @threshold = (64 * (1.0 - param)).to_i  
      @rate = 0.4 + 0.6 * param  
      refresh  
    end  

        def initialize(viewport, tilemap)  
            super(viewport)  
            @tilemap = tilemap  
            init_param  
            init_cache  

            self.bitmap = Bitmap.new(@tilemap.map_data.xsize * 32,  
                                     @tilemap.map_data.ysize * 32)  
            self.bitmap.fill_rect(self.bitmap.rect, @gray[255])  
            # 内部亮度矩阵,存放各个角色看到的亮度的最大值   
            @brightness = Table.new(@tilemap.map_data.xsize, @tilemap.map_data.ysize)  
            # 显示亮度矩阵   
            @disp = Table.new(@tilemap.map_data.xsize, @tilemap.map_data.ysize)  
            # 玩家位置   
            @cx = -1; @cy = -1  
            # 跟随的玩家数量初始化为1   
            init_br(1)  
            # 设置绘制方法   
            @update_func = SMOOTH ? self.method(:smooth_update) :   
                                    self.method(:rough_update)  
            # 刷新列表初始化   
            @xlist=[0]*1000  
            @ylist=[0]*1000  
            @blist=[0]*1000  # 亮度   
            @tlist=[1]*1000  # 是否要刷新。正数为需要   
            @list_size = 0  

            refresh  
        end  

        def dispose  
            self.bitmap.disposeifself.bitmap != nil  
            super  
        end  

        def init_cache  
            srand; @Gray = []  
            # 颜色对象           
            (0..255).each{|x|@gray.push(Color.new(46, 29, 27, x))}  
            # 测试用颜色对象   
            # (0..255).each{|a| @gray.push(Color.new(rand(255), rand(255), rand(255), 64))}   

            # 地图标记   
            @tags = Table.new(@tilemap.map_data.xsize, @tilemap.map_data.ysize)  
            for x in0...@tags.xsize  
                for y in0...@tags.ysize  
                    @tags[x, y]=$game_map.terrain_tag(x, y)  
                end  
            end  
        end  

        def init_br(n)  
            # multiple lighting   
            # 初始化每个角色的亮度矩阵   
            @br=Table.new(@tilemap.map_data.xsize, @tilemap.map_data.ysize, n)  
            @nc = n  
            @current = 0  
        end  

        # 取某方向的最大亮度   
        def base_brightness(direction)  
            return@lighting[@directional[$game_player.direction/2-1][direction/2-1]]  
        end  
        # 计算刷新矩形   
        def count_refresh_rect  
            @min_x = $game_map.display_x / 128  
            @min_y = $game_map.display_y / 128  
            @max_x = @min_x + $width / 32  
            @max_y = @min_y + $height / 32  
            # 调整   
            case$game_player.direction  
            when2  
                @max_y += 3  
            when4  
                @min_x -= 3  
            when6  
                @max_x += 3  
            when8  
                @min_y -= 3  
            end  
            # 剪裁,规范化   
            @min_x = [@min_x, 0].max.to_i  
            @min_y = [@min_y, 0].max.to_i  
            @max_x = [@max_x, @tilemap.map_data.xsize].min.to_i  
            @max_y = [@max_y, @tilemap.map_data.ysize].min.to_i  
        end  

        def set_brightness(x, y)  
            # 设置内部亮度值   
            m=0  
            (0...@nc).each{|z|  
                m=[m, @br[x, y, z]].max  
            }  
            @brightness[x, y]=m  
            # 更新刷新列表   
            if m != @disp[x, y]  
                @xlist[@list_size] = x  
                @ylist[@list_size] = y  
                @list_size += 1  
            end  
        end  

        def refresh  
            @cx = $game_player.x  
            @cy = $game_player.y  
            @list_size = 0  

            count_refresh_rect  
            @br[@cx, @cy, @current] = 255  
            set_brightness(@cx, @cy)  
            @ctag = @tags[@cx, @cy]  
            # 四方向预处理   
            b=base_brightness(2)  
            (@cy+1...@max_y).to_a.each{|y|  
                @br[@cx, y, @current] = b  
                set_brightness(@cx, y)  
                b *= @rate  
                breakif@tags[@cx, y] > @ctag  
            }  

            b=base_brightness(4)  
            (@min_x...@cx).to_a.reverse_each{|x|  
                @br[x, @cy, @current] = b  
                set_brightness(x, @cy)  
                b *= @rate  
                breakif@tags[x, @cy] > @ctag  
            }  

            b=base_brightness(6)  
            (@cx+1...@max_x).to_a.each{|x|  
                @br[x, @cy, @current] = b  
                set_brightness(x, @cy)  
                b *= @rate  
                breakif@tags[x, @cy] > @ctag  
            }  

            b=base_brightness(8)  
            ref_tag = @ctag + 1  
            (@min_y...@cy).to_a.reverse_each{|y|  
                @br[@cx, y, @current] = b  
                set_brightness(@cx, y)  
                b *= @rate  
                this_tag = @tags[@cx, y]  
                breakif this_tag > ref_tag  
                # ref_tag = [this_tag, ref_tag].max   
            }  

            # 填充其他格子   
            # up-right   
            iterate_tiles(@cx+1...@max_x,  
                          (@min_y...@cy).to_a.reverse,  
                          1, -1)# rescue p @min_y, @cy   
            # up-left   
            iterate_tiles((@min_x...@cx).to_a.reverse,  
                          (@min_y...@cy).to_a.reverse,  
                          -1, -1)  
            # down-left   
            iterate_tiles((@min_x...@cx).to_a.reverse,  
                          @cy+1...@max_y,  
                          -1, 1)  
            # down-right   
            iterate_tiles(@cx+1...@max_x,   
                          @cy+1...@max_y,  
                          1, 1)  

            # 滚动   
            @current = (@current + 1) % @nc  
        end  

        def iterate_tiles(xarray, yarray, dx, dy)  
          ref_tag = @ctag  
          for y in yarray  
            for x in xarray  
              tag1 = @tags[x - dx, y]  
              tag2 = @tags[x, y - dy]  

              # 墙判定   
              br1 = tag1 > @ctag ? 0 : @br[x-dx, y, @current]  
              br2 = tag2 > ref_tag ? 0 : @br[x, y-dy, @current]  

              ref_tag = tag2 if dy==-1and ref_tag < tag2  

              # 计算亮度   
              tmp = (br1 + br2) / 2  
              @br[x, y, @current] = (tmp>@threshold?tmp:0)  
              set_brightness(x, y)  
            end  
          end  
        end  

        def update_bitmap(step=STEP)  
            new_size=0  
            for i in0...@list_size  
                x = @xlist; y = @ylist  
                diff = @brightness[x, y] - @disp[x, y]  
                if diff!=0  
                  @disp[x, y] += [diff.abs*step, 1].max.to_i * (diff0)  
                  @xlist[new_size]=x; @ylist[new_size]=y;  
                  @blist[new_size]=@disp[x, y]  
                  self.bitmap.fill_rect(x*32, y*32, 32, 32, @gray[255-@blist[new_size]])  
                  #self.bitmap.draw_text(x*32, y*32, 32, 32, @tags[x, y].to_s, 1)   
                  new_size += 1  
                end  
            end  

            @list_size = new_size  
            # puts new_size   
            # 调用dll   
            #$Call_fillshadow.call(self.bitmap.object_id,   
            #            @xlist.object_id, @ylist.object_id, @blist.object_id,   
            #            @list_size)   
        end  

        def smooth_update  
            # 移动时刷新视野数据   
            refresh if$game_player.x != @cxor$game_player.y != @cy  
            # 每一帧平滑刷新视野图形   
            update_bitmap  
        end  
        def rough_update  
            # 移动时刷新视野数据   
            if$game_player.x != @cxor$game_player.y != @cy  
              refresh   
              update_bitmap  
            end  
        end      
        def update  
          @update_func.call  
          super  
        end  
    end  

    # 接入部分   
    class Spriteset_Map  
      attr_accessor :vision_sprite  

      def update_vision  
        if@vision_sprite==nil  
          @vision_sprite=Sprite_Vision.new(@viewport1, @tilemap)  
          @vision_sprite.init_br($game_party.actors.size)  
          @vision_sprite.opacity=0  
        end  
        if$game_switches[Sprite_Vision::SWITCH]  
          @vision_sprite.visible=true  
          @vision_sprite.opacity+=10if@vision_sprite.opacity < 255  
          @vision_sprite.ox=$game_map.display_x / 4  
          @vision_sprite.oy=$game_map.display_y / 4  
          @vision_sprite.update  
        else  
          if@vision_sprite!=nil  
            @vision_sprite.opacity-=10  
            @vision_sprite.visible=falseif@vision_sprite.opacity
    天天去同能,天天有童年!
    回复 论坛版权

    使用道具 举报

    ahome_bigavatar:guest
    ahome_bigavatar:welcomelogin
    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|Archiver|手机版|小黑屋|同能RPG制作大师 ( 沪ICP备12027754号-3 )

    GMT+8, 2024-5-14 16:17 , Processed in 0.061683 second(s), 41 queries .

    Powered by Discuz! X3.4

    Copyright © 2001-2020, Tencent Cloud.

    快速回复 返回顶部 返回列表