[XP] Heretic's Circular Sprite Motion

Started by Heretic86, April 29, 2015, 07:59:50 pm

Previous topic - Next topic

Heretic86

April 29, 2015, 07:59:50 pm Last Edit: July 05, 2015, 04:24:51 pm by Heretic86
Circular Sprite Motion XP
Authors: Heretic
Version: 1.1
Type: Custom Movement System
Key Term: Custom Movement System



Introduction

This script will allow you to give Sprites a Circular Motion, where they can "spin" around their Parent Event.  It does not affect Collisions.

You can also use Circular Motion to create a "Float" Effect by setting the X Radius Value to 0.


Features


  • Circular Motion

  • Create a "Float" Effect

  • Transition either the Speed of Rotation, or the Radii

  • Hey look!  I'm Spinnin!  Anyone remember Frog in a Blender?




Screenshots







New in Version 1.1




Demo

http://downloads.chaos-project.com/heretic86/MP/CircularSpriteMotion.exe


Script

Place below Modular Passable (Required)
Place below Loop Maps and Collision Optimizer (Optional, both require Modular Passable)
Place above Main

Spoiler: ShowHide
#===============================================================================
#
#           HERETIC'S CIRCULAR SPRITE MOTION [XP]
#           Version 1.1
#           Sunday, March 15th, 2015
#
#===============================================================================
#
#
#   *****   REQUIRES HERETICS MODULAR PASSABLE SCRIPT   *****
#
#
#  -----  OVERVIEW  -----
#
#  This script will allow you to apply Circular Motion to Sprites.
#
#  NOTE: Requires Heretic's Modular Passable
#
#  NOTE: Does NOT affect Collisions, Sprite ONLY.
#
#
#  -----  INSTRUCTIONS  -----
#
#  Default Values for Events are set by putting a \comment[values] Comment on
#  each Page of an Event.  Values can be changed later with Script Calls.
#
#  For installation, place this script above MAIN, and below Modular Passable.
#
#  For Character Sprites to Spin, they must have a \spin and \spin_radius[N]
#  comment within the first *10 Lines on each Page.
#
#  To use these properties on the Player, use a Move Route Script to change
#  the corresponding property name.  \spin comments should be set by using
#  a Move Route Script -> @spin = true
#
#  These patterns are intended as Effects ONLY!  They do NOT affect collisions
#  in any way shape or form.  You will probably want to set "Always On Top"
#  because Sprites can appear under other Events below the location
#  of the "Spinning" Event.
#
#  * 10 Lines is a Modifiable Parameter in the Modular Passable Script.  It
#    can be overridden per event page with a comment: \comment_limit[N] where
#    the letter N is a number higher than 10.  Increasing this number to an
#    excessive degree can impact performance, this, using this \comment_limit
#    option is useful as very few events should need to exceed the Limit of 10.
#
#
#  -----  COMMENT CONFIGURATION OPTIONS  -----
#
#  Apply each of the following Comments to an Event for corresponding Effects:
#
#  /spin              - Enables Circular Motion Effects
#  /spin_radius[N]    - Distance in Pixels from actual Event Map location
#  /spin_radius[N, N] - Distance in X, Y Distance for a Elliptical Movement
#  /spin_speed[N]     - Speed in Degrees Per Frame
#  /spin_speed[N, N]  - X and Y have different Rotational Speeds (non circles)
#  /spin_angle[N]     - Initial Angle (0.0 - 360.0)
#  /spin_angle[N, N]  - X and Y have different Inital Angles
#
#
#  -----  SCRIPT CALL OPTIONS  -----
#
#  @spin = true / false   
#    - enable or disable Circular Movement of Sprites
#  @spin_radius = 32
#    - set the radius of Circular Movement to 32 Pixels from actual Character
#  @spin_radius = [64, 32]
#    - set the X, Y to shape Elliptical Movement.  X = 64 pixels and Y = 32
#  @spin_speed = 10
#    - set the speed of Circular Movement to 10 Degrees per Frame
#  @spin_speed = [5, 7.5]
#    - set X and Y Rotations to have independent speeds
#
#  --- Transitions ----
#
#  All numeric properties can be transitioned.  These scripts should be called
#  from a Move Route Script, or character.script
#
#  spin_speed_to(new_speed, duration=0)
#  -  Transitions from current speed to new speed over duration in frames
#
#  spin_speed_to([new_x_speed, new_y_speed], duration=0)
#  -  Transition both X and Y to new Targets using same duration in frames
#    * Non Circular and Non Elliptical Movements
#
#  spin_radius_to(new_radius, duration=0)
#  -  Transitions from current Radius to New Radius over duration in frames
#
#  spin_radius_x_to(new_x_radius, duration=0)
#  -  Transition from current Radius X to alter the X size of the Ellipse
#
#  spin_radius_y_to(new_y_radius, duration=0)
#  -  Transition from current Radius Y to altery the Y size of the Ellipse
#
#
#  NOTE:  You can transition from a Circle with one Radius to a Double Radius

