じ☆ve冰风 发表于 2024-4-20 02:06:18

重写“半生烛光”

整体还是很鸡肋,效果基本没变化,懒得做gif示意图了。
烛火可以自定义颜色,支持不透明度变化实现明暗变化,API效率提升,代码是关于灯光效果的实现,关于交互自行修改添加吧。
Light.dllVS2017 C语言编写

RUBY 代码
class Rect
def to_int
    self.__id__
end
end

class Bitmap
def to_int
    self.__id__
end
end


module LIGHT
# 并不严谨的标志,但是方便
Flag = "set_light"

Pic_Dir = "Graphics/Light_Textures"

# 透明通道图片,有效值为alpha,填充的颜色能看清图形就好,建议黑色
Light_Type_Pic_Name = {
    0 => "round.png"
}

Light_Effect_Rect_Frame = 10

dll = "Light.dll"

# 源位图双线性插值缩放至目标位图(无混合)
# dst_bitmap_obj_id, src_bitmap_obj_id
Stretch = Win32API.new(dll, 'bitmap_stretch_move', 'LL', 'L')

# ————灯光专用方法————
# 以纹理的alpha值进行颜色填充,再与黑色(0xFF000000)进行混合(Bitmap#blt)
# alpha: 0       16
    @min_alpha = (alpha_dinx & 0xFF00) >> 8
    @max_alpha = alpha_dinx & 0xFF
    if@min_alpha > @max_alpha
      @min_alpha, @max_alpha = @max_alpha, @min_alpha
    end
end

def display_at(target_bitmap)
    self.alpha_update
    returnif@alpha == 0

    dx = (@event.real_x - $game_map.display_x + 3) / 4 + @off_x
    returnif dx >= target_bitmap.width            #left
    returnif dx + @src_rect.width - 1 = target_bitmap.height         #top
    returnif dy + @src_rect.height - 1@max_alpha
      @alpha, @delta_alpha = @max_alpha, -@delta_alpha
      end
      if@alpha < @min_alpha
      @alpha, @delta_alpha = @min_alpha, -@delta_alpha
      end
    end
end

def src_rect_update
    if@rect_active == true
      @src_rect.x += @src_rect.width
      @src_rect.x = 0if@src_rect.x >= @bitmap.width
    end
end

def bitmap_dispose
    @bitmap.dispose
end
end


class LightRenderTarget

def initialize(viewport)
    @alpha = -1
    self.alpha = 128

    returnif$game_map.light_switch == false

    @rt = Sprite.new(viewport)
    @target = Bitmap.new(viewport.rect.width, viewport.rect.height)
    @rt.bitmap = @target
    @rt.blend_type = 2
    @rt.z = 1000
end

def alpha=(new_alpha)
    returnif@alpha == new_alpha
    @alpha = new_alpha < 0 ? 0 : (new_alpha > 255 ? 255 : new_alpha)
end

def update
    returnif$game_map.light_switch == false
    returnif@alpha == 0

    if Graphics.frame_count % LIGHT::Light_Effect_Rect_Frame == 0
      $game_map.light_data.each{|i| i.src_rect_update}
    end

    LIGHT::Full.call(@target, @alpha)   
    $game_map.light_data.each{|i| i.display_at(@target)}
end

def dispose
    if@target != nil
      @target.dispose
      @rt.dispose
      @target = nil
    end

    LIGHT.cache_clear
end
end

class Interpreter
includeLIGHT::Macro
end

class Game_Player
includeLIGHT::Interface

def light_on(*args)
    @light_data ||= []
    self.set_light(*args)
end

# 其实类似手电筒,根据方向调整 center_type, off_x, off_y, cell_idx就可以实现
end


#———以下代码有大部分RMXP原代码,建议直接添加至原代码———

class Game_Map
attr_reader   :light_data
attr_reader   :light_switch
#--------------------------------------------------------------------------
# ● 初始化条件
#--------------------------------------------------------------------------
def initialize
    @map_id = 0
    @display_x = 0
    @display_y = 0

    @light_data = []
    @light_switch = false
