じ☆ve冰风 发表于 2026-8-3 13:06:40

Costume Selector

This is a script that I wrote and allows to set up sprites in 96x128 sheets as costumes for the Player to pick from and use.
I wrote it to suit my personal needs when playing RPG Maker VX Ace games, but I figured it'd be cool to share it with all of you.
You're all constantly sharing cool scripts for free and stuff so I might as well put my grain of sand.

Key Points

To open the selector you can use SceneManager.call(Scene_SpriteSelector).

The magic happens in the "@sprite_data" array
Which uses the following parameters:
-The filename of a 96x128 sprite sheet containing your sprite's walking frames
-A switch Id to toggle when you pick a sprite to use
-A text string meant to describe each sprite
-A switch Id that defines whether the sprite is unlocked and ready to use or not.
-An item Id through which you can unlock specific sprites by having a specific item in the inventory.
Setting the 2nd, 4th or 5th parameters (parameters 1, 3 and 4 in the code) to "-1" disables them.

The script is somewhat messy because I wrote it for personal usage.
Consider this something that you can plop into a project and will work as intended at best, and a script to use as a base to work with at worst.

By default, the selector is designed for games that use a base screen resolution of 640x480 pixels
But this can be easily adjusted with the variables that I laid at the top. Reducing the padding between or the amount of sprites per row and column should make it easy for this script to work in other screen resolutions besides the intended 640x480 for example.
Probably.

The script has a small safety measure of sorts
If you input an invalid or nonexistent filename the script will show "a code-based placeholder sprite" kinda thing, a black square with a question mark.
I should expand that and make it detect sprite sheets that don't adjust to the 96x128px criteria, buuut I'm kinda lazy and I personally don't need to do that so.

The script uses a SPRITE_ID_VARIABLE to track the Id of the current sprite in use
By default, SPRITE_ID_VARIABLE is set to 6.
As a result, if you added 50 sprites to pick from and selected the 44th, the value of the Variable 6 would be set to 44.

Pics and Vids



Code

                Ruby:       
#############################################################################################################
#                                                                                                         #
# Terms of Use:                                                                                             #
#                                                                                                         #
# - This script can be used in commercial and non-commercial projects.                                    #
#                                                                                                         #
# - This script can be edited and used as a base to work with.                                              #
#                                                                                                         #
# - Redistribution is allowed but the link to this script's thread in RPG Maker Forums has to be included.#
#   https://forums.rpgmakerweb.com/index.php?threads/costume-selector.176487                              #
#                                                                                                         #
# - If you use this script in a publicly published project                                                #
#   regardless of whether it's commercial or not,                                                         #
#   credits to me (Nanjo from the RPG Maker Forums) are mandatory.                                          #
#                                                                                                         #
#############################################################################################################

class Scene_SpriteSelector < Scene_MenuBase
FRAME_WIDTH = 32
FRAME_HEIGHT = 32
ARROW_OFFSET_Y = -24
SPRITE_OFFSET_Y = 16
VERTICAL_SPACING = 16
HORIZONTAL_SPACING = 18
TOP_PADDING = 40
SPRITES_PER_ROW = 11
SPRITES_PER_COLUMN = 6
SPRITES_PER_PAGE = SPRITES_PER_ROW * SPRITES_PER_COLUMN
SPRITE_ID_VARIABLE = 6
ACTOR_ID = 1

def start
    super
    @current_page = 0
    @current_index = 0
    create_background_window
    create_sprites
    create_arrow
    create_message_window
    update_arrow
end

def create_background_window
    @background_window = Window_Base.new(0, 0, Graphics.width, Graphics.height - 72)
    @background_window.opacity = 128
end

def create_sprites
    dispose_sprites
    @sprites = []
    @unlocked_sprites = []

    @sprite_data = [
      ["Actor1", -1, "Actor 1 sprite", -1, -1],
      ["Actor2", -1, "Actor 2 sprite", -1, -1],
      ["Actor3", -1, "Actor 3 sprite", -1, -1],
      ["Actor4", -1, "Actor 4 sprite", -1, -1],
      ["Insane1", -1, "Unlocks when Life Up is in inventory", -1, 9],
      ["Insane2", -1, "Unlocks when Switch 1 is ON", 1, -1],
      ["Monster1", -1, "Unlocks when Life Up is in inventory and Switch 2 is ON", 2, 9],
      ["Monster2", 2, "Sets Switch 2 to ON", -1, -1],
    ]

    @viewport = Viewport.new(0, 0, Graphics.width, Graphics.height - 72)
    @viewport.z = 100

    first_row_y = TOP_PADDING
    page_data = @sprite_data[@current_page * SPRITES_PER_PAGE, SPRITES_PER_PAGE] || []

    page_data.each_with_index do |data, index|
      sprite = Sprite.new(@viewport)
      character_name = data
      next if character_name.nil?

      sprite.opacity = ($game_switches] || data == -1) && ($game_party.has_item?($data_items]) || data == -1) ? 255 : 100
      @unlocked_sprites.push(sprite.opacity == 255)

      begin
      sprite.bitmap = Cache.character(character_name)
      rescue StandardError
      sprite.bitmap = Bitmap.new(FRAME_WIDTH, FRAME_HEIGHT)
      sprite.bitmap.fill_rect(0, 0, FRAME_WIDTH, FRAME_HEIGHT, Color.new(0, 0, 0))
      draw_small_question_mark(sprite.bitmap)
      end

      sprite.src_rect.set(0, 0, FRAME_WIDTH, FRAME_HEIGHT)
      row = index / SPRITES_PER_ROW
      col = index % SPRITES_PER_ROW
      sprite.x = 50 + col * (FRAME_WIDTH + HORIZONTAL_SPACING)
      sprite.y = first_row_y + row * (FRAME_HEIGHT + SPRITE_OFFSET_Y + VERTICAL_SPACING)

      @sprites.push(sprite)
    end