#  Examples:
#
#  $game_map.events[12].spin = true
#  $game_map.events[12].spin_speed = 10
#  $game_map.events[12].spin_speed = -5.5
#  $game_map.events[12].spin_speed_to(5, 40)
#  $game_map.events[12].spin_radius_to(32, 20)

#  These work on the Game Player as well
#
#  $game_player.spin = true
#  $game_player.spin_speed = 12
#  $game_player.spin_speed_to(5, 40)
#  $game_player.spin_radius_to = 64
#
#
#  -----  VERSION HISTORY  -----
#
#  Version 1.1 - Friday, July 3rd, 2015
#  * Changed Spin Speed from Integer to allow for XY Arrays
#   - Array allows for more interesting "patterns" of movement
#   - You can now set the Spin Speed by putting in seperate values
#     for both the X and Y Speeds of Rotation
#     \spin_speed[4] - Same value for both X and Y Rotations
#     \spin_speed[2.5, 4.3] - X and Y Rotational Speeds are Independant
#  * Changed initial Spin Angle to also have separate XY Starting Values
#   - You can now set the Initial Vectors by putting in separate values
#     \spin_angle[45] - Initial Starting Value when Speeds are the same
#     \spin_angle[0, 45] - Different Starting Values for both X and Y
#  Version 1.0 - Sunday, March 15th, 2015
#  * Initial Release
#  -----  PAGE OPTIONS  -----
#
#  These Comments are applied Per Event Page!  This allows you to have
#  different configurations on each Event Page!  One Page just Rotates
#  to the Left, then Right.  Another Page could be used to Point at
#  the Player by giving the Rotating Event a Rotate Target!
#
#  All Page Values will be cleared when an Event changes to another valid Page.

# Check for Modular Passable Script - REQUIRED - DO NOT EDIT
unless $Modular_Passable
  print "Fatal Error: Heretics Uniform Circular Sprite Motion script\n",
        "requires Heretics Modular Passable Script!\n\n",
        "Modular Passable is Not Available or is below this script.\n",
        "Modular Passable MUST be above this script.\n\n",
        "The Game will now Exit"
  # End game before fatal errors
  exit
end

