Extended Map Sprite Tiles & Autotiles (EMSTA)
Extended Map Sprite Tiles & Autotiles (EMSTA) allows inserting tile or autotile sprites on the map via script without layer limitations. It's basically like when you use an event as a tile, but in this case there's no event, so it causes much less lag.It doesn't affect the passability, but apart from that it is like a completely normal tile. In addition, in terms of passability, it can be easily solved by assigning an empty but not passable tile.
So far I know it doesn't seem like a big deal, but what advantages does this have then?
[*]More than 3 tiles per map coordinate without having to use an empty event (i.e. less lag)
[*]More than 4 tiles per map coordinate; now it's unlimited.
[*]More tile priorities; now unlimited, and it also accepts negative values.
[*]More than 7 autotiles per tileset/map. here]
[*]The Cliff Bugfix can be used with EMSTA for more complex cliff interactions.
[*]Battle animations applied on tile and autotile sprites, and other similar stuff.
[*]Engine shortcuts. Assign a parameter to EMSTA sprites and apply changes on them by group.
Authors: Wecoc & Eron
First Release: February 2018
Last Version: June 2020
Terms of use
- Giving credits (Wecoc & Eron) for using this script is optional, but appreciated.
- You can repost this code.
- You can edit this code freely, and distribute the edits as well.
- This code can be used on commercial games.
Code
Ruby:
#==============================================================================# ** Extended Map Sprite Tiles & Autotiles (EMSTA)#------------------------------------------------------------------------------# Authors: Wecoc & Eron (credits are optional)# Version: 1.1#==============================================================================# This script allows inserting tile and autotile sprites on the map.# They will look like normal tiles, but won't affect the passability.# Its advantage is you can define as many as you want per coordinate, and you# can get them from another tileset, so you can break the limit of autotiles# per map. Even with that it's a bit complicated to use so I recommend limiting# it to those cases where it's really necessary.#------------------------------------------------------------------------------# Note: When placing EMSTA sprites an ID is assigned, like with events. You can# use it as reference to directly control that sprite, for example removing it.#------------------------------------------------------------------------------# 1) Define a tile sprite on the map# $game_map.set_sprite_tile(x, y, tile_id)# $game_map.set_sprite_tile(x, y, tileset_id, tile_id)# $game_map.set_sprite_tile(x, y, tileset_id, tile_id, z)# tile_id - Tile ID (position inside the tileset)# tileset_id - Tileset ID on the Database (current tileset when non-defined)# z - Tile priority (when non-defined uses default priority on the tileset)# Example: $game_map.set_sprite_tile(4, 10, 3, 384)# Note: You can also define a tag for this sprite# Example: $game_map.set_sprite_tile(4, 10, 3, 384, :tree)#------------------------------------------------------------------------------# 1) Define an autotile sprite on the map# $game_map.set_sprite_autotile(x, y, autotile_id, tile_id)# $game_map.set_sprite_autotile(x, y, tileset_id, autotile_id, tile_id)# $game_map.set_sprite_autotile(x, y, tileset_id, autotile_id, tile_id, z)# autotile_id - Autotile index on the tileset, from 1 to 7# tile_id - Subtile ID, from 0 to 47# tileset_id - Tileset ID on the Database (current tileset when non-defined)# z - Tile priority (when non-defined uses default priority on the tileset)# Example: $game_map.set_sprite_autotile(4, 10, 3, 1, 24)# Note: You can also define a tag for this sprite# Example: $game_map.set_sprite_autotile(4, 10, 3, 1, 24, :water)#------------------------------------------------------------------------------# 3) Change an autotile on the map for an EMSTA autotile sprite# (it will use the tile_id and Z of the reference autotile)# $game_map.change_autotile_sprite(x, y, layer, autotile_id)# $game_map.change_autotile_sprite(x, y, layer, tileset_id, autotile_id)# layer - Map layer, from 0 to 2# You can also define two extra arguments after the autotile_id:# clear_tile_id - ID of the tile used to erase the reference autotile# clear - Boolean defining if the reference autotile should be erased# By default their values are 0 and true respectively.# tag - Symbol used to categorize tiles, by default nil#------------------------------------------------------------------------------# 4) Change an autotile for an EMSTA sprite along the whole layer# $game_map.change_autotile_layer(autotile, layer, autotile_id)# $game_map.change_autotile_layer(autotile, layer, tileset_id, autotile_id)# autotile - ID of the reference autotile, from 1 to 7# It works exactly like in the previous case but along an entire layer#==============================================================================# FAQ## - How do I get an EMSTA sprite previously inserted?## Script call for a Tile:# $game_map.sprite_tiles# Script call for an Autotile:# $game_map.sprite_autotiles## - How do I get it if I don't know its ID but I know coordinate and tile ID?# This example was made with a Tile. Change X, Y and TILE_ID## tiles = $game_map.sprite_tiles.values# tile = tiles.select do |sprite|# sprite == X# sprite == Y# sprite == TILE_ID# end## If tile is nil that means there's no sprite with those parameters## - Once I get the tile how do I get its ID?# id = $game_map.sprite_tiles.key(tile)## - How do I get all the sprites that share a tag?# tiles = $game_map.sprite_tiles.values# tiles = tiles.select do |sprite|# sprite[-1] == TAG# end## - What incompatibilities does this script have?# It should be compatible with practically everything#==============================================================================#==============================================================================# ** EronAutotileCache#==============================================================================module EronAutotileCache@@hash = {}module_functiondef hash @@hashendend#==============================================================================# ** Hash#==============================================================================class Hashdef key(value) for k in self.keys return k if self == value end return nilendend#==============================================================================# ** Game_Map#==============================================================================class Game_Map#--------------------------------------------------------------------------attr_accessor :sprite_tiles, :sprite_autotiles#--------------------------------------------------------------------------# * Setup#--------------------------------------------------------------------------alias sprite_tile_setup setup unless $@def setup(*args) sprite_tile_setup(*args) @sprite_tiles = {} @sprite_autotiles = {}end#--------------------------------------------------------------------------# * Get the next non-used index for a Tile or Autotile sprite#--------------------------------------------------------------------------def get_next_sprite_id(hash) return 1 if hash.size == 0 for i in 1..(hash.size + 1) return i if hash.nil? endend#--------------------------------------------------------------------------# * Show a Tile sprite on the map#--------------------------------------------------------------------------def set_sprite_tile(x, y, *args) tag = args.pop if args[-1].is_a?(Symbol) || args[-1].nil? case args.size when 1 # tile_id tileset_id = @map.tileset_id tile_id = args z = nil else # tileset_id, tile_id[, z] tileset_id = args tile_id = args z = args end id = get_next_sprite_id(@sprite_tiles) if z == nil tileset = $data_tilesets z = tileset.priorities end return if @sprite_tiles.values.include?() @sprite_tiles = return trueend#--------------------------------------------------------------------------# * Show an Auotitle sprite on the map#--------------------------------------------------------------------------def set_sprite_autotile(x, y, *args) tag = args.pop if args[-1].is_a?(Symbol) || args[-1].nil? case args.size when 2 # autotile_id, tile_id tileset_id = @map.tileset_id autotile_id = args tile_id = args else # tileset_id, autotile_id, tile_id[, z] tileset_id = args autotile_id = args tile_id = args z = args end id = get_next_sprite_id(@sprite_autotiles) if z == nil tileset = $data_tilesets z = tileset.priorities end ary = @sprite_autotiles.values return if ary.include?() @sprite_autotiles = return trueend#--------------------------------------------------------------------------# * Change an autotile to an EMSTA sprite on a specific coordinate#--------------------------------------------------------------------------def change_autotile_sprite(x, y, layer, *args) tag = args.pop if args[-1].is_a?(Symbol) || args[-1].nil? current_autotile = self.data return if current_autotile == 0 or current_autotile >= 384 clear = true clear_tile = 0 if args[-1].is_a?(TrueClass) or args[-1].is_a?(FalseClass) clear = args.pop clear_tile = args.pop end case args.size when 1 # autotile_id tileset_id = @map.tileset_id autotile_id = args else # tileset_id, autotile_id tileset_id = args autotile_id = args end tile_id = current_autotile % 48 z = $data_tilesets.priorities set_sprite_autotile(x, y, tileset_id, autotile_id, tile_id, z, tag) self.data = clear_tile if clearend#--------------------------------------------------------------------------# * Change an autotile to an EMSTA sprite along a map layer#--------------------------------------------------------------------------def change_autotile_layer(autotile, layer, *args) for iy in 0...self.height for ix in 0...self.width current = (self.data.to_f / 48).floor if current == autotile change_autotile_sprite(ix, iy, layer, *args) end end endendend#==============================================================================# ** Sprite_Tile#==============================================================================class Sprite_Tile < RPG::Sprite#--------------------------------------------------------------------------attr_accessor :real_x, :real_y, :real_z#--------------------------------------------------------------------------# * Update#--------------------------------------------------------------------------def update super self.x = (@real_x - $game_map.display_x + 3) / 4 + 16 self.y = (@real_y - $game_map.display_y + 3) / 4 + 32 self.z = @real_z + (@real_y - $game_map.display_y + 3) / 4 + 32endend#==============================================================================# ** Sprite_Autotile#==============================================================================class Sprite_Autotile < Sprite_Tile#--------------------------------------------------------------------------attr_accessor :complete_bitmap, :frame, :frames#--------------------------------------------------------------------------# * Update#--------------------------------------------------------------------------def update super if @frames > 1 && @current_frame != @frame @current_frame = @frame refresh_bitmap endend#--------------------------------------------------------------------------# * Refresh Bitmap#--------------------------------------------------------------------------def refresh_bitmap self.bitmap = Bitmap.new(32, 32) self.bitmap.blt(0, 0, @complete_bitmap, Rect.new(@frame * 32, 0, 32, 32))endend#==============================================================================# ** Spriteset_Map#==============================================================================class Spriteset_Map#--------------------------------------------------------------------------# * Initialize#--------------------------------------------------------------------------alias sprite_tile_ini initialize unless $@def initialize @sprite_tiles = [] @sprite_autotiles = [] @sprite_tile_copy = {} @sprite_autotile_copy = {} sprite_tile_iniend#--------------------------------------------------------------------------# * Dispose#--------------------------------------------------------------------------alias sprite_tile_dis dispose unless $@def dispose sprite_tile_dis @sprite_tiles.each {|sprite| sprite.dispose} @sprite_autotiles.each {|sprite| sprite.dispose}end#--------------------------------------------------------------------------# * Refresh Sprite Tiles#--------------------------------------------------------------------------def refresh_sprite_tiles for sprite in @sprite_tiles sprite.dispose end @sprite_tiles.clear for i in $game_map.sprite_tiles.keys tile = $game_map.sprite_tiles sprite = Sprite_Tile.new(@viewport1) sprite.real_x = tile * 128 sprite.real_y = tile * 128 sprite.ox = 16 sprite.oy = 32 tileset = $data_tilesets] sprite.bitmap = RPG::Cache.tile(tileset.tileset_name, tile, 0) sprite.real_z = tile * 32 @sprite_tiles.push(sprite) endend#--------------------------------------------------------------------------DECONSTRUCT_AUTOTILE_PARTS = #--------------------------------------------------------------------------# * Refresh Sprite Autotiles#--------------------------------------------------------------------------def refresh_sprite_autotiles for sprite in @sprite_autotiles sprite.dispose end @sprite_autotiles.clear for i in $game_map.sprite_autotiles.keys autotile = $game_map.sprite_autotiles sprite = Sprite_Autotile.new(@viewport1) sprite.real_x = autotile * 128 sprite.real_y = autotile * 128 sprite.ox = 16 sprite.oy = 32 sprite.frame = 0 tileset = $data_tilesets] autotile_name = tileset.autotile_names - 1] bitmap = RPG::Cache.autotile(autotile_name) case bitmap.height when 32 sprite.complete_bitmap = bitmap sprite.frames = bitmap.width / 32 when 128 frames = .max if EronAutotileCache.hash.include?(autotile_name) result = EronAutotileCache.hash else result = Bitmap.new(256, 192 * frames) deconstruct_autotile(bitmap, result, frames) EronAutotileCache.hash = result end bitmap = Bitmap.new(32 * frames, 32) for f in 0...frames ix = (autotile % 8) * 32 iy = ((autotile.to_f / 8).floor) * 32 bitmap.blt(f * 32, 0, result, Rect.new(ix, iy + 192 * f, 32, 32)) end sprite.complete_bitmap = bitmap sprite.frames = frames end sprite.bitmap = sprite.complete_bitmap if sprite.frames == 1 sprite.real_z = autotile * 32 @sprite_autotiles.push(sprite) endend#--------------------------------------------------------------------------# * Deconstruct Autotile#--------------------------------------------------------------------------def deconstruct_autotile(image, result, frames) t = DECONSTRUCT_AUTOTILE_PARTS for f in 0...frames fx = 96 * f fy = 192 * f bitmaps = for iy in 0...8 for ix in 0...6 bitmap = Bitmap.new(16, 16) bitmap.blt(0, 0, image, Rect.new(fx + 16 * ix, 16 * iy, 16, 16)) bitmaps << bitmap end end for iy in 0...12 for ix in 0...16 index = ix + iy * 16 bitmap = bitmaps] result.blt(ix * 16, fy + iy * 16, bitmap, bitmap.rect) end end end return resultend#--------------------------------------------------------------------------# * Update#--------------------------------------------------------------------------alias sprite_tile_upd update unless $@def update if @sprite_tile_copy != $game_map.sprite_tiles @sprite_tile_copy = $game_map.sprite_tiles.clone refresh_sprite_tiles end if @sprite_autotile_copy != $game_map.sprite_autotiles @sprite_autotile_copy = $game_map.sprite_autotiles.clone refresh_sprite_autotiles end @autotile_frame = 0 if @autotile_frame.nil? @autotile_frame += 1 if @autotile_frame % 16 == 0 @sprite_autotiles.each do |sprite| sprite.frame = (@autotile_frame / 16) % sprite.frames end end for sprite in @sprite_tiles + @sprite_autotiles sprite.update end sprite_tile_updendend
本贴来自国际rpgmaker官方论坛作者:Wecoc处,因国际论坛即将永久关站,为了存档多年珍贵资料,署名转载到本论坛存档,由于官方帖子为英文原帖,需要中文翻译请点击论坛顶部切换语言为中文就可以将帖子翻译成中文浏览,方便大家随时查看,原文地址:https://forums.rpgmakerweb.com/threads/extended-map-sprite-tiles-autotiles-emsta.138583/
页:
[1]