Jump to content
kal

Ruby/RGSS3 questions that don't deserve their own thread

Recommended Posts

I have a simple jump script and want to add a state when the player jumps and remove that state when that player lands.

 

Here is the script.

 

 

 

# Allows jumping by input...
# ** module INPUT

module Free_Jump_Object
  Armor = [985] # ID Armors needed to jump
end

class Game_Actor < Game_Battler 
  def armor_equipped?(armor_id)
    armors.any? {|armor| armor.id == armor_id }
  end
end

module JUMP
  module Settings
	  DashJumpSize = 2
	  JumpSize = 1
	  Key = :X # the game key that can be pressed to jump. Not necessarily the
				  # same as the keyboard key
  end # End - Settings
end # End - JUMP

# ** Game_Player

class Game_Player < Game_Character

  # alias method move_by_input
  alias jump_settings_move_by_input_alias_method_49271 move_by_input
  def move_by_input
	jump_settings_move_by_input_alias_method_49271
	try_jump if Input.trigger?(JUMP::Settings::Key)
  end # End - move_by_input

  def does_not_have_proper_equipment
    Free_Jump_Object::Armor.each do |xa_armor|
      return true if $game_party.members[0].armor_equipped?(xa_armor)
      return false if !$game_party.members[0].armor_equipped?(xa_armor)
    end
  end
  
  def try_jump
	return if !does_not_have_proper_equipment
	#print "inside try_jump \n"
	
  RPG::SE.new("Jump", 50, 100).play
  
	jump_x, jump_y = 0,0
	case @direction
	when 2
	  jump_y = get_jump_size
	when 4
	  jump_x = -get_jump_size
	when 6
	  jump_x = get_jump_size
	when 8
	  jump_y = -get_jump_size
	end
	jump(jump_x, jump_y) if map_passable?(jump_x+@x, jump_y+@y, @direction)
  end # End - try_jump

  def get_jump_size
	val = dash? ? JUMP::Settings::DashJumpSize : JUMP::Settings::JumpSize
	#print "jump size = #{val}\n"
	#val
  end

end # End - Game_Player

 

 

Share this post


Link to post
Share on other sites

Hello everyone! I'm writing a script for someone and as of right now my method is in the Game Interpreter class because it is called through a common event that only runs if a switch is on. The switch is turned on through a parallel process event on the very first map of the game. This is NOT my goal. The reason I currently have it set this way is because anytime I try to call my method through the script editor itself I get an error of $game_actors not an initialized variable or whatever. Heres the script:

 

 

 

class Game_Interpreter

  def actor_change_equip()
			   @actors = [
	  $game_actors[1],
	  $game_actors[2],
	  $game_actors[3],
	  $game_actors[4]
			  ]

    @actor_level = [
	  @actors[0].level,
	  @actors[0].level,
	  @actors[0].level,
	  @actors[0].level
			  ]

    @actor_weapon_lvl = [
#
# actor 1
#
	  5,
	  10,
	  15,
	  20
 ]

@actor_weapon = [
#
# actor 1
#
	  $data_weapons[2],
	  $data_weapons[3],
	  $data_weapons[4],
	  $data_weapons[5]
]
if @actor_level[0] == @actor_weapon_lvl[0]
	    
		 $game_party.gain_item(@actor_weapon[0], 1)
		 @actors[0].change_equip(0, @actor_weapon[0])
		 $game_party.lose_item(@actor_weapon[0], 1)
	     
	   end
     end
end

 

 

So what it does is checks to see if the actor level meets the specified requirement for weapon upgrade. Then once its met the upgrade happens. My script is above main and below materials. What I want is to do away with the common event script call and have it automatically check while game is being played if it meets requirements. Any pointers will be much appreciated. By the way this is a scaled down version of the script.

Share this post


Link to post
Share on other sites

This would be much more efficient if you instead made weapon_lvl and upgrade_weapons properties of Game_Actor, set them via notetags and iterated through them. If I get time later I'll whip something up for you.

Share this post


Link to post
Share on other sites

This would be much more efficient if you instead made weapon_lvl and upgrade_weapons properties of Game_Actor, set them via notetags and iterated through them. If I get time later I'll whip something up for you.

