Charas-Project
Game Creation => Requests => RPG Maker Programming => Topic started by: GaryCXJk on December 30, 2012, 01:32:29 AM
-
Okay, so, lately I've been working with RPG Maker VX Ace. In fact, I started working with it the moment I bought it, during the holiday sale on Steam. So far it's been great, but recently I've started some project thanks to my brother. I can never say no to any of his requests.
Basically it's a free movement script, which I conveniently call Free Movement. You basically can move off the grid with this script.
It's very WIP, as I wasn't able to test everything.
[noae][noae][noae][noae][noae][noae][noae]module CXJ
module FREE_MOVEMENT
ENABLE_DIAGONAL = true # Enables diagonal movement.
DEFAULT_COLLISION = [8, 12, 16, 20]
DEFAULT_INTERACTION = {
2 => [4, 0, 24, 24],
4 => [16, 10, 24, 24],
6 => [-8, 10, 24, 24],
8 => [4, 20, 24, 24],
}
BOAT_COLLISION = [4, 4, 24, 24]
AIRSHIP_COLLISION = [4, 8, 24, 24]
PIXELS_PER_STEP = 4
FOLLOWERS_DISTANCE = 16
FOLLOWERS_DISTANCE_MARGIN = 4
JUMP_SPEED = 0.5
end
end
#==============================================================================
# ** Game_Map
#------------------------------------------------------------------------------
# This class handles maps. It includes scrolling and passage determination
# functions. The instance of this class is referenced by $game_map.
#==============================================================================
class Game_Map
#--------------------------------------------------------------------------
# * New: Determine Valid Coordinates
#--------------------------------------------------------------------------
def valid_rect?(x, y, rect)
x2 = x + (rect.x / 32.0)
y2 = y + (rect.y / 32.0)
x3 = x2 + (rect.width / 32.0)
y3 = y2 + (rect.height / 32.0)
round_x(x2) >= 0 && round_x(x3) < width && round_y(y2) >= 0 && round_y(y3) < height
end
#--------------------------------------------------------------------------
# * Override: Check Passage
# bit: Inhibit passage check bit
#--------------------------------------------------------------------------
def check_passage(x, y, bit)
x = round_x(x)
y = round_y(y)
all_tiles(x, y).each do |tile_id|
flag = tileset.flags[tile_id]
next if flag & 0x10 != 0 # [☆]: No effect on passage
return true if flag & bit == 0 # [○] : Passable
return false if flag & bit == bit # [×] : Impassable
end
return false # Impassable
end
#--------------------------------------------------------------------------
# * New: Determine Passability of Normal Character
# d: direction (2,4,6,8)
# Determines whether the tile at the specified coordinates is passable
# in the specified direction.
#--------------------------------------------------------------------------
def passable_rect?(x, y, d, rect)
x2 = x + (rect.x / 32.0)
y2 = y + (rect.y / 32.0)
x3 = x2 + (rect.width / 32.0)
y3 = y2 + (rect.height / 32.0)
return false unless check_passage(x2, y2, (1 << (d / 2 - 1)) & 0x0f)
return false unless check_passage(x2, y3, (1 << (d / 2 - 1)) & 0x0f)
return false unless check_passage(x3, y2, (1 << (d / 2 - 1)) & 0x0f)
return check_passage(x3, y3, (1 << (d / 2 - 1)) & 0x0f)
end
#--------------------------------------------------------------------------
# * Determine if Passable by Boat
#--------------------------------------------------------------------------
def boat_passable_rect?(x, y, rect)
x2 = x + (rect.x / 32.0)
y2 = y + (rect.y / 32.0)
x3 = x2 + (rect.width / 32.0)
y3 = y2 + (rect.height / 32.0)
return false unless check_passage(x2, y2, 0x0200)
return false unless check_passage(x2, y3, 0x0200)
return false unless check_passage(x3, y2, 0x0200)
return check_passage(x3, y3, 0x0200)
end
#--------------------------------------------------------------------------
# * Determine if Passable by Ship
#--------------------------------------------------------------------------
def ship_passable_rect?(x, y, rect)
x2 = x + (rect.x / 32.0)
y2 = y + (rect.y / 32.0)
x3 = x2 + (rect.width / 32.0)
y3 = y2 + (rect.height / 32.0)
return false unless check_passage(x2, y2, 0x0400)
return false unless check_passage(x2, y3, 0x0400)
return false unless check_passage(x3, y2, 0x0400)
return check_passage(x3, y3, 0x0400)
end
#--------------------------------------------------------------------------
# * Determine if Airship can Land
#--------------------------------------------------------------------------
def airship_land_ok_rect?(x, y, rect)
x2 = x + (rect.x / 32.0)
y2 = y + (rect.y / 32.0)
x3 = x2 + (rect.width / 32.0)
y3 = y2 + (rect.height / 32.0)
return false unless check_passage(x2, y2, 0x0800) && check_passage(x2, y2, 0x0f)
return false unless check_passage(x2, y3, 0x0800) && check_passage(x2, y3, 0x0f)
return false unless check_passage(x3, y2, 0x0800) && check_passage(x3, y2, 0x0f)
return check_passage(x3, y3, 0x0800) && check_passage(x3, y3, 0x0f)
end
#--------------------------------------------------------------------------
# * Get Array of Events at Designated Coordinates
#--------------------------------------------------------------------------
def events_xy_rect(x, y, rect)
@events.values.select {|event| event.pos_rect?(x, y, rect) }
end
#--------------------------------------------------------------------------
# * Get Array of Events at Designated Coordinates (Except Pass-Through)
#--------------------------------------------------------------------------
def events_xy_rect_nt(x, y, rect)
@events.values.select {|event| event.pos_rect_nt?(x, y, rect) }
end
#--------------------------------------------------------------------------
# * Get Array of Tile-Handling Events at Designated Coordinates
# (Except Pass-Through)
#--------------------------------------------------------------------------
def tile_events_xy_rect(x, y, rect)
@tile_events.select {|event| event.pos_rect_nt?(x, y, rect) }
end
end
#==============================================================================
# ** Game_CharacterBase
#------------------------------------------------------------------------------
# This base class handles characters. It retains basic information, such as
# coordinates and graphics, shared by all characters.
#==============================================================================
class Game_CharacterBase
attr_accessor :move_poll
#--------------------------------------------------------------------------
# * Alias: Object Initialization
#--------------------------------------------------------------------------
alias game_characterbase_initialize_cxj_fm initialize
def initialize
game_characterbase_initialize_cxj_fm
@move_poll = []
end
#--------------------------------------------------------------------------
# * Alias: Frame Update
#
# Added processing of movement being polled.
#--------------------------------------------------------------------------
alias game_characterbase_update_cxj_fm update
def update
interpret_move unless moving?
game_characterbase_update_cxj_fm
end
#--------------------------------------------------------------------------
# * New: Movement Interpreting
# Interprets the polled movement.
#--------------------------------------------------------------------------
def interpret_move(step_left = distance_per_frame)
if @move_poll.size > 0
current_move = @move_poll.shift()
d = current_move[0]
horz = (d - 1) % 3 - 1
vert = 1 - ((d - 1) / 3)
turn_ok = current_move[1]
set_direction(d)
processed = false
if (d % 2 == 0 && passable?(@x, @y, d)) || (d % 2 != 0 && diagonal_passable?(@x, @y, horz, vert))
process_move(horz, vert)
processed = true
elsif d % 2 != 0 && !diagonal_passable?(@x, @y, horz, vert)
if passable?(@x, @y, horz + 5)
set_direction(horz + 5)
process_move(horz, 0)
processed = true
end
if passable?(@x, @y, 5 - vert * 3)
set_direction(5 - vert * 3)
process_move(0, vert)
processed = true
end
end
if(processed)
pixelstep = CXJ::FREE_MOVEMENT::PIXELS_PER_STEP / 32.0
if(step_left > pixelstep && !@move_poll.empty?)
interpret_move(step_left - pixelstep)
elsif(jumping? && !@move_poll.empty?)
interpret_move(0)
end
else
@move_poll.clear
end
current_move
end
end
def process_move(horz, vert)
pixelstep = CXJ::FREE_MOVEMENT::PIXELS_PER_STEP / 32.0
@x = @x + horz * pixelstep
@y = @y + vert * pixelstep
if(!jumping?)
@x = $game_map.round_x(@x)
@y = $game_map.round_y(@y)
@real_x = @x - horz * pixelstep
@real_y = @y - vert * pixelstep
increase_steps
end
end
#--------------------------------------------------------------------------
# * New: Collision Rectangle
# Gets the collision rectangle.
#--------------------------------------------------------------------------
def collision_rect
collision = CXJ::FREE_MOVEMENT::DEFAULT_COLLISION
return Rect.new(collision[0], collision[1], collision[2] - 1, collision[3] - 1)
end
#--------------------------------------------------------------------------
# * Override: Determine if Passable
# d : Direction (2,4,6,8)
#--------------------------------------------------------------------------
def passable?(x, y, d)
horz = (d - 1) % 3 - 1
vert = 1 - ((d - 1) / 3)
pixelstep = CXJ::FREE_MOVEMENT::PIXELS_PER_STEP / 32.0
x2 = $game_map.round_x(x + horz * pixelstep)
y2 = $game_map.round_y(y + vert * pixelstep)
return false unless $game_map.valid_rect?(x2, y2, collision_rect)
return true if @through || debug_through?
return false unless map_passable_rect?(x, y, d, collision_rect)
return false unless map_passable_rect?(x2, y2, reverse_dir(d), collision_rect)
return false if collide_with_characters?(x2, y2)
return true
end
#--------------------------------------------------------------------------
# * Determine Diagonal Passability
# horz : Horizontal (4 or 6)
# vert : Vertical (2 or 8)
#--------------------------------------------------------------------------
def diagonal_passable?(x, y, horz, vert)
pixelstep = CXJ::FREE_MOVEMENT::PIXELS_PER_STEP / 32.0
x2 = $game_map.round_x(x + horz * pixelstep)
y2 = $game_map.round_y(y + vert * pixelstep)
d = (horz == 4 ? -1 : 1) + (vert == 2 ? -3 : 3) + 5
passable?(x, y, vert) && passable?(x, y, horz) && passable?(x, y, d) && passable?(x2, y2, vert) && passable?(x2, y2, horz) && passable?(x2, y2, d)
end
#--------------------------------------------------------------------------
# * Determine if Map is Passable
# d : Direction (2,4,6,8)
#--------------------------------------------------------------------------
def map_passable_rect?(x, y, d, rect)
$game_map.passable_rect?(x, y, d, rect)
end
#--------------------------------------------------------------------------
# * Override: Change Direction to Designated Direction
# d : Direction (2,4,6,8)
#
# Fix for diagonal movement.
#--------------------------------------------------------------------------
def set_direction(d)
if !@direction_fix && d != 0
@direction = d
if d % 2 != 0
@direction+= 1
@direction-= 2 if d > 5
@direction = 10 - direction if d > 2 && d < 8
end
end
@stop_count = 0
end
#--------------------------------------------------------------------------
# * Override: Move Straight
# d: Direction (2,4,6,8)
# turn_ok : Allows change of direction on the spot
#
# Polls the movement instead of processing them immediately.
#--------------------------------------------------------------------------
def move_straight(d, turn_ok = true)
pixelstep = CXJ::FREE_MOVEMENT::PIXELS_PER_STEP / 32.0
@move_poll+= [[d, turn_ok]] * (distance_per_frame / pixelstep).ceil
end
#--------------------------------------------------------------------------
# * Override: Move Diagonally
# horz: Horizontal (4 or 6)
# vert: Vertical (2 or 8)
#
# Polls the movement instead of processing them immediately.
#--------------------------------------------------------------------------
def move_diagonal(horz, vert)
pixelstep = CXJ::FREE_MOVEMENT::PIXELS_PER_STEP / 32.0
@move_poll+= [[vert + (horz > 5 ? 1 : -1), true]] * (distance_per_frame / pixelstep).ceil
end
#--------------------------------------------------------------------------
# * New: Determine Coordinate Match
#--------------------------------------------------------------------------
def pos_rect?(x, y, rect)
main_left = @x + collision_rect.x / 32.0
main_top = @y + collision_rect.y / 32.0
main_right = main_left + collision_rect.width / 32.0
main_bottom = main_top + collision_rect.height / 32.0
other_left = x + rect.x / 32.0
other_top = y + rect.y / 32.0
other_right = other_left + rect.width / 32.0
other_bottom = other_top + rect.height / 32.0
coltest = true
coltest = false if main_right < other_left
coltest = false if main_left > other_right
coltest = false if main_bottom < other_top
coltest = false if main_top > other_bottom
if coltest == false && ($game_map.loop_horizontal? || $game_map.loop_vertical?) && x <= $game_map.width && y <= $game_map.height
return true if $game_map.loop_horizontal? && pos_rect?(x + $game_map.width, y, rect)
return true if $game_map.loop_vertical? && pos_rect?(x, y + $game_map.height, rect)
end
return coltest
end
#--------------------------------------------------------------------------
# * New: Determine if Coordinates Match and Pass-Through Is Off (nt = No Through)
#--------------------------------------------------------------------------
def pos_rect_nt?(x, y, rect)
pos_rect?(x, y, rect) && !@through
end
#--------------------------------------------------------------------------
# * Detect Collision with Event
#--------------------------------------------------------------------------
def collide_with_events?(x, y)
$game_map.events_xy_rect_nt(x, y, collision_rect).any? do |event|
(event.normal_priority? || self.is_a?(Game_Event)) && event != self
end
end
#--------------------------------------------------------------------------
# * Override: Detect Collision with Vehicle
#--------------------------------------------------------------------------
def collide_with_vehicles?(x, y)
$game_map.boat.pos_rect_nt?(x, y, collision_rect) || $game_map.ship.pos_rect_nt?(x, y, collision_rect)
end
#--------------------------------------------------------------------------
# * Override: Update While Jumping
#--------------------------------------------------------------------------
def update_jump
@jump_count -= 1
diff_x = @real_x
@real_x = (@real_x * @jump_count + @x) / (@jump_count + 1.0)
@real_y = (@real_y * @jump_count + @y) / (@jump_count + 1.0)
update_bush_depth
if @jump_count == 0
@real_x = @x = $game_map.round_x(@x)
@real_y = @y = $game_map.round_y(@y)
end
end
#--------------------------------------------------------------------------
# * Override: Calculate Jump Height
#--------------------------------------------------------------------------
def jump_height
(@jump_peak * @jump_peak - (@jump_count * CXJ::FREE_MOVEMENT::JUMP_SPEED - @jump_peak).abs ** 2) / 2
end
end
#==============================================================================
# ** Game_Character
#------------------------------------------------------------------------------
# A character class with mainly movement route and other such processing
# added. It is used as a super class of Game_Player, Game_Follower,
# GameVehicle, and Game_Event.
#==============================================================================
class Game_Character < Game_CharacterBase
#--------------------------------------------------------------------------
# * Move at Random
#--------------------------------------------------------------------------
def move_random
@move_poll+= [[2 + rand(4) * 2, false]] * (32 / CXJ::FREE_MOVEMENT::PIXELS_PER_STEP)
end
#--------------------------------------------------------------------------
# * Move Toward Character
#--------------------------------------------------------------------------
def move_toward_character(character)
sx = distance_x_from(character.x)
sy = distance_y_from(character.y)
if sx.abs > sy.abs
@move_poll+= [[sx > 0 ? 4 : 6, true]]
@move_poll+= [[sy > 0 ? 8 : 2, true]] if !@move_succeed && sy != 0
elsif sy != 0
@move_poll+= [[sy > 0 ? 8 : 2, true]]
@move_poll+= [[sx > 0 ? 4 : 6, true]] if !@move_succeed && sx != 0
end
end
#--------------------------------------------------------------------------
# * Move Away from Character
#--------------------------------------------------------------------------
def move_away_from_character(character)
sx = distance_x_from(character.x)
sy = distance_y_from(character.y)
if sx.abs > sy.abs
move_straight(sx > 0 ? 6 : 4)
move_straight(sy > 0 ? 2 : 8) if !@move_succeed && sy != 0
elsif sy != 0
move_straight(sy > 0 ? 2 : 8)
move_straight(sx > 0 ? 6 : 4) if !@move_succeed && sx != 0
end
end
#--------------------------------------------------------------------------
# * Override: Jump
# x_plus : x-coordinate plus value
# y_plus : y-coordinate plus value
#--------------------------------------------------------------------------
def jump(x_plus, y_plus)
if x_plus.abs > y_plus.abs
set_direction(x_plus < 0 ? 4 : 6) if x_plus != 0
else
set_direction(y_plus < 0 ? 8 : 2) if y_plus != 0
end
distance = Math.sqrt(x_plus * x_plus + y_plus * y_plus).round
pollcount = distance * (32.0 / CXJ::FREE_MOVEMENT::PIXELS_PER_STEP).ceil
@move_poll+= [[(x_plus < 0 ? -1 : x_plus > 0 ? 1 : 0) + (y_plus < 0 ? 8 : y_plus > 0 ? 2 : 5), false]] * pollcount
@jump_peak = 10 + distance - @move_speed
@jump_count = @jump_peak / CXJ::FREE_MOVEMENT::JUMP_SPEED * 2
@stop_count = 0
straighten
end
end
#==============================================================================
# ** Game_Player
#------------------------------------------------------------------------------
# This class handles the player. It includes event starting determinants and
# map scrolling functions. The instance of this class is referenced by
# $game_player.
#==============================================================================
class Game_Player < Game_Character
#--------------------------------------------------------------------------
# * Object Initialization
#--------------------------------------------------------------------------
alias game_player_initialize_cxj_fm initialize
def initialize
@last_poll = []
game_player_initialize_cxj_fm
@custom_collision = []
@interaction = CXJ::FREE_MOVEMENT::DEFAULT_INTERACTION
if @note =~ /<collisionbox:[ ]*(\s*),[ ]*(\s*),[ ]*(\s*),[ ]*(\s*)>/i
@custom_collision = Rect.new($1, $2, $3 - 1, $4)
end
if @note =~ /<interaction (\s*):[ ]*(\s*),[ ]*(\s*),[ ]*(\s*),[ ]*(\s*)>/i && $1 > 0 && $1 < 10 && $1 % 2 == 0
@interaction[$1] = [$2, $3, $4, $5]
end
end
#--------------------------------------------------------------------------
# * New: Movement Interpreting
# Interprets the polled movement.
#--------------------------------------------------------------------------
def interpret_move(step_left = distance_per_frame)
current_move = super(step_left)
@last_poll.push(current_move) if !current_move.nil?
end
#--------------------------------------------------------------------------
# * New: Collision Rectangle
# Gets the collision rectangle.
#--------------------------------------------------------------------------
def collision_rect
return @custom_collision if @custom_collision.size > 0
return super
end
#--------------------------------------------------------------------------
# * New: Interaction Rectangle
# Gets the interaction rectangle.
#--------------------------------------------------------------------------
def interaction_rect
collision = @interaction[@direction]
return Rect.new(collision[0], collision[1], collision[2] - 1, collision[3] - 1)
end
#--------------------------------------------------------------------------
# * Override: Processing of Movement via Input from Directional Buttons
#
# Added diagonal movement.
#--------------------------------------------------------------------------
def move_by_input
return if !movable? || $game_map.interpreter.running?
if CXJ::FREE_MOVEMENT::ENABLE_DIAGONAL && Input.dir8 > 0 && Input.dir8 % 2 != 0
d = Input.dir8
horz = (d == 1 || d == 7 ? 4 : 6)
vert = (d == 1 || d == 3 ? 2 : 8)
move_diagonal(horz, vert)
elsif Input.dir4 > 0
move_straight(Input.dir4)
end
end
#--------------------------------------------------------------------------
# * Detect Collision (Including Followers)
#--------------------------------------------------------------------------
def collide_rect?(x, y, rect)
!@through && (pos_rect?(x, y, rect) || followers.collide_rect?(x, y, rect))
end
#--------------------------------------------------------------------------
# * Trigger Map Event
# triggers : Trigger array
# normal : Is priority set to [Same as Characters] ?
#--------------------------------------------------------------------------
def start_map_event(x, y, triggers, normal, rect = collision_rect)
return if $game_map.interpreter.running?
$game_map.events_xy_rect(x, y, rect).each do |event|
if event.trigger_in?(triggers) && event.normal_priority? == normal
event.start
end
end
end
#--------------------------------------------------------------------------
# * Determine if Front Event is Triggered
#--------------------------------------------------------------------------
def check_event_trigger_there(triggers)
x2 = $game_map.round_x_with_direction(@x, @direction)
y2 = $game_map.round_y_with_direction(@y, @direction)
start_map_event(x2, y2, triggers, true, interaction_rect)
return if $game_map.any_event_starting?
return unless $game_map.counter?(x2, y2)
x3 = $game_map.round_x_with_direction(x2, @direction)
y3 = $game_map.round_y_with_direction(y2, @direction)
start_map_event(x3, y3, triggers, true, interaction_rect)
end
#--------------------------------------------------------------------------
# * Board Vehicle
# Assumes that the player is not currently in a vehicle.
#--------------------------------------------------------------------------
def get_on_vehicle
front_x = $game_map.round_x_with_direction(@x, @direction)
front_y = $game_map.round_y_with_direction(@y, @direction)
@vehicle_type = :boat if $game_map.boat.pos_rect?(front_x, front_y, interaction_rect)
@vehicle_type = :ship if $game_map.ship.pos_rect?(front_x, front_y, interaction_rect)
@vehicle_type = :airship if $game_map.airship.pos_rect?(@x, @y, collision_rect)
if vehicle
@vehicle_getting_on = true
horz = (@x > vehicle.x ? -1 : @x < vehicle.x ? 1 : 0)
vert = (@y > vehicle.y ? -3 : @y < vehicle.y ? 3 : 0)
d = 5 + horz - vert
set_direction(d)
@x = vehicle.x
@y = vehicle.y
@followers.gather
end
@vehicle_getting_on
end
#--------------------------------------------------------------------------
# * Get Off Vehicle
# Assumes that the player is currently riding in a vehicle.
#--------------------------------------------------------------------------
def get_off_vehicle
if vehicle.land_ok?(@x, @y, @direction)
set_direction(2) if in_airship?
@followers.synchronize(@x, @y, @direction)
vehicle.get_off
unless in_airship?
@x = $game_map.round_x_with_direction(@x, @direction)
@y = $game_map.round_y_with_direction(@y, @direction)
@transparent = false
end
@vehicle_getting_off = true
@move_speed = 4
@through = false
make_encounter_count
@followers.gather
end
@vehicle_getting_off
end
#--------------------------------------------------------------------------
# * Determine if Map is Passable
# d: Direction (2,4,6,8)
#--------------------------------------------------------------------------
def map_passable_rect?(x, y, d, rect)
case @vehicle_type
when :boat
$game_map.boat_passable_rect?(x, y, vehicle.collision_rect)
when :ship
$game_map.ship_passable_rect?(x, y, vehicle.collision_rect)
when :airship
true
else
super
end
end
#--------------------------------------------------------------------------
# * Override: Move Diagonally
#--------------------------------------------------------------------------
def move_diagonal(horz, vert)
@followers.move if diagonal_passable?(@x, @y, horz, vert) || passable?(@x, @y, horz + 5) || passable?(@x, @y, 5 - vert * 3)
super
end
#--------------------------------------------------------------------------
# * Alias: Create Encounter Count
#--------------------------------------------------------------------------
alias game_player_make_encounter_count_cxj_fm make_encounter_count
def make_encounter_count
game_player_make_encounter_count_cxj_fm
@encounter_count*= (32 / CXJ::FREE_MOVEMENT::PIXELS_PER_STEP) + (32 / 2 < CXJ::FREE_MOVEMENT::PIXELS_PER_STEP ? 1 : 0)
end
#--------------------------------------------------------------------------
# * Detect Collision with Vehicle
#--------------------------------------------------------------------------
def collide_with_vehicles?(x, y)
(@vehicle_type != :boat && $game_map.boat.pos_rect_nt?(x, y, collision_rect)) || (@vehicle_type != :ship && $game_map.ship.pos_rect_nt?(x, y, collision_rect))
end
#--------------------------------------------------------------------------
# * Processing When Not Moving
# last_moving : Was it moving previously?
#--------------------------------------------------------------------------
alias game_player_update_nonmoving_cxj_fm update_nonmoving
def update_nonmoving(last_moving)
game_player_update_nonmoving_cxj_fm(last_moving)
update_encounter if !last_moving && !@last_poll.empty?
@last_poll.clear
end
end
#==============================================================================
# ** Game_Followers
#------------------------------------------------------------------------------
# This is a wrapper for a follower array. This class is used internally for
# the Game_Player class.
#==============================================================================
class Game_Followers
#--------------------------------------------------------------------------
# * Detect Collision
#--------------------------------------------------------------------------
def collide_rect?(x, y, rect)
visible_folloers.any? {|follower| follower.pos_rect?(x, y, rect) }
end
#--------------------------------------------------------------------------
# * Movement
#--------------------------------------------------------------------------
def move
reverse_each {|follower| follower.board if gathering?; follower.chase_preceding_character }
end
end
#==============================================================================
# ** Game_Vehicle
#------------------------------------------------------------------------------
# This class handles vehicles. It's used within the Game_Map class. If there
# are no vehicles on the current map, the coordinates are set to (-1,-1).
#==============================================================================
class Game_Vehicle < Game_Character
#--------------------------------------------------------------------------
# * New: Collision Rectangle
# Gets the collision rectangle.
#--------------------------------------------------------------------------
def collision_rect
collision = CXJ::FREE_MOVEMENT::DEFAULT_COLLISION
case @type
when :boat
collision = CXJ::FREE_MOVEMENT::BOAT_COLLISION
when :airship
collision = CXJ::FREE_MOVEMENT::AIRSHIP_COLLISION
end
return Rect.new(collision[0], collision[1], collision[2] - 1, collision[3] - 1)
end
#--------------------------------------------------------------------------
# * Determine if Docking/Landing Is Possible
# d: Direction (2,4,6,8)
#--------------------------------------------------------------------------
def land_ok?(x, y, d)
if @type == :airship
return false unless $game_map.airship_land_ok_rect?(x, y, collision_rect)
return false unless $game_map.events_xy_rect(x, y, collision_rect).empty?
else
x2 = $game_map.round_x_with_direction(x, d)
y2 = $game_map.round_y_with_direction(y, d)
return false unless $game_map.valid_rect?(x2, y2, collision_rect)
return false unless $game_map.passable_rect?(x2, y2, reverse_dir(d), collision_rect)
return false if collide_with_characters?(x2, y2)
end
return true
end
end
#==============================================================================
# ** Game_Event
#------------------------------------------------------------------------------
# This class handles events. Functions include event page switching via
# condition determinants and running parallel process events. Used within the
# Game_Map class.
#==============================================================================
class Game_Event < Game_Character
#--------------------------------------------------------------------------
# * Initialize Public Member Variables
#--------------------------------------------------------------------------
alias game_event_init_public_members_cxj_fm init_public_members
def init_public_members
game_event_init_public_members_cxj_fm
@collisionbox = Rect.new(0, 0, 31, 31)
end
#--------------------------------------------------------------------------
# * Initialize Public Member Variables
#--------------------------------------------------------------------------
def set_collision_rect(x, y, width, height)
@collisionbox = Rect.new(x, y, width - 1, height - 1)
end
#--------------------------------------------------------------------------
# * New: Collision Rectangle
# Gets the collision rectangle.
#--------------------------------------------------------------------------
def collision_rect
return @collisionbox
end
#--------------------------------------------------------------------------
# * Override: Move Straight
# d: Direction (2,4,6,8)
# turn_ok : Allows change of direction on the spot
#
# Polls the movement instead of processing them immediately.
#--------------------------------------------------------------------------
def move_straight(d, turn_ok = true)
@move_poll+= [[d, turn_ok]] * (rand(32 / CXJ::FREE_MOVEMENT::PIXELS_PER_STEP))
end
#--------------------------------------------------------------------------
# * Detect Collision with Player (Including Followers)
#--------------------------------------------------------------------------
def collide_with_player_characters?(x, y)
normal_priority? && $game_player.collide_rect?(x, y, collision_rect)
end
end
#==============================================================================
# ** Game_Follower
#------------------------------------------------------------------------------
# This class handles followers. A follower is an allied character, other than
# the front character, displayed in the party. It is referenced within the
# Game_Followers class.
#==============================================================================
class Game_Follower < Game_Character
#--------------------------------------------------------------------------
# * Alias: Object Initialization
#--------------------------------------------------------------------------
alias game_follower_initialize_cxj_fm initialize
def initialize(member_index, preceding_character)
game_follower_initialize_cxj_fm(member_index, preceding_character)
@force_chase = false
@board = false
end
#--------------------------------------------------------------------------
# * Pursue Preceding Character
#--------------------------------------------------------------------------
def chase_preceding_character
unless moving? && !@force_chase
dist = CXJ::FREE_MOVEMENT::FOLLOWERS_DISTANCE / 32.0
mrgn = CXJ::FREE_MOVEMENT::FOLLOWERS_DISTANCE_MARGIN / 32.0
sx = distance_x_from(@preceding_character.x)
sy = distance_y_from(@preceding_character.y)
sd = Math.hypot(sx, sy)
if @board
@x = @preceding_character.x
@y = @preceding_character.y
@board = false
elsif(sd > dist && sx.abs > mrgn && sy.abs > mrgn)
@move_poll+=[[(sx > 0 ? -1 : 1) + (sy > 0 ? 8 : 2), true]]
elsif sx.abs > dist && sx.abs > sy.abs
@move_poll+=[[sx > 0 ? 4 : 6, true]]
elsif sy.abs > dist && sx.abs < sy.abs
@move_poll+=[[sy > 0 ? 8 : 2, true]]
end
end
end
def distance_preceding_character
sx = distance_x_from(@preceding_character.x)
sy = distance_y_from(@preceding_character.y)
return Math.hypot(sx, sy)
end
def process_move(horz, vert)
super(horz, vert)
dist = CXJ::FREE_MOVEMENT::FOLLOWERS_DISTANCE / 32.0
if distance_preceding_character > dist && @move_poll.size == 0
@force_chase = true
chase_preceding_character
@force_chase = false
end
end
def board
@board = true
end
end
#==============================================================================
# ** Game_Interpreter
#------------------------------------------------------------------------------
# An interpreter for executing event commands. This class is used within the
# Game_Map, Game_Troop, and Game_Event classes.
#==============================================================================
class Game_Interpreter
#--------------------------------------------------------------------------
# * Initialize Public Member Variables
#--------------------------------------------------------------------------
def set_collision_rect(x, y, width, height)
$game_map.events[@event_id].set_collision_rect(x, y, width, height)
end
end
=begin
class Spriteset_Map
#--------------------------------------------------------------------------
# * Object Initialization
#--------------------------------------------------------------------------
def initialize
create_viewports
create_tilemap
create_parallax
create_characters
create_shadow
create_weather
create_pictures
create_timer
@colbox = Sprite.new
@colbox.bitmap = Bitmap.new(96, 96)
update
end
#--------------------------------------------------------------------------
# * Frame Update
#--------------------------------------------------------------------------
def update
update_tileset
update_tilemap
update_parallax
update_characters
update_shadow
update_weather
update_pictures
update_timer
update_viewports
@colbox.x = $game_player.screen_x - 48
@colbox.y = $game_player.screen_y - 64
@colbox.bitmap.clear
@colbox.bitmap.fill_rect(0, 0, 96, 96, Color.new(0, 0, 0, 64))
cRec = $game_player.collision_rect.dup
iRec = $game_player.interaction_rect.dup
d = $game_player.direction
cRec.set(cRec.x + 32, cRec.y + 32, cRec.width, cRec.height)
@colbox.bitmap.fill_rect(cRec, Color.new(0, 255, 0, 128))
#iRec.set(iRec.x + 32, iRec.y + 32, iRec.width, iRec.height)
iRec.set(iRec.x + 32 + 32 * (d == 4 ? -1 : d == 6 ? 1 : 0), iRec.y + 32 + 32 * (d == 8 ? -1 : d == 2 ? 1 : 0), iRec.width, iRec.height)
#iRec.set(iRec.x + 48 + 32 * (d == 4 ? -1 : d == 6 ? 1 : 0), iRec.y + 64 + 32 * (d == 8 ? -1 : d == 2 ? 1 : 0), iRec.width, iRec.height)
@colbox.bitmap.fill_rect(iRec, Color.new(255, 0, 0, 128))
end
end
=end
[/noae][/noae][/noae][/noae][/noae][/noae][/noae]
Video (http://youtu.be/ZqijOtzLgbA)
There are only a few things really missing, like diagonal sprites and diagonal interaction boxes, and the ability to adjust not only jump length (which is already implemented) but also jump height. I also want to add a method which allows people to move while jumping, and I might want to add some extra stuff, think things like being able to jump into pits (and getting damage from it or getting teleported somewhere else) or swimming, but I'll be seeing about those, as they're not really core elements. After that, I'll be making an Action RPG system to accompany this.
By the way, I also have other scripts available for it on Area91 (http://area91.multiverseworks.com) in case you're wondering.
-
Ooooooo.
I never got further than rm2k3 so I can't test it out :p
-
I know I've already told you this, but you're awesome.
-
Works just fine, Gary! Just wondering, how does it handle cut-scenes? For example, move hero events?
-
Works just fine, Gary! Just wondering, how does it handle cut-scenes? For example, move hero events?
I absolutely have no idea. Those are things that need to be tested.
EDIT: Okay, so I've figured that I needed to modify the methods a bit so that everything moves with steps of 1 tile (32 pixels).
-
Also, I just noticed that touch event aren't triggered by the player when they're running.
-
Test video (http://youtu.be/C1y9oJPwK80)
I've got a new version done, finally.
Download WIP 1 (http://area91.multiverseworks.com/rmvxa/wip/free_movement_wip1.zip)
WIP 1 script (http://area91.multiverseworks.com/rmvxa/wip/free_movement_wip1.rb)
-
A little heads up, I decided to release this script.
http://area91.multiverseworks.com/index.php?action=rmvxa_script&view=free_movement (http://area91.multiverseworks.com/index.php?action=rmvxa_script&view=free_movement)