じ☆ve冰风 发表于 2024-4-19 23:36:09

Sprite_Vision 地图视野

RUBY 代码
#======================================   
# 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=
    @directional = [,
                  ,
                  ,
                  ]
    # 由近到远的亮度变化率。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)
      # 内部亮度矩阵,存放各个角色看到的亮度的最大值   
      @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=*1000
      @ylist=*1000
      @blist=*1000# 亮度   
      @tlist=*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=$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]]
    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=].max
      }
      @brightness=m
      # 更新刷新列表   
      if m != @disp
            @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 = b
            set_brightness(x, @cy)
            b *= @rate
            breakif@tags > @ctag
      }

      b=base_brightness(6)
      (@cx+1...@max_x).to_a.each{|x|
            @br = b
            set_brightness(x, @cy)
            b *= @rate
            breakif@tags > @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 = .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
          tag2 = @tags

          # 墙判定   
          br1 = tag1 > @ctag ? 0 : @br
          br2 = tag2 > ref_tag ? 0 : @br

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

          # 计算亮度   
          tmp = (br1 + br2) / 2
          @br = (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 - @disp
            if diff!=0
            @disp += .max.to_i * (diff0)
            @xlist=x; @ylist=y;
            @blist=@disp
            self.bitmap.fill_rect(x*32, y*32, 32, 32, @gray])
            #self.bitmap.draw_text(x*32, y*32, 32, 32, @tags.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
      @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
页: [1]
查看完整版本: Sprite_Vision 地图视野