Yes ive looked into note tagging but havent quite figured it out yet

Share this post


Link to post
Share on other sites

Also you seem to need to learn about the wonderful world of closures  (and maybe also the fact that $game_party has a method that returns the party or battle party but that is besides the point). Okay okay maybe that wikipedia's explanation is a bit dry and technical, but the point is, there are methods you can run on arrays that let you pass code to be run on the whole array in one command. It's basically the Ruby version of a for loop, but it can actually be used for a lot more then that.

 

This is done by using blocks. Blocks basically come in the form of using brackets like this { } or using a do statement followed by an end statement. They also usually require a variable named surrounded by pipes like |this|. The variable in the pipes will be set to whatever the block is running on. In the case of arrays it's usually the current value of what the loop it's doing is working on. There are tons and tons of different things you can do with this. You should look at the defualt scripts if you want a good idea of how they are used. But the big one is the array's .each method which runs whatever you want on each member of an array like this:

 

$game_actors.each do |actor|
  if actor.level >= 5
    # do something with that actor
  end
end
Or if you want to make an array out of another array instead of doing this:

 

something = [
  array[0],
  array[1],
  array[2],
  array[3]
]
 

you can use the .collect method to do this instead:

 

something = [0,1,2,3].collect {|i| array[i]}

Share this post


Link to post
Share on other sites

Also you seem to need to learn about the wonderful world of closures (and maybe also the fact that $game_party has a method that returns the party or battle party but that is besides the point). Okay okay maybe that wikipedia's explanation is a bit dry and technical, but the point is, there are methods you can run on arrays that let you pass code to be run on the whole array in one command. It's basically the Ruby version of a for loop, but it can actually be used for a lot more then that.

 

This is done by using blocks. Blocks basically come in the form of using brackets like this { } or using a do statement followed by an end statement. They also usually require a variable named surrounded by pipes like |this|. The variable in the pipes will be set to whatever the block is running on. In the case of arrays it's usually the current value of what the loop it's doing is working on. There are tons and tons of different things you can do with this. You should look at the defualt scripts if you want a good idea of how they are used. But the big one is the array's .each method which runs whatever you want on each member of an array like this:

 

 

$game_actors.each do |actor|
  if actor.level >= 5
    # do something with that actor
  end
end
Or if you want to make an array out of another array instead of doing this:

 

something = [
  array[0],
  array[1],
  array[2],
  array[3]
]
you can use the .collect method to do this instead:

 

something = [0,1,2,3].collect {|i| array[i]}
That does help a lot in shortening the script quite a bit. Ive basically taught myself thus far by experimenting (with the VERY limited free time i have available) and then of course DiamondPlatinums great video tutorials... Im still getting used to the language. But... I am still wondering about calling this method without using a script call from a common event...

 

I've tried just calling it in the script editor after the end of the method but the method never actually worked. Like this

 

def method24
end
method24
Ive tried putting it into its own class and using the:

 

object = Class.new
object.method
But that threw an error saying "$game_actors" invalid (because the global variables had not been initialized yet).

 

Ive tried creating it in its own module with constants and a self.method while using the

 

module RPG
  include MyModule
end
(MyModule being the module that holds the constants and the self.method)

 

But that threw an error of "no method for []". (Imagine all of the instance variables listed above as ALL_CAPS rather than @like_this.)

Edited by guitarski24

Share this post


Link to post
Share on other sites

Well, I am not quite sure how you are trying to call it, but one thing you have to keep in mind is $game_actors is only valid after the game actually starts. I think you may be a bit confused about how scripts actually work. You should look at a few other people have done and read through the default scripts if you can. But basically what it all comes down to is that you can't just run things whenever you want. I guess you could say the code flows from a river and ends up going from one place to another in a pretty ordered way.

 

Think of it like this, the computer is reading every single statement from the top of the script list to the bottom, but most of the things it is being told to do is just remember how to do things for later. Then it gets to the end and is told "okay, now that you know everything about how all the classes and methods are set up, go back and do this previously remembered thing witch will tell you what to do next". So it does and it leads into a chain and a loop, each time the loop runs it says to go update all these things.

 