end
#--------------------------------------------------------------------------
# ● 设置
#   map_id : 地图 ID
#--------------------------------------------------------------------------
def setup(map_id)
    # 地图 ID 记录到 @map_id
    @map_id = map_id
    # 地图文件装载后、设置到 @map
    @map = load_data(sprintf("Data/Map%03d.rxdata", @map_id))
    # 定义实例变量设置地图元件信息
    tileset = $data_tilesets[@map.tileset_id]
    @tileset_name = tileset.tileset_name
    @autotile_names = tileset.autotile_names
    @panorama_name = tileset.panorama_name
    @panorama_hue = tileset.panorama_hue
    @fog_name = tileset.fog_name
    @fog_hue = tileset.fog_hue
    @fog_opacity = tileset.fog_opacity
    @fog_blend_type = tileset.fog_blend_type
    @fog_zoom = tileset.fog_zoom
    @fog_sx = tileset.fog_sx
    @fog_sy = tileset.fog_sy
    @battleback_name = tileset.battleback_name
    @passages = tileset.passages
    @priorities = tileset.priorities
    @terrain_tags = tileset.terrain_tags
    # 初始化显示坐标
    @display_x = 0
    @display_y = 0
    # 清除刷新要求标志
    @need_refresh = false

    # 释放上一地图的灯光对象
    @light_data.each{|i| i.bitmap_dispose}
    @light_data.clear

    # 设置地图事件数据
    @events = {}
    for i in@map.events.keys
      @events = Game_Event.new(@map_id, @map.events)
    end

    @light_switch = !@light_data.empty?

    # 设置公共事件数据
    @common_events = {}
    for i in1...$data_common_events.size
      @common_events = Game_CommonEvent.new(i)
    end
    # 初始化雾的各种信息
    @fog_ox = 0
    @fog_oy = 0
    @fog_tone = Tone.new(0, 0, 0, 0)
    @fog_tone_target = Tone.new(0, 0, 0, 0)
    @fog_tone_duration = 0
    @fog_opacity_duration = 0
    @fog_opacity_target = 0
    # 初始化滚动信息
    @scroll_direction = 2
    @scroll_rest = 0
    @scroll_speed = 4
end
end


class Game_Event
includeLIGHT::Macro
includeLIGHT::Interface

# !!注释即代码,不能乱写!!
# 只在“第一个指令块”有效。
# 标志:事件当前页的第一条指令set_light(...);
def refresh_light
    if@list
      if@list.code == 108
      if(params = @list.parameters).include?(LIGHT::Flag)
          i, scripts = 1, params.dup

          while(@list.code == 408)
            scriptsXP) 脚本 tktk_bitmap.dll 替换成 Light.dll,原工程自行下载。
RUBY 代码
=begin
HN_Light version 1.0.1.0 for VX Ace
        by 半生
http://www.tktkgame.com

要HN_RG_BITMAP(ver 0.1.2.1以降)

2012/01/08 ver 1.0.1.2
 队列歩行の仲间に対応

2015/04/25 Xp移植(ver 1.0)
By RyanBern

2015/12/20 ver 1.1
Z 坐标修正 && 战斗测试 BUG 修复

2018/02/11 ver 1.2
增加控制黑暗不透明度的变量

=end


# 注释掉的为原代码,替换代码都比原代码快


class Bitmap; def to_int; self.__id__; end; end
class Rect; def to_int; self.__id__; end; end

# ----- 在这里设定-----
module HN_Light
# 简略化0:(精细)~2:(粗暴,负荷轻)
SIMPLIFY = 2

# 表示黑暗处的不透明度的变量号码
# 变量的数值为0-255,越大则不可见度越高
DARK_OPACITY_VAR = 11

# 玩家的烛光类型使用的变量号码
PLAYER_LIGHT_TYPE = 12

# 黑暗判断上使用的开关
DARK_SWITCH = 11

# 烛光事件识别用的正规表达式
REGEX_LIGHT = /@LIGHT(\d+)/

# 烛光图像的目录
LIGHT_IMG_DIR = "Graphics/Pictures/"

# 烛光Bitmap设定
LIGHTS = [
# [文件名,单元数, 放大率,Y偏移值, 色相]
    ["light1",   1,    2.0,      0,    0],
    ["light2",   1,    1.0,      0,    0],
    ["light3",   1,    0.8,      0,    0],
    ["light4",   1,    1.0,      -16,    0],
    ["light5",   1,    2.0,      0,    0],
    ["light6",   1,    1.0,      0,    0],
    ["light7",   1,    3.0,      -16,    0],
    ["light1",   1,    0.5,      0,    0],
    ["light6",   1,    2.0,      0,    0],
]

dll = "Light.dll"
Stretch = Win32API.new(dll, 'bitmap_stretch_move', 'LL', 'L')
Mul = Win32API.new(dll, 'bitmap_light_mul', 'LLLLLL', 'L')
Full = Win32API.new(dll, 'bitmap_full_white_alpha', 'LL', 'L')
end
#----- 在这里设定 -----

module HN_Light
# 事件mix-in用
module LightEvent
    attr_reader :light_type
    def initialize
      super()
      @light_type = 0
    end

    def check_light
      @light_type = 0
      returnif@list.nil?
      @list.eachdo |command|
      breakif@light_type > 0
      if command.code == 108or command.code == 408
          command.parameters.eachdo |line|
            if line =~ REGEX_LIGHT
            @light_type = $1.to_i
            break
            end
          end
      end
      end# END @list.each
    end

end# END module LightEvent


class Light
    attr_reader :bitmap
    attr_reader :cells
    attr_reader :width
    attr_reader :height
    attr_reader :ox
    attr_reader :oy
    def initialize(light_type, s_zoom = 1)
      light = LIGHTS
      if light.nil?
      # 本来不应该来这里
      @bitmap = Bitmap.new(32, 32)
      @cells = 1
      @zoom = 1.0
      @oy = 16
      @ox = 16
      @width= 32
      @height = 32
      else
      @bitmap = Bitmap.new(LIGHT_IMG_DIR + light)
      #@bitmap.invert()
      @cells = light.to_i
      @cells = 1if(@cells < 1or@cells > @bitmap.width)
      @zoom = light.to_f
      @zoom = 1.0if@zoom0)
      @light_events.push(event)
      end
    end
