地上の洞窟

どこにも行かず、液晶と「にらめっこ」し続ける人の物語。

【RGSS3】スクリーンショット

ゲーム内でスクリーンショットを撮れるようになる、ありきたりなスクリプトです。
デフォルトではF8キーを押すことで、現在の画面をpngファイルへと変換し
Game.exeと同じ階層に「ScreenShot」フォルダを作成し保存します。

ついでに効果音も再生したりします。パシャリ。

更新履歴 内容
2023/08/18 初版

→スクリプト一覧へ


スクリプト(ダブルクリックで全選択)↓

=begin =========================================================================
 ■ ScreenShot - 地上の洞窟
================================================================================

 ボタン入力によって、現在の画面を.png形式の画像として保存します。

================================================================================
 ■ 設定項目
=end #==========================================================================

module Screenshot


  # KEY : スクリーンショットの実行を判別するためのボタン。
  KEY = :F8


  # SE_ENABLE : スクリーンショット時に効果音を再生するかどうかの設定。
  # true → 再生する / false → 再生しない
  SE_ENABLE = true


  # SE_NAME   : スクリーンショット時に再生する効果音のファイルパス。
  # SE_VOLUME : 効果音のボリューム。
  # SE_PITCH  : 効果音のピッチ。
  SE_NAME   = "Key"
  SE_VOLUME = 50
  SE_PITCH  = 115


  # PATH : スクリーンショットを保存するフォルダのパス。
  PATH = "./ScreenShot"
  
  
  # MAKE_MISSING_FOLDER : 
  # スクリーンショットの保存先のフォルダが存在しない場合、自動で作成します。
  # true → 作成する / false → 作成しない
  MAKE_MISSING_FOLDER = true


  # TIMES : スクリーンショットの保存処理にかけるフレーム数の目安。
  # 小さい程保存までの時間は短くなりますが、処理が重くなりフリーズする場合があります。
  TIMES = 60


#==============================================================================
# ■ ここからソースコード
#==============================================================================

  SE_DATA = RPG::SE.new(SE_NAME, SE_VOLUME, SE_PITCH)
  TIME_FORMAT = "%Y-%m-%d_%H-%M-%S"
  PNG_SIGNATURE = "\x89PNG\r\n\x1a\n"
  PNG_TERMINAL = "\x00\x00\x00\x00IEND\xAEB`\x82"
  PNG_HEADER_NAME = "IHDR"
  PNG_DATA_NAME = "IDAT"
  PNG_CHUNK_FORMAT = "NA4A*N"
  PNG_HEADER_FORMAT = "N2C5"
  PNG_RAW_DATA_FORMAT = "C*"

  @queue = []

  class << self
    def update
      if Input.trigger?(KEY)
        push
        SE_DATA.play if SE_ENABLE
      end
      (q = @queue[0]) && q.update
    end

    def push
      @queue << Writer.new
    end

    def shift
      @queue.shift
    end
  end

  class Writer
    def initialize
      @bitmap = Graphics.snap_to_bitmap
      @width = @bitmap.width
      @height = @bitmap.height
      @x = 0
      @y = 0
      @count = 0
      @stream = Zlib::Deflate.new
      @raw_data = []
      @packet = @width * @height / TIMES
    end

    def update
      if @data
        export_image
      else
        create_data
      end
    end

    def create_data
      @count = 0
      $ss_current = []
      while @y < @height
        $ss_current << 0
        while @x < @width
          @bitmap.get_pixel(@x, @y).ss_push
          @x += 1
        end
        @x = 0
        @y += 1
        if (@count += @width) >= @packet
          @stream << $ss_current.pack(PNG_RAW_DATA_FORMAT)
          return
        end
      end
      @stream << $ss_current.pack(PNG_RAW_DATA_FORMAT)
      @data = @stream.finish
      @stream.close
    end

    def export_image
      create_png_file(screenshot_path)
      @bitmap.dispose
      Screenshot.shift
    end

    def make_missing_folder(target_path)
      path = ""
      part = target_path.split('/')
      part.each do |str|
        Dir.exist?(path << str) || Dir.mkdir(path)
        path << '/'
      end
    end
    
    def screenshot_path
      make_missing_folder(PATH) if MAKE_MISSING_FOLDER
      base = "#{PATH}/#{Time.new.strftime(TIME_FORMAT)}"
      name = base
      i = 0
      while File.exist?(name) && i < 1_000
        name = "#{base}-#{i += 1}"
      end
      "#{name}.png"
    end

    def create_png_file(path)
      open(path, 'wb') do |file|
        file.print PNG_SIGNATURE
        file.print png_header
        file.print png_data
        file.print PNG_TERMINAL
      end
    end

    def png_chunk(type, data)
      [data.bytesize, type, data, Zlib.crc32(type << data)].pack(PNG_CHUNK_FORMAT)
    end
    
    def png_header
      png_chunk(
        PNG_HEADER_NAME,
        [@width, @height, 8, 2, 0, 0, 0].pack(PNG_HEADER_FORMAT)
      )
    end
    
    def png_data
      png_chunk(PNG_DATA_NAME, @data)
    end
  end
end

class Color
  def ss_push
    $ss_current.push(red, green, blue)
  end
end

class Scene_Base
  alias ss_update_basic update_basic unless method_defined?(:ss_update_basic)
  def update_basic
    Screenshot.update
    ss_update_basic
  end
end