For some reason, most people completely and utterly fail to understand this. I think it's because most people who do just assume it's obvious and never explain it. But I see way to many people try and do silly things like try and call something to set up infinite loops to run something every frame, and it just doesn't work like that. Well, actually, astonishingly there are some scripting languages which seem to delay script calls in such a way that it actually can do that, and Ruby's fibers can be used to that effect (and in fact are in Game_Interpreter) but those are special setups that are designed to be able to do that. The point is, that's not how scripting in RPG Maker VX Ace really works.

 

Most off it works through monkey patching though the use of aliases. See going back to the loop, the loop goes though and updates stuff by calling methods but you can sort of alter the methods it calls. It's like covertly cutting a wire and splicing in a wiretap or something. Or maybe damming a river and redirecting it is more apt given what I said about code being like a river. The details of the full loop aren't really important, but what is, is that you find a appropriate place to alter the loop and say "do this instead". Usually that place will be an object's "update" method but not always. The more you stipulate on the exact method the better. Then you "alias" it, give it a new name, and overwrite it and call the original, and bam, you just made your own new bypass for the raging river of code to flow into. And for that to work you pretty much have to read all of the default scripts very carefully and know just the right place to do it.

  • Like 1

Share this post


Link to post
Share on other sites

Yes. I guess I've got a LOT of work to do. But this has been EXTREMELY helpful and I thank you for the advice/mini tutorial. Practicd makes perfect I suppose.

Share this post


Link to post
Share on other sites

I like to help! Good luck! *sprinkles fairy dust on you*

  • Like 1

Share this post


Link to post
Share on other sites

I'm working on some animated trees to bring some life to my game maps with a more realistic enviroment.
Packing my maps with tons of events (one per tree) would surely ruin the game performance.
I would like to hear any other suggestions, to avoid eventing animated stuffs.
Any ideas on a good way to implement changes on the regular map update method?

Any script around there that already do something like that (cycle through map tileset frames)?
I'm not sure yet how many frames will the trees have (currently, with 11 frames, using some basic wind effect, my trees move in a rather unnatural way, but mostly due to the fact that I'm still learning my way on Blender...).

tree_zps38o4um4u.gif
*This sample tree and the others will be rendered on blender based on the great models available at http://yorik.uncreated.net/greenhouse.html

Edited by lukems

Share this post


Link to post
Share on other sites

Quick question, can't seem to figure this out even though it's probably super easy...

 

I've got a window in a scene (let's call it "@test_window = WindowTest.new", and I want the draw_text_ex that is displayed in that window to change based on a in-game variable (which the scene can change on the fly, that part already works). The problem is, the text won't update until I leave the scene and reload it.

 

I've tried to put in a @test_window.refresh call (the WindowTest class does has a refresh method), but it always returns an error, citing a NoMethod Error. Boggles my mind.

 

Any insights?

Share this post


Link to post
Share on other sites

Quick question, can't seem to figure this out even though it's probably super easy...

 

I've got a window in a scene (let's call it "@test_window = WindowTest.new", and I want the draw_text_ex that is displayed in that window to change based on a in-game variable (which the scene can change on the fly, that part already works). The problem is, the text won't update until I leave the scene and reload it.

 

I've tried to put in a @test_window.refresh call (the WindowTest class does has a refresh method), but it always returns an error, citing a NoMethod Error. Boggles my mind.

 

Any insights?

Can you show me the window class? If you inheritance it from Window_Base, it doesn't have refresh method.

Share this post


Link to post
Share on other sites

@lukems

With some clever coding/eventing, you could probably use Tsukihime's TileSwap script to achieve the effect you desire. I did something similar in VX,

for a Crypt of the Necrodancer - esque effect; albeit, with a script of my own, seeing as how Tsukihime's is for Ace.

 

@WCouillard

If you made your class with just

class WindowTest

it's because the refresh method doesn't exist in that class.

If you take a look at Window_Status from the default scripts, it has a refresh method that is called

two different times. Once, when the window is initialized, and again, whenever the current actor is set to

a different actor (first three methods).

Edited by ???nOBodY???

Share this post


Link to post
Share on other sites

 

