#==============================================================================| # ** Script Info | #------------------------------------------------------------------------------| # * Script Name | # DoubleX RMVXA Pixel Movement | #------------------------------------------------------------------------------| # * Functions | # Lets users set the smallest number of pixel covered per move command | #------------------------------------------------------------------------------| # * Terms Of Use | # You shall keep this script's Script Info part's contents intact | # You shalln't claim that this script is written by anyone other than | # DoubleX or his aliases | # None of the above applies to DoubleX or his aliases | #------------------------------------------------------------------------------| # * Prerequisites | # Abilities: | # 1. Little RGSS3 scripting proficiency to fully utilize this script | #------------------------------------------------------------------------------| # * Instructions | # 1. Open the script editor and put this script into an open slot between | # Materials and Main, save to take effect. | #------------------------------------------------------------------------------| # * Links | # Script Usage 101: | # 1. forums.rpgmakerweb.com/index.php?/topic/32752-rmvxa-script-usage-101/ | # 2. rpgmakervxace.net/topic/27475-rmvxa-script-usage-101/ | # This script: | # 1. [url]http://pastebin.com/RPF8dDDR[/url] | # Mentioned Patreon Supporters: | # [url]https://www.patreon.com/posts/71738797[/url] | #------------------------------------------------------------------------------| # * Authors | # DoubleX | #------------------------------------------------------------------------------| # * Changelog | # v1.01a(GMT 1600 14-8-2015): | # 1. Lets users set a key/script call to set a char to have integer coors | # 2. Fixed event triggered by player touch not triggering bug | # 3. Fixed encounters simply not working bug | # 4. Fixed the bullet through paper problem when moving diagonally | # 5. Found the origin of the starting map not passable bug with either | # vehicle's starting positions being uninitialized by users | # 6. Increased this script's correctness, effectiveness and efficiency | # 7. Little RGSS3 scripting proficiency's needed to fully utilize the script| # v1.00a(GMT 1600 12-8-2015): | # 1. 1st version of this script finished | #==============================================================================| #==============================================================================| # ** (v1.01a+)Script Call Info | #------------------------------------------------------------------------------| # * Character manipulations | # 1. pixel_movement_nearest_tile | # - Sets the x and y psotions of the char to be their nearest integers | #==============================================================================| ($doublex_rmvxa ||= {})[:Pixel_Movement] = "v1.01a" #==============================================================================| # ** Script Configurations | # You only need to edit this part as it's about what this script does | #------------------------------------------------------------------------------| module DoubleX_RMVXA module Pixel_Movement # Sets the global minimum pixel covered per move command as MIN_PIXEL_MOVE # It must return a natural number # If an object moves faster than MIN_PIXEL_MOVE per frame, that object's # original speed will be used instead # Errors might come if MIN_PIXEL_MOVE is increased during the game execution # If MIN_PIXEL_MOVE_VAR_ID is a natural number, the value of variable with # id MIN_PIXEL_MOVE_VAR_ID will be used instead of using MIN_PIXEL_MOVE MIN_PIXEL_MOVE = 1 MIN_PIXEL_MOVE_VAR_ID = 0 # (v1.01a+)Sets the key to set the player's x and y positions as their # nearest integers as NEAREST_TILE_KEY # It must return a symbol and should return a keymap binding symbol # Using a custom keymap binding script might help setting NEAREST_TILE_KEY # If NEAREST_TILE_KEY_VAR_ID is a natural number, the value of variable with # id NEAREST_TILE_KEY_VAR_ID will be used instead of using NEAREST_TILE_KEY NEAREST_TILE_KEY = :X NEAREST_TILE_KEY_VAR_ID = 0 #==============================================================================| # ** Script Implementations | # You need not edit this part as it's about how this script works | #------------------------------------------------------------------------------| # * Script Support Info: | # 1. Prerequisites | # - Basic knowledge of pixel movement | # - Some RGSS3 scripting proficiency to fully comprehend this script | # 2. Method documentation | # - The 1st part describes why this method's rewritten/aliased for | # rewritten/aliased methods or what the method does for new methods | # - The 2nd part describes what the arguments of the method are | # - The 3rd part informs which version rewritten, aliased or created this| # method | # - The 4th part informs whether the method's rewritten or new | # - The 5th part describes how this method works for new methods only, | # and describes the parts added, removed or rewritten for rewritten or | # aliased methods only | # Example: | # #--------------------------------------------------------------------------| | # # Why rewrite/alias/What this method does | | # #--------------------------------------------------------------------------| | # # *argv: What these variables are | # # &argb: What this block is | # def def_name(*argv, &argb) # Version X+; Rewrite/New | # # Added/Removed/Rewritten to do something/How this method works | # def_name_code | # # | # end # def_name | #------------------------------------------------------------------------------| #--------------------------------------------------------------------------| # Helper methods simplifying the uses of the configuration value | #--------------------------------------------------------------------------| def self.min_pixel_move return MIN_PIXEL_MOVE if MIN_PIXEL_MOVE_VAR_ID <= 0 $game_variables[MIN_PIXEL_MOVE_VAR_ID] end # min_pixel_move def self.nearest_tile_key # v1.01a+ return NEAREST_TILE_KEY if NEAREST_TILE_KEY_VAR_ID <= 0 $game_variables[NEAREST_TILE_KEY_VAR_ID] end # nearest_tile_key end # Pixel_Movement end # DoubleX_RMVXA class Game_Map # Edit def x_with_direction(x, d) # Rewrite # Rewritten return x + DoubleX_RMVXA::Pixel_Movement.min_pixel_move / 32.0 if d == 6 return x - DoubleX_RMVXA::Pixel_Movement.min_pixel_move / 32.0 if d == 4 x # end # x_with_direction def y_with_direction(y, d) # Rewrite # Rewritten return y + DoubleX_RMVXA::Pixel_Movement.min_pixel_move / 32.0 if d == 2 return y - DoubleX_RMVXA::Pixel_Movement.min_pixel_move / 32.0 if d == 8 y # end # y_with_direction def round_x_with_direction(x, d) # Rewrite round_x(x_with_direction(x, d)) # Rewritten end # round_x_with_direction def round_y_with_direction(y, d) # Rewrite round_y(y_with_direction(y, d)) # Rewritten end # round_y_with_direction def valid?(x, y) # Rewrite x >= 0 && x <= width - 1 && y >= 0 && y <= height - 1 # Rewritten end # valid? #----------------------------------------------------------------------------| # Uses a unit bounding square to detect overlapped tiles instead | #----------------------------------------------------------------------------| alias layered_tiles_flag_pixel_movement? layered_tiles_flag? def layered_tiles_flag?(x, y, bit, &argb) # Rewritten (x == (x = x.to_i) ? [x] : [x, x + 1]).each { |xi| (y == (y = y.to_i) ? [y] : [y, y + 1]).each { |yi| return true if layered_tiles_flag_pixel_movement?(x, y, bit, &argb) } } false # end # layered_tiles_flag? end # Game_Map class Game_CharacterBase # Edit #----------------------------------------------------------------------------| # New private instance variables | #----------------------------------------------------------------------------| # @pixel_movement_diff: The movement distance of the current frame # @pixel_movement_dist: The accumulated movement distance #----------------------------------------------------------------------------| # Uses a unit bounding square to detect character collisions instead | #----------------------------------------------------------------------------| def pos?(x, y) # Rewrite # Rewritten to regard just touching as edges as colliding x + 1 >= @x && x <= @x + 1 && y + 1 >= @y && y <= @y + 1 # end # pos? #----------------------------------------------------------------------------| # Uses a unit bounding square to detect character collisions instead | #----------------------------------------------------------------------------| def pos_nt?(x, y) # Rewrite # Rewritten to regard just touching the edges as not colliding !@through && x + 1 > @x && x < @x + 1 && y + 1 > @y && y < @y + 1 # end # pos_nt? #----------------------------------------------------------------------------| # Uses a unit bounding square to detect character collisions instead | #----------------------------------------------------------------------------| def passable?(x, y, d) # Rewrite x2 = $game_map.round_x_with_direction(x, d) y2 = $game_map.round_y_with_direction(y, d) # Rewritten to check if all overlapped tiles are valid and passable as well xs = x2 == (x2i = x2.to_i) ? [x2i] : [x2i, x2i + 1] ys = y2 == (y2i = y2.to_i) ? [y2i] : [y2i, y2i + 1] xs.each { |xi| ys.each { |yi| return false unless $game_map.valid?(xi, yi) } } return true if @through || debug_through? (x == (x = x.to_i) ? [x] : [x, x + 1]).each { |xi| (y == (y = y.to_i) ? [y] : [y, y + 1]).each { |yi| return false unless map_passable?(xi, yi, d) } } rd = reverse_dir(d) xs.each { |xi| ys.each { |yi| return false unless map_passable?(xi, yi, rd) } } # !collide_with_characters?(x2, y2) end # passable? #----------------------------------------------------------------------------| # Prevents an event from being falsely considered as colliding with itself | #----------------------------------------------------------------------------| def collide_with_events?(x, y) # Rewrite return true if is_a?(Game_Event) ($game_map.events_xy_nt(x, y) - [self]).any? { |e| e.normal_priority? } end # collide_with_events? def move_straight(d, turn_ok = true) # Rewrite @move_succeed = passable?(@x, @y, d) if @move_succeed set_direction(d) @x = $game_map.round_x_with_direction(@x, d) @y = $game_map.round_y_with_direction(@y, d) @real_x = $game_map.x_with_direction(@x, reverse_dir(d)) @real_y = $game_map.y_with_direction(@y, reverse_dir(d)) # Rewritten to prevent character from being locked into impassable places set_pixel_movement_min last_x = @real_x last_y = @real_y pixel_movement_straight(last_x, last_y, d) unless passable?(@x, @y, d) @pixel_movement_diff = ((@x - last_x) ** 2 + (@y - last_y) ** 2) ** 0.5 @pixel_movement_dist += @pixel_movement_diff while @pixel_movement_dist >= 1 increase_steps @pixel_movement_dist -= 1 end # elsif turn_ok set_direction(d) check_event_trigger_touch_front end end # move_straight def move_diagonal(horz, vert) # Rewrite @move_succeed = diagonal_passable?(@x, @y, horz, vert) if @move_succeed @x = $game_map.round_x_with_direction(@x, horz) @y = $game_map.round_y_with_direction(@y, vert) @real_x = $game_map.x_with_direction(@x, reverse_dir(horz)) @real_y = $game_map.y_with_direction(@y, reverse_dir(vert)) # Rewritten to prevent character from being locked into impassable places set_pixel_movement_min set_pixel_movement_diagonal(horz, vert) @pixel_movement_diff = ((@x - @real_x) ** 2 + (@y - @real_y) ** 2) ** 0.5 @pixel_movement_dist += @pixel_movement_diff while @pixel_movement_dist >= 1 increase_steps @pixel_movement_dist -= 1 end # increase_steps end set_direction(horz) if @direction == reverse_dir(horz) set_direction(vert) if @direction == reverse_dir(vert) end # move_diagonal alias init_private_members_pixel_movement init_private_members def init_private_members(*argv, &argb) init_private_members_pixel_movement(*argv, &argb) @pixel_movement_diff = @pixel_movement_dist = 0 # Added end # init_private_members #----------------------------------------------------------------------------| # Checks if events collide with the players as well | #----------------------------------------------------------------------------| alias collide_with_characters_pixel_movement? collide_with_characters? def collide_with_characters?(x, y) return true if $game_player != self && $game_player.pos_nt?(x, y) # Added collide_with_characters_pixel_movement?(x, y) end # collide_with_characters? #----------------------------------------------------------------------------| # Sets the number of pixel covered per frame to be at least that of the char| #----------------------------------------------------------------------------| def set_pixel_movement_min # New dpf = distance_per_frame if @x > @real_x @x = [@real_x + dpf, $game_map.width - 1].min if @x < @real_x + dpf elsif @x < @real_x @x = [@real_x - dpf, 0].max if @x > @real_x - dpf end if @y > @real_y @y = [@real_y + dpf, $game_map.height - 1].min if @y < @real_y + dpf elsif @y < @real_y @y = [@real_y - dpf, 0].max if @y > @real_y - dpf end end # set_pixel_movement_min #----------------------------------------------------------------------------| # Prevents the character from being locked into an impassable place | #----------------------------------------------------------------------------| # last_x : The real x coordinate right before moving straight # last_y : The real y coordinate right before moving straight # d: The movement direction def pixel_movement_straight(last_x, last_y, d) # New mpm = DoubleX_RMVXA::Pixel_Movement.min_pixel_move / 32.0 # Uses a binary search to find the point making the char to become passable while (@x - last_x).abs > mpm || (@y - last_y).abs > mpm @real_x = (@x + last_x) / 2 @real_y = (@y + last_y) / 2 if passable?(@real_x, @real_y, d) last_x = @real_x next last_y = @real_y end @x = @real_x @y = @real_y end # @real_x = @x @real_y = @y end # pixel_movement_straight #----------------------------------------------------------------------------| # Fixes the bullet through paper problem when moving diagonally | #----------------------------------------------------------------------------| # horz: The horizontal direction component # vert: The vertical direction component def set_pixel_movement_diagonal(horz, vert) # New # Sets the maximum number of pixels covered that are still passable mpm = DoubleX_RMVXA::Pixel_Movement.min_pixel_move / 32.0 xi = @real_x yi = @real_y xs = (@x - @real_x) / (@x - @real_x).abs ys = (@y - @real_y) / (@y - @real_y).abs while xi * xs <= @x * xs && yi * ys <= @y * ys && diagonal_passable?(xi, yi, horz, vert) xi += mpm * xs yi += mpm * ys end @x = xi @y = yi # end # set_pixel_movement_diagonal #----------------------------------------------------------------------------| # Tries to set the real x and y positions to be their nearest integers | #----------------------------------------------------------------------------| def pixel_movement_nearest_tile # v1.01a+; New test_x = ((@x * 2).to_i + 1) / 2 test_y = ((@y * 2).to_i + 1) / 2 [2, 4, 6, 8].each { |d| return unless passable?(test_x, test_y, d) } @x = test_x @y = test_y end # pixel_movement_nearest_tile end # Game_CharacterBase class Game_Player < Game_Character # v1.01a+; Edit def update # Rewrite last_real_x = @real_x last_real_y = @real_y last_moving = moving? move_by_input super update_scroll(last_real_x, last_real_y) update_vehicle # Rewritten unless $game_map.interpreter.running? moving? ? pixel_movement_update : update_nonmoving(last_moving) end # @followers.update # Added return unless Input.trigger?(DoubleX_RMVXA::Pixel_Movement.nearest_tile_key) pixel_movement_nearest_tile # end # update # last_moving: The moving flag at the last frame def update_nonmoving(last_moving) # Rewrite # Rewritten return if last_moving && check_touch_event movable? && Input.trigger?(:C) && (get_on_off_vehicle || check_action_event) # end # update_nonmoving alias move_by_input_pixel_movement move_by_input def move_by_input # Added @pixel_movement_diff = ((@x - @real_x) ** 2 + (@y - @real_y) ** 2) ** 0.5 # move_by_input_pixel_movement end # move_by_input alias encounter_progress_value_pixel_movement encounter_progress_value def encounter_progress_value encounter_progress_value_pixel_movement * @pixel_movement_diff # Rewritten end # encounter_progress_value def moving? # New @pixel_movement_diff != 0 end # moving? def pixel_movement_update # New $game_party.on_player_walk check_touch_event || update_encounter end # pixel_movement_update end # Game_Player #------------------------------------------------------------------------------| #==============================================================================|