#==============================================================================
# ** Game_Character
#==============================================================================
class Game_Character
  #--------------------------------------------------------------------------
  # * Public Instance Variables - Game_Character
  #--------------------------------------------------------------------------
  attr_accessor  :spin          # If Character Spins
  attr_accessor  :spin_angle    # Initial Angle of Character
  attr_accessor  :spin_speed    # How quickly to Spin
  attr_accessor  :spin_radius   # Distance to Offset Sprite from Char [x, y]
  #--------------------------------------------------------------------------
  # * Frame Update - Game_Character
  #--------------------------------------------------------------------------
  alias spin_char_initialize initialize unless $@
  def initialize
    # New Property for Spinning Sprites
    @spin_angle = 0
    # Call Original or other Aliases
    spin_char_initialize
  end
  #--------------------------------------------------------------------------
  # * Frame Update - Game_Character
  #--------------------------------------------------------------------------
  alias spin_update update unless $@
  def update
    # If Spin Speed To Transition is taking place
    if @spin_speed_target and @spin_speed_duration and @spin_speed_duration > 0
      # If Speed Target has different values for X and Y (Array)
      if @spin_speed_target.is_a?(Array)
        # Shorthand for X and Y
        tx = @spin_speed_target[0].to_f
        ty = @spin_speed_target[1].to_f
        # Duration is same for both X and Y in a Transition
        d = @spin_speed_duration
        # Adjust the Spin Speed over Duration Frames for X and Y
        @spin_speed[0] = (@spin_speed[0] * (d - 1) + tx) / d
        @spin_speed[1] = (@spin_speed[1] * (d - 1) + ty) / d
        # If Spin Speed To has not completed
        if @spin_speed_duration > 0
          # Decrease the Duration Cycle to End
          @spin_speed_duration -= 1
        end
        # End the Spin Speed To Transition
        @spin_speed[0] = @spin_speed_target[0] if @spin_speed_target[0] == 0
        @spin_speed[1] = @spin_speed_target[1] if @spin_speed_target[1] == 0
      # Else Spin Speed uses same Speed 
      else
        # Shorthand
        t = @spin_speed_target.to_f
        d = @spin_speed_duration
        # Adjust the Spin Speed over Duration Frames
        @spin_speed = (@spin_speed * (d - 1) + t) / d
        # If Spin Speed To has not completed
        if @spin_speed_duration > 0
          # Decrease the Duration Cycle to End
          @spin_speed_duration -= 1
        end
        # End the Spin Speed To Transition
        @spin_speed = @spin_speed_target if @spin_speed_target == 0
      end
    end
    # If Spin Radius Transition for X, Y Radius for Shaped Orbits
    if (@spin_radius_x_duration and @spin_radius_x_duration > 0) or
       (@spin_radius_y_duration and @spin_radius_y_duration > 0)
      # If Radius X Transition
      if @spin_radius_x_target and @spin_radius_x_duration > 0
        # Shorthand
        t = @spin_radius_x_target.to_f
        d = @spin_radius_x_duration
        # Adjust the Spin Radius X over Duration Frames
        @spin_radius[0] = (@spin_radius[0] * (d - 1) + t) / d
        # If Spin Radius To has not completed
        if @spin_radius_x_duration > 0
          # Decrease the Duration Cycle to End
          @spin_radius_x_duration -= 1
        end
        # End the Spin radius To Transition
        @spin_radius[0] = @spin_radius_x_target if @spin_radius_x_duration == 0
      end
      # If Radius Y Transition
      if @spin_radius_y_target and @spin_radius_y_duration > 0
        # Shorthand
        t = @spin_radius_y_target.to_f
        d = @spin_radius_y_duration
        # Adjust the Spin Radius Y over Duration Frames
        @spin_radius[1] = (@spin_radius[1] * (d - 1) + t) / d
        # If Spin Radius To has not completed
        if @spin_radius_y_duration > 0
          # Decrease the Duration Cycle to End
          @spin_radius_y_duration -= 1
        end
        # End the Spin radius To Transition
        @spin_radius[1] = @spin_radius_y_target if @spin_radius_x_duration == 0
      end
    # If Spin Radius To Transition is taking place
    elsif @spin_radius_target and @spin_radius_duration and
       @spin_radius_duration > 0
      # Shorthand
      t = @spin_radius_target.to_f
      d = @spin_radius_duration
      # Adjust the Spin Radius over Duration Frames
      @spin_radius = (@spin_radius * (d - 1) + t) / d
      # If Spin Radius To has not completed
      if @spin_radius_duration > 0
        # Decrease the Duration Cycle to End
        @spin_radius_duration -= 1
      end
      # End the Spin radius To Transition
      @spin_radius = @spin_radius_target if @spin_radius_duration == 0
    end
    # Update Spin Counter
    if @spin_speed
      # If Speed has different Speeds for both X and Y (Array)
      if @spin_speed.is_a?(Array)
        # If Angle is not an Array
        if not @spin_angle.is_a?(Array)       
          # Change the Angle into an Array using Current Angle Value for X, Y
          @spin_angle = [@spin_angle, @spin_angle]
        end
        # Update X and Y Speeds independently
        @spin_angle[0] += @spin_speed[0]
        @spin_angle[1] += @spin_speed[1]
        # Clamp to 360 Degrees for both X and Y values
        @spin_angle[0] %= 360.0
        @spin_angle[1] %= 360.0
      # If the Angle is an Array and Speed is not an Array
      elsif @spin_angle.is_a?(Array)
        # Apply Speed changes to both X and Y value so ther is no "Snapping"
        @spin_angle[0] += @spin_speed
        @spin_angle[1] += @spin_speed
        # Clamp to 360 Degrees
        @spin_angle[0] %= 360.0
        @spin_angle[1] %= 360.0
      # Else Spin Speed is a Single Value not an Array
      else
        # Increase the Spin Counter
        @spin_angle += @spin_speed
        # Clamp to 360 Degrees
        @spin_angle %= 360.0
      end
    end
    # Call Original or other Aliases
    spin_update
  end
  #--------------------------------------------------------------------------
  # * Spin Speed To - Game_Character
  #      target   : Target in Pixels to Clip the Sprites Base
  #      duration : Duration in Frames (Optional) 
  #--------------------------------------------------------------------------
  def spin_speed_to(target, duration = 0)
    # If No Duration
    if duration == 0
      # Just set the Spin Speed with no Transition
      @spin_speed = target
      return
    end
    # The Target Spin Speed when finished
    @spin_speed_target = target
    # The Number of Frames to take to adjust Spin Speed
    @spin_speed_duration = duration
  end
  #--------------------------------------------------------------------------
  # * Spin Radius To - Game_Character
  #      target   : Target Radius
  #      duration : Duration in Frames (Optional) 
  #--------------------------------------------------------------------------
  def spin_radius_to(target, duration = 0)
    # Check for nil Radius
    @spin_radius = 0 if @spin_radius.nil?
    # If No Duration
    if duration == 0
      # Just set the Spin Radius with no Transition
      @spin_radius = target
      return
    end
    # If Radius is an Array for X, Y
    if @spin_radius.is_a?(Array)
      # Set the Target for both X and Y values
      @spin_radius_x_target = @spin_radius_y_target = target
      # The Number of Frames to take to adjust Spin Radius
      @spin_radius_x_duration = @spin_radius_y_duration = duration     
    else
      # The Target Spin Radius when finished
      @spin_radius_target = target
      # The Number of Frames to take to adjust Spin Radius
      @spin_radius_duration = duration     
    end
  end
  #--------------------------------------------------------------------------
  # * Spin Radius X To - Game_Character
  #      target   : Target Radius X Size
  #      duration : Duration in Frames (Optional) 
  #--------------------------------------------------------------------------
  def spin_radius_x_to(target, duration = 0)
    # Check for nil Radius
    @spin_radius = 0 if @spin_radius.nil?
    # If No Duration
    if duration == 0
      # Old Radius Y Value
      orig_ry = (@spin_radius.is_a?(Array)) ? @spin_radius[1] : @spin_radius
      # Just set the Spin Radius X with no Transition
      @spin_radius = [target, orig_ry]
      return
    end
    # If current Radius is not an Array
    if @spin_radius.is_a?(Numeric)
      # Old Radius Value
      orig_r = @spin_radius
      # Convert Value to Array for both Values to allow Transition on X
      @spin_radius = [orig_r, orig_r]
    end
    # The Target Spin Radius when finished
    @spin_radius_x_target = target
    # The Number of Frames to take to adjust Spin Radius
    @spin_radius_x_duration = duration
  end
  #--------------------------------------------------------------------------
  # * Spin Radius Y To - Game_Character
  #      target   : Target Radius Y Size
  #      duration : Duration in Frames (Optional) 
  #--------------------------------------------------------------------------
  def spin_radius_y_to(target, duration = 0)
    # Check for nil Radius
    @spin_radius = 0 if @spin_radius.nil?
    # If No Duration
    if duration == 0
      # Old Radius X Value
      orig_rx = (@spin_radius.is_a?(Array)) ? @spin_radius[0] : @spin_radius
      # Just set the Spin Radius Y with no Transition
      @spin_radius = [orig_rx, target]
      return
    end
    # If current Radius is not an Array
    if @spin_radius.is_a?(Numeric)
      # Old Radius Value
      orig_r = @spin_radius
      # Convert Value to Array for both Values to allow Transition on Y
      @spin_radius = [orig_r, orig_r]
    end   
    # The Target Spin Radius Y when finished
    @spin_radius_y_target = target
    # The Number of Frames to take to adjust Spin Radius Y
    @spin_radius_y_duration = duration
  end
  #--------------------------------------------------------------------------
  # * Get Screen X-Coordinates
  #--------------------------------------------------------------------------
  alias spin_screen_x screen_x unless $@
  def screen_x
    # Get Original or other Aliases
    orig_x = spin_screen_x
    # If has a Spin property
    if @spin and @spin_radius
      # Use Value or 2nd Array Arg as Radius
      radius = (@spin_radius.is_a?(Array) ) ? @spin_radius[0] : @spin_radius
      # Use Value or 2nd Array Arg as Angle
      angle = (@spin_angle.is_a?(Array) ) ? @spin_angle[0] : @spin_angle
      # Calculate X Offset Distance (Round to prevent Screen Tearing)
      orig_x += (radius * Math.cos(angle * Math::PI / 180.0)).round
    end
    # Return Modified Value
    return orig_x
  end
  #--------------------------------------------------------------------------
  # * Get Screen Y-Coordinates
  #--------------------------------------------------------------------------
  alias spin_screen_y screen_y unless $@
  def screen_y
    # Get Original or other Aliases
    orig_y = spin_screen_y
    # If has a Spin property
    if @spin and @spin_radius
      # Use Value or 2nd Array Arg as Radius
      radius = (@spin_radius.is_a?(Array) ) ? @spin_radius[1] : @spin_radius
      # Use Value or 2nd Array Arg as Angle
      angle = (@spin_angle.is_a?(Array) ) ? @spin_angle[1] : @spin_angle
      # Calculate Y Offset Distance (Round to prevent Screen Tearing)
      orig_y += (radius * Math.sin(angle * Math::PI / 180.0)).round
    end
    # Return Modified Value
    return orig_y
  end