end

def draw_small_question_mark(bitmap)
    font = Font.new(24)
    bitmap.font = font
    question_text = "?"
    text_width = bitmap.text_size(question_text).width
    text_height = bitmap.text_size(question_text).height
    x = (FRAME_WIDTH - text_width) / 2
    y = (FRAME_HEIGHT - text_height) / 2
    bitmap.draw_text(x, y, text_width, text_height, question_text, 1)
end

def create_message_window
    @message_window = Window_Base.new(0, Graphics.height - 72, Graphics.width, 72)
    @message_window.contents = Bitmap.new(@message_window.width - 32, @message_window.height - 32)
    update_message
end

def update_message
    @message_window.contents.clear
    if @sprite_data[@current_index]
      text = @sprite_data[@current_index]
      @message_window.draw_text(0, 0, @message_window.contents.width, 48, text, 1)
    end
end

def create_arrow
    @arrow_sprite = Sprite.new(@viewport)
    @arrow_sprite.bitmap = Bitmap.new(32, 16)
    @arrow_sprite.bitmap.clear

    16.times do |y|
      x_start = y
      x_end = 31 - y
      @arrow_sprite.bitmap.fill_rect(x_start, y, x_end - x_start + 1, 1, Color.new(255, 0, 0))
    end

    @arrow_sprite.ox = 16
    @arrow_sprite.oy = 0
end

def update_arrow
    return if @sprites.empty? || @sprites[@current_index].nil?
    sprite = @sprites[@current_index]
    @arrow_sprite.x = sprite.x + FRAME_WIDTH / 2
    @arrow_sprite.y = sprite.y + ARROW_OFFSET_Y
end

def handle_input
    if Input.repeat?(:RIGHT)
      if @current_index < SPRITES_PER_PAGE - 1 && @current_page * SPRITES_PER_PAGE + @current_index < @sprite_data.size - 1
      @current_index += 1
      elsif (@current_page + 1) * SPRITES_PER_PAGE < @sprite_data.size
      @current_page += 1
      @current_index = 0
      end
      create_sprites
      update_arrow
      update_message
    elsif Input.repeat?(:LEFT)
      if @current_index > 0
      @current_index -= 1
      elsif @current_page > 0
      @current_page -= 1
      @current_index = SPRITES_PER_PAGE - 1
      end
      create_sprites
      update_arrow
      update_message
    elsif Input.repeat?(:DOWN)
      if @current_index + SPRITES_PER_ROW < SPRITES_PER_PAGE && @current_page * SPRITES_PER_PAGE + @current_index + SPRITES_PER_ROW < @sprite_data.size
      @current_index += SPRITES_PER_ROW
      elsif (@current_page + 1) * SPRITES_PER_PAGE < @sprite_data.size
      @current_page += 1
      @current_index += SPRITES_PER_ROW - SPRITES_PER_PAGE
      end
      create_sprites
      update_arrow
      update_message
    elsif Input.repeat?(:UP)
      if @current_index - SPRITES_PER_ROW >= 0
      @current_index -= SPRITES_PER_ROW
      elsif @current_page > 0
      @current_page -= 1
      @current_index -= SPRITES_PER_ROW - SPRITES_PER_PAGE
      end
      create_sprites
      update_arrow
      update_message
    elsif Input.trigger?(:C)
      selected_index = @current_page * SPRITES_PER_PAGE + @current_index
      if @unlocked_sprites[@current_index]
      sprite_name = @sprite_data

      begin
          Cache.character(sprite_name)
      rescue StandardError
          Sound.play_buzzer
          return
      end

      $game_player.set_graphic(sprite_name, 0)
      $game_variables = selected_index if SPRITE_ID_VARIABLE != -1
      $game_switches[@sprite_data] = true if @sprite_data != -1

      Sound.play_ok
      SceneManager.return
      else
      Sound.play_buzzer
      end
    elsif Input.trigger?(:B)
      SceneManager.return
    end
end

def update
    super
    handle_input
end

def dispose_sprites
    @sprites.each(&:dispose) if @sprites
    @sprites = []
end
end


Special thanks to Anonymous for helping me fix a problem with the cursor when switching between sprite pages that was driving me crazy!

Well, that's all from me!

Take care
data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7!​



本贴来自国际rpgmaker官方论坛作者:Nanjo处,因国际论坛即将永久关站,为了存档多年珍贵资料,署名转载到本论坛存档,由于官方帖子为英文原帖,需要中文翻译请点击论坛顶部切换语言为中文就可以将帖子翻译成中文浏览,方便大家随时查看,原文地址:https://forums.rpgmakerweb.com/threads/costume-selector.176487/
页: [1]
查看完整版本: Costume Selector