DoubleX RMVXA Pixel Movement
Version: v1.01a
Introduction
Lets users set the smallest number of pixel covered per move command
Prerequisites
* Little RGSS3 scripting proficiency to fully utilize this script
Script
"script"
Code:
#==============================================================================|
# ** 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. http://pastebin.com/RPF8dDDR |
# Mentioned Patreon Supporters: |
# https://www.patreon.com/posts/71738797 |
#------------------------------------------------------------------------------|
# * 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
#------------------------------------------------------------------------------|
#==============================================================================|
Instructions
Open the script editor and put this script into an open slot between Materials and Main. Save to take effect.
FAQ
None so far
Credits and Thanks
None
Terms and Conditions
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
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