end

#==============================================================================
# ** Game_Event - Class
#==============================================================================
class Game_Event < Game_Character
  #--------------------------------------------------------------------------
  # * Object Initialization
  #     map_id : map ID
  #     event  : event (RPG::Event)
  #--------------------------------------------------------------------------
  alias spin_initialize initialize unless $@ 
  def initialize(map_id, event)
    # Call Original or other Aliases
    spin_initialize(map_id, event)
  end
  #--------------------------------------------------------------------------
  # * Reset Page Comment Config - Game_Event
  #  - Aliasing Requires Modular Passable, otherwise this is unique
  #  - Resets Rotation Options set by Comment Config during a Page Change
  #--------------------------------------------------------------------------
  alias spin_reset_page_comment_config reset_page_comment_config unless $@
  def reset_page_comment_config
    # Reset to set again by Comment Conditions
    @spin = nil
    @spin_angle = 0
    @spin_speed = nil
    @spin_speed_target = nil
    @spin_speed_duration = nil
    @spin_radius = nil
    @spin_radius_target = nil
    @spin_radius_duration = nil
    @spin_radius_x_target = nil
    @spin_radius_y_target = nil
    @spin_radius_x_duration = nil
    @spin_radius_y_duration = nil
    # Runs Original or Other Aliases
    spin_reset_page_comment_config
  end
  #--------------------------------------------------------------------------
  # * Spin Check Comment Page Config - Game_Event
  #     comment : the Comment to be checked to adjust Page Properties
  #     count   : integer of which List of Event Commands is checked
  #
  #   Note: When aliasing, please return the value of aliased methods for
  #         the local variable count to be altered as needed.
  #   return alias_check_page_comment_config(comment, count)
  #--------------------------------------------------------------------------
  alias spin_check_page_comment_config check_page_comment_config unless $@
  def check_page_comment_config(comment, count)
    # Looks for "\spin_speed[N]" Comments (to Floating or Array of Integers)
    comment.gsub(/^\\spin_speed\[([-0-9., ]+)\]\z/i){
      # Single Number Capture
      @spin_speed = $1.to_f if $1.to_f.is_a?(Numeric);
      # If Capture is intended as an [X, Y] Array
      @spin_speed = $1.split(",").map { |s| s.to_f } if $1.include?(",")
      # Allow other Scripts to use this Count to modify Events with M.P.
      return count;}
    # Looks for "\spin_radius[N]" Comments (to Float or Array)
    comment.gsub(/^\\spin_radius\[([-0-9., ]+)\]\z/i){
      # Single Number Capture
      @spin_radius = $1.to_f if $1.to_f.is_a?(Numeric);
      # If Capture is intended as an [X, Y] Array
      @spin_radius = $1.split(",").map { |s| s.to_f } if $1.include?(",")
      # Allow other Scripts to use this Count to modify Events with M.P.
      return count; }
    # Look for Initial "spin_angle[N.n]" in the Comments
    comment.gsub(/^\\spin_angle\[([-0-9., ]+)\]\z/i){
      # Single Number Capture
      @spin_angle = $1.to_f % 360.0 if $1.to_f.is_a?(Numeric);
      # If Capture is intended as an [X, Y] Array
      @spin_angle = $1.split(",").map { |s| s.to_f } if $1.include?(",")
      # Allow other Scripts to use this Count to modify Events with M.P.
      return count;}
    # Looks for "\spin" in the Comments (Use on Character Events)
    comment.gsub(/^\\spin\z/i){@spin = true; return count}
    # Return adjusted or unadjusted counter for other scripts to use this
    return spin_check_page_comment_config(comment, count)
  end 