I want the draw_text_ex that is displayed in that window to change based on a in-game variable (which the scene can change on the fly, that part already works). The problem is, the text won't update until I leave the scene and reload it.

 

So by this, do you mean you want an in-game variable to decide which method ("draw_text_ex" or "draw_text" or some other method) it uses to draw your text in the window? Or do you mean you want to your window to detect when the variable has changed and then redraw the text using the method "draw_text_ex"?

 

Are you sure the NoMethod error is referring to "refresh" and not another method called by "refresh"? And that you haven't mistyped the method name in either the call or the class? Either way, DrDhoom has a point - the only way for anyone to find the problem would be to take a look at the code you're using for both the call AND the class.

Share this post


Link to post
Share on other sites

It does inherit Window_Base, but I also gave the new class its own refresh method. Anyway... here is the Window class.

#==============================================================================
# â–  Window_SystemPreview
#==============================================================================

class Window_SystemPreview < Window_Base
  #--------------------------------------------------------------------------
  # initialize
  #--------------------------------------------------------------------------
  def initialize
    super(window_x, window_y, window_width, window_height)
    refresh
  end
  
  #--------------------------------------------------------------------------
  # window_x
  #--------------------------------------------------------------------------
  def window_x
    return Graphics.width - window_width - 24
  end
  
  #--------------------------------------------------------------------------
  # window_y
  #--------------------------------------------------------------------------
  def window_y
    return Graphics.height - window_height
  end
  
  #--------------------------------------------------------------------------
  # window_width
  #--------------------------------------------------------------------------
  def window_width
    return Graphics.width - 48
  end
  
  #--------------------------------------------------------------------------
  # window_height
  #--------------------------------------------------------------------------
  def window_height
    return 72
  end
    
  #--------------------------------------------------------------------------
  # refresh
  #--------------------------------------------------------------------------
  def refresh
    contents.clear
    preview_string
  end

  #--------------------------------------------------------------------------
  # preview_string: Changes preview text based on selected style
  #--------------------------------------------------------------------------
    def preview_string
      name = $game_variables[33]
      case name
       when 0
        text = 'Text here'
       when 1
        text = 'Text here 2'
       when 2
        text = '?'
       when 3
        text = '?'
       when 4
        text = '?'
       when 5
        text = '?'
       when 6
        text = '?'
       when 7
        text = '?'
       when 8
        text = '?'
       when 9
        text = '?'
       when 10
        text = '?'
       when 11
        text = '?'
       when 12
        text = '?'
      end
      draw_text_ex(0, 0, text)
    end
end # Window_SystemPreview

So, when the variable is changed during the scene, the windowskin is changed (this updates on the spot). I was hoping to add this window to the scene to give a description of each different windowskin. It updates the text, but only when you leave the scene and start it again.

 

All I added to the actual scene's code besides adding the window was...

@preview_window.refresh

And I put that in the method that changes the variable used in the above code, but it crashes.

Share this post


Link to post
Share on other sites

What is the full error? Especially the error class.

Edited by DrDhoom

Share this post


Link to post
Share on other sites
  #--------------------------------------------------------------------------
  # refresh_preview_window
  #--------------------------------------------------------------------------
  def refresh_preview_window
    @preview_window.refresh #WC
  end

  #--------------------------------------------------------------------------
  # change_custom_variables
  #--------------------------------------------------------------------------
  def change_custom_variables(direction)
    Sound.play_cursor
    value = direction == :left ? -1 : 1
    value *= 10 if Input.press?(:A)
    ext = current_ext
    var = YEA::SYSTEM::CUSTOM_VARIABLES[ext][0]
    minimum = YEA::SYSTEM::CUSTOM_VARIABLES[ext][4]
    maximum = YEA::SYSTEM::CUSTOM_VARIABLES[ext][5]
    $game_variables[var] += value
    $game_variables[var] = [[$game_variables[var], minimum].max, maximum].min
    draw_item(index)
    refresh_preview_window #WC
  end

This is the part of the YEA System Options scene where the user can change the variable up or down. I added in the method to refresh the preview window I created in here. It returns error for that last line citing a NoMethod error (undefined method refresh) even though I added a refresh method to that window class as you can see in my previous post. Really not sure why it's not working. Calling a window class' refresh method in the same exact way works in other situations for me.

 