end

alias:_hn_light__setup_events:setupunless method_defined?(:_hn_light__setup_events)
def setup(map_id)
    _hn_light__setup_events(map_id)
    refresh_lights()if@map_id > 0
end

alias:_hn_light__refresh:refreshunless method_defined?(:_hn_light__refresh)
def refresh
    _hn_light__refresh()
    refresh_lights()if@map_id > 0
end
end

class Sprite_Dark < Sprite
@@base_color = Color.new(255,255,255,192)

def initialize(viewport = nil)
    super(viewport)
    @width = 640
    @height = 480

    caseHN_Light::SIMPLIFY
    when1
      @zoom = 2
    when2
      @zoom = 4
    else
      @zoom = 1
    end
    @width /= @zoom
    @height /= @zoom
    self.zoom_x = @zoom.to_f
    self.zoom_y = @zoom.to_f

    self.bitmap = Bitmap.new(@width, @height)
    self.bitmap.fill_rect(self.bitmap.rect, @@base_color)
    self.blend_type = 2# 混合型(减算)
    self.z = 800
    self.visible = false
    @light_cache = {}
end

# 追加烛光
def add_light(charactor)
    returnif charactor.nil?
    light_type = charactor.light_type
    returnif(light_type < 1or light_type > HN_Light::LIGHTS.size)
    unless@light_cache.key?(light_type)
      @light_cache = HN_Light::Light.new(light_type, @zoom)
    end
    light = @light_cache

    # 画面外什麽都不做
    if@zoom == 1
      returnif(charactor.screen_x < 0- light.width + light.ox)
      returnif(charactor.screen_x > @width + light.ox)
      returnif(charactor.screen_y < 0 - light.height + light.oy)
      returnif(charactor.screen_y > @height + light.oy)
    else
      returnif(charactor.screen_x < 0- (light.width + light.ox) * @zoom)
      returnif(charactor.screen_x > (@width + light.ox)* @zoom)
      returnif(charactor.screen_y < 0 - (light.height + light.oy) * @zoom)
      returnif(charactor.screen_y > (@height + light.oy) * @zoom)
    end

    # 动画判定
    if light.cells > 1
      index = (Graphics.frame_count / 4) % light.cells
      rect = Rect.new(index * light.width , 0, light.width, light.height)
    else
      rect = light.bitmap.rect
    end
    if@zoom != 1
      p_x = charactor.screen_x / @zoom - light.ox
      p_y = (charactor.screen_y - 16) / @zoom - light.oy
    else
      p_x = charactor.screen_x - light.ox
      p_y = charactor.screen_y - 16 - light.oy
    end

    # 乗算合成(3)
    #self.bitmap.blend_blt(p_x, p_y, light.bitmap, rect, 3)
    HN_Light::Mul.call(self.bitmap, p_x, p_y, light.bitmap, rect, 255)
end


def refresh
    #self.bitmap.fill_rect(self.bitmap.rect, @@base_color)
    HN_Light::Full.call(self.bitmap, @@base_color.alpha.to_i)
    $game_map.light_events.eachdo |event|
      nextifHN_Light::LIGHTS.nil?
      add_light(event)
    end
    add_light($game_player)
end

# 更新
def update
    super
    #@@base_color = Color.new(255, 255, 255, $game_variables)
    @@base_color.alpha = $game_variables
    refresh()
end

#--------------------------------------------------------------------------
# ● 解放
#--------------------------------------------------------------------------
def dispose
    self.bitmap.dispose
    @light_cache.values.eachdo |light|
      light.dispose
    end
    super
end
end


class Spriteset_Map
# 动画判定
def create_dark
    @dark_sprite = Sprite_Dark.new(@viewport1)
end

# 更新黑暗Sprite
def update_dark
    if(@dark_sprite.visible = $game_switches)
      @dark_sprite.update
    end
end

# 破弃黑暗Sprite
def dispose_dark
    @dark_sprite.dispose
end

# 初期化
alias:_dark__initialize:initializeunless private_method_defined?(:_dark__initialize)
def initialize
    _dark__initialize()
    create_dark()
    update_dark()
end

# 更新
alias:_dark__update:updateunless method_defined?(:_dark__update)
def update
    _dark__update()
    update_dark()if !@dark_sprite.nil? and !@dark_sprite.disposed?
end

# 结束处理
alias:_dark__dispose:disposeunless method_defined?(:_dark__dispose)
def dispose
    dispose_dark()
    _dark__dispose()
end
end








             本帖来自P1论坛作者RPGzh500223,因Project1站服务器在国外有时候访问缓慢不方便作者交流学习,经联系P1站长fux2同意署名转载一起分享游戏制作经验,共同为国内独立游戏作者共同创造良好交流环境,原文地址:https://rpg.blue/forum.php?mod=viewthread&tid=491685若有侵权,发帖作者可联系底部站长QQ在线咨询功能删除,谢谢。
页: [1]
查看完整版本: 重写“半生烛光”