end



Instructions

Circular Motion, or "Spin" Effects are created by adding Comments to Events.  Each Event will require THREE Comments:

\spin
\spin_speed[N]
\spin_radius[N]

Spin Speed can be a Negative Number.

Spin Radius will accept ONE or TWO RADII, allowing for Floating Effects:
\spin_radius[0, 16]

Transition either Spin or Radius with Scripts:

spin_speed_to(new_speed, duration)
spin_radius_to(new_radius, duration)

You can Transition from One to Two Radii by using an [X, Y] Array in new_radius:
spin_speed_to([32, 64], 20)

Apply these Effects to Events or the Player:
$game_map.events[12].spin = true
$game_map.events[12].spin_speed = -5.25
$game_map.events[12].spin_radius = 16
$game_player.spin_speed_to(15, 40)



Compatibility

Dryclean Only!!!


Credits and Thanks


  • I'd like to thank whoever invented Sarcasm, its delicious!




Author's Notes

This is a Movement Effects Script.  It does NOT affect Collisions, so you may want to be careful about confusing Players in the way you apply the effects.
Current Scripts:
Heretic's Moving Platforms

Current Demos:
Collection of Art and 100% Compatible Scripts

(Script Demos are all still available in the Collection link above.  I lost some individual demos due to a server crash.)

KK20

Kise reported having issues setting up the event to make the circular motion. Perhaps a rewrite of the instructions is in order (maybe with a text-based example too, like what you did with the script call options). Make it clear that each spin configuration needs to be in a separate comment (or change the script to allow it all in one comment instead). Also, you list the options with a forward slash when they should be backslashes.

#  /spin              - Enables Circular Motion Effects
#  /spin_radius[N]    - Distance in Pixels from actual Event Map location
#  /spin_radius[N, N] - Distance in X, Y Distance for a Elliptical Movement
#  /spin_speed[N]     - Speed in Degrees Per Frame
#  /spin_speed[N, N]  - X and Y have different Rotational Speeds (non circles)
#  /spin_angle[N]     - Initial Angle (0.0 - 360.0)
#  /spin_angle[N, N]  - X and Y have different Inital Angles





   


   
   


   
   

Other Projects
RPG Maker XP AceUpgrade RMXP to RMVXA performance!
XPA TilemapTilemap rewrite with many features, including custom resolution!



Nintendo Switch Friend Code: 8310-1917-5318
Discord: KK20 Tyler#8901

Join the CP Discord Server!