~~~

So, in the time that I posted that last bit, I went in and gave something else a try.

 

I took the refresh_preview_window method and put it in the scene class instead of where it was, and called SceneManager.scene.refresh_preview_window at the end of the change_custom_variables method, and that worked just fine. :D

Share this post


Link to post
Share on other sites

Where did you put the method "refresh_preview_window"? Under Window_SystemOptions or its Scene class (which would be Scene_System in the script it came from)?

 

The "change_custom_variables" method is part of Window_SystemOptions and if you're putting "refresh_preview_window" just above it I don't see how that method would be callable from the Scene class.

 

On the other hand, if you shifted "refresh_preview_window" into the Scene class, then I ask where you put the @preview_window variable. Was it under Window_SystemOptions or Scene_System? Because if @preview_window was in Window_SystemOptions then you should be getting an error saying there's no method for @preview_window  (because @preview_window doesn't exist).

 

The only way I see this scenario making sense is if you put @preview_window under Scene_System and then tried to call "refresh" from a non-existent @preview_window variable in Window_SystemOptions (where it failed), and then shifted the call into the Scene, where you HAD setup an existing @preview_window. Is this what happened?

 

EDIT: Did the original error say the lack of a method was coming from a nil:NilClass?

Edited by Traverse

Share this post


Link to post
Share on other sites

Orginally, the line used to refresh the @preview_window (which was created in Scene_System) was in the Window_SystemOptions class, under the change_custom_variables method (which obviously didn't work). That returned a nil:NilClass error, yeah.

 

Once I put my refresh_preview_window method into the scene class (Scene_System) and used the other line (SceneManager.scene.refresh_preview_window) to call it from the change_custom_variables method, it all worked well.

Share this post


Link to post
Share on other sites

Yeah, that explains it. Always gotta remember to make sure that the call is done right, not just the code you're calling.

 

The general rule of thumb about Windows and Scenes is that it is the Scene that makes/calls the Windows and its methods. Windows generally don't call other Windows. The only exception I know of is Window_Message which calls the Gold, Key Items, Number Input and Choice windows.

Share this post


Link to post
Share on other sites

I'm working on some animated trees to bring some life to my game maps with a more realistic enviroment.

Packing my maps with tons of events (one per tree) would surely ruin the game performance.

I would like to hear any other suggestions, to avoid eventing animated stuffs.

Any ideas on a good way to implement changes on the regular map update method?

Any script around there that already do something like that (cycle through map tileset frames)?

I'm not sure yet how many frames will the trees have (currently, with 11 frames, using some basic wind effect, my trees move in a rather unnatural way, but mostly due to the fact that I'm still learning my way on Blender...).

tree_zps38o4um4u.gif

*This sample tree and the others will be rendered on blender based on the great models available at http://yorik.uncreated.net/greenhouse.html

I think the best way to do this might involve actually messing around with the tilemap's bitmaps in real time. It wouldn't be too hard to do really. Might be more complected if you had a lot of different animations you wanted to do with different numbers of frames and framerates. Works better to change the tileset bitmap then to fiddle around with swapping the tiles on the map around.

Edited by KilloZapit

Share this post


Link to post
Share on other sites

You could also make the trees an animated parallax of sorts,

and just change the parallax for the trees every couple frames or something.

Share this post


Link to post
Share on other sites

Though given how much memory and disk space animated parallax takes up, and how slow it would probably end up being...

Share this post


Link to post
Share on other sites

I am using the HD RGSS301.dll to allow me to run my game in 800 x 600.  This works fine until I make a change and save my project, at which time something is rewriting and reverting the RGSS301.dll back to it's default original state.  What is causing this?  I'd really like to continue and use the larger resoluiton but pasting the .dll in every time I test is tiresome.

 

Anyone have ideas what I can do to make it stop reverting back to the non HD .dll?

 

Actually, I think this needs it's own thread...

Edited by Wren

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

  • Recently Browsing   0 members

    No registered users viewing this page.

×
Top ArrowTop Arrow Highlighted