SLIP INTO RUBY - UNDER THE HOOD PART 14: SPRITESETS
In which we collect sprites together in neat little rows.
- Trihan
- 01/27/2017 02:55 PM
- 3186 views
Fans of sport! You join me on a most auspicious day: the day we finish sifting through the classes responsible for all the wonderful RPG things you see with your eye-stalks. It's time, yet again, for
Today we're going to round off the sprite class breakdown by looking at the three Spriteset classes. These combine sprites together into various effects: namely weather, the map, and battle displays. Let's do it.
Spriteset_Weather
This class is, as the name suggests, for weather effects. In VX Ace there are three kinds of weather: rain, storm, and snow. This spriteset is used in Spriteset_Map, and has four public instance variables:
We've got three attr_accessors: :type for the weather type, :ox for the x origin, and :oy for the y origin. We also have an attr_reader :power, which is the intensity of the effect.
The constructor takes a parameter viewport which defaults to nil. First, we set @viewport to the passed-in value. We call init_members, which initialises the member variables as we'll see shortly. We also call create_rain_bitmap, create_storm_bitmap and create_snow_bitmap, which creates the sprites for each effect.
The init_members method initialises instance variables. @type is set to :none, @ox, @oy and @power are set to 0, and @sprites is initialised as an empty array, which will hold the list of sprites used to achieve the effects.
The dispose method iterates through each element of @sprite with the iteration variable "sprite" and calls its dispose method. Then, @rain_bitmap, @storm_bitmap and @snow_bitmap are disposed to free up the memory their associated objects were occupying.
This method defines the first colour used for weather particles, and returns a new Color object with 255 on R, G and B (white) and 192 alpha, so it will be partially transparent.
This method defines the second colour used for weather particles, and returns a new Color objects with 255 on R, G and B (white) and 96 alpha, so it will be very transparent.
The method for creating a rain bitmap first sets @rain_bitmap to a new 7x42 Bitmap object. Then, we have a 7-iteration loop using the iteration variable "i" and calling fill_rect to draw a "raindrop" in the first particle colour. A drop in the rain effect is just 7 vertical 6-pixel lines which start at the top right, with each line being drawn 1 pixel further left than the one before it, ending at the bottom left. The result of each loop iteration is shown in the image below.
Creating a storm bitmap is pretty similar to rain, but the line is drawn slightly differently since the raindrops are angled more. The bitmap we create is 34x64, and our drawing loop is 32 iterations. The drop still starts at the top right and ends at the bottom left.
There are three calls to fill_rect per iteration, as storm drops are thicker than rain and we need to draw 3 small lines per "section". Each section consists of a vertical line of 2 pixels in the second particle colour, then a vertical line of 2 pixels in the first particle colour, then another vertical line of 2 pixels in the second colour. The result of this is shown below.
This method creates the bitmaps for the snow effect. Each snowflake is a 6x6 slightly shaded circle and is drawn via four calls to fill_rect. The process for this is shown below.
This method sets the intensity of the weather, and takes one parameter, power. First, @power is set to the passed-in value. Then, we call add_sprite a number of times equal to the maximum number of sprites minus the number we already have. Finally, we call remove_sprite a number of times equal to the number of sprites we have minus the maximum number. remove_sprite will probably never actually be called, since we'll only ever be adding as many sprites as it takes to reach the maximum anyway.
You may not remember from one of the previous articles, but this method is called by Game_Screen using an algorithm to gradually ramp up the power value proportional to the duration. That's why weather starts off with just a few particles and builds up to whatever power you chose on the slider.
This method determines the maximum number of sprites, and is currently hardcoded as @power multiplied by 10. In other words, each point of power on the slider will allow for an additional 10 weather particles, making the absolute maximum 90.
This method adds a particle sprite. Creates a new instance of Sprite passing in the spriteset's viewport, sets its opacity to 0, and pushes it to the @sprites array.
This method deletes a particle sprite. Removes and returns the last element of @sprites, storing it in the local variable "sprite", then calls its dispose method if it is not nil.
The frame update method calls update_screen, which we'll look at in a sec, and then iterates through each element of @sprites with the iteration variable "sprite", using it as an argument when calling update_sprite.
This method updates the screen, and simply sets the R, G and B values of the viewport's tone to the negative of the value returned by calling the dimness method, which we're about to look at.
This method gets the dimness for the screen's RGB values, and returns @power multiplied by 6 as an integer. Effectively this means that dimness will start at (-0, -0, -0) and decrease by 6 for every point of power until reaching (-54, -54, -54) at 9 power, which will result in the screen darkening slightly over time as the weather effect gets more intense.
The update_sprite method takes one parameter, "sprite". We set the sprite's ox to the ox of the spriteset, and the sprite's oy to the oy of the spriteset. Then we have a case statement for @type. When :rain, we call update_sprite_rain, passing in the sprite. When :storm, we do the same with update_sprite_storm. When :snow, we do the same with update_sprite_snow. Finally, we call create_new particle, passing in sprite, if the sprite's opacity is less than 64 (in other words, it's nearly disappeared).
This method updates rain sprites and takes one parameter, "sprite". Sets the sprite's bitmap to @rain_bitmap (which will essentially make it a 7x42 angled line), decrements its x coordinate by 1, adds 6 to its y, and reduces its opacity by 12. This means that every frame the raindrop will move 1 pixel left, 6 pixels downwards, and become slightly more transparent.
This method updates storm sprites and takes one parameter, "sprite". Sets the sprite's bitmap to @storm_bitmap (making it a 34x64 line), decrements its x coordinate by 3, adds 6 to its y, and reduces its opacity by 12. More or less the same as the rain sprite update except in this case we're moving 3 pixels to the left per frame instead of 1.
This method updates snow sprites and takes one parameter, "sprite". Sets the sprite's bitmap to @snow_bitmap (making it a 6x6 shaded circle), decrements its x coordinate by 1, adds 3 to its 6, and reduces its opacity by 12. This will cause it to move slowly left and slightly downwards, slower than rain or storm. Finally, we reduce opacity by 12.
This method creates a new particle and takes one parameter, "sprite". Sets the sprite's x coordinate to a random number between 0 and 100 more than the screen width, minus 100, plus @ox. Then sets the y coordinate to a random number between 0 and 200 more than the screen height, minus 200, plus @oy. This basically allows particles to start a bit off-screen. Opacity is set to 160 plus a random number between 0 and 96, giving a range of 160-255. This is why some raindrops appear more faint than others, and is what gives the weather a pseudo-3D effect.
Spriteset_Map
This class brings together all of the sprites you see on screen, the tilesets, the pictures, shadows, timers, parallax backgrounds...basically it's responsible for creating the entire appearance of each map. That's a lot of responsibility for one class, but hopefully once we're done you'll have a full understanding of everything it's doing behind the scenes.
As you should be used to seeing by now, the constructor for this class is essentially just a wrapper for calls to a bunch of other creation methods and the update method.
This method creates the 3 viewports that make up a map. When no argument is specified in the call to Viewport.new, as is the case here, its dimensions are the size of the screen. We set the z of @viewport2 to 50, and the z of @viewport3 to 100, meaning the viewports are "layered"; viewport1 is on the bottom, viewport2 in the middle, and viewport3 on top.
Note that the z coordinate of a viewport takes precedence over that of a sprite being displayed on that viewport, so even if you set the z coordinate of something in viewport3 to, say, 25, it'll still appear above everything in viewport2.
In the method for creating the Tilemap (a class containing all of the map data), we can see that it's using viewport1. Its map_data property, which is a 3-dimensional Table, is set to $game_map.data, which contains the data from the map's rvdata2 file. Finally, we call load_tileset, which we'll look at now.
The method for loading a tileset is essentially just plugging values into instance variables. @tileset is set to the tileset property of $game_map, which if you'll remember from that lesson returns $data_tilesets[@tileset_id].
We iterate through the tileset_names property with an index, using the iteration variable "name" and index variable "i". In each iteration, we set the bitmaps property of the element in tilemap with index i to the cached tileset with a name corresponding to that of the current tileset.
Essentially this goes through the various tileset graphics from the database (A1, A2, A3, A4, A5, B, C, D and E) and loads up the graphic files you chose.
Following this each loop, we set the flags property of @tilemap to the flags property of @tileset. Flags denote passability, ladder tile, bush tile, damaging floor, terrain tag etc. and the possible values are outlined in the help file.
This method creates the canvas for a parallax background, by creating a new Plane on viewport1. As per the help file, Planes are special sprites which tile across the entire screen. Its z is set to -100 so that it will appear below the tilemap.
This method creates the character sprites that represent the player, followers, and events.
First, @character_sprites is initialised as an empty array.
We iterate through each value in the events hash of $game_map, with the iteration variable "event" and in this loop we push a new instance of Sprite_Character to the @character_sprites array, passing in @viewport1 and the event value (this is an instance of Game_Event). We do the same with the vehicles property, which creates the sprites for the boat, ship and airship. There's another each loop for followers, but this one pushes them in reverse order so that followers closer to the player will appear on top (if we didn't have this, because the z coordinate of the "last" party member would be higher than the others, they would appear on top, causing the follower display to look weird). The last sprite we push to the array is, of course, $game_player. Finally, @map_id is set to the map_id property of $game_map.
This method creates the shadow for the airship.
First, we create a new Sprite in @viewport1 and assign it to @shadow_sprite. We set its bitmap property to the Cached system graphic called "Shadow", and set its origin to bottom centre. Its z coordinate is set to 180, meaning it will appear above everything else in viewport1.
This method creates the spriteset for the weather, using @viewport2. This means that weather effects will appear above the tiles and characters.
This method creates the picture sprites, or rather it initialises @picture_sprites as an empty array. The actual creation is done in the picture update method, as we'll see later.
This method creates the sprite for the in-game timer on @viewport2, meaning it appears above tiles and characters.
The dispose method for the spriteset is simply a wrapper for calls to the methods that dispose of everything else.
Disposes the tilemap object and frees up the memory from it.
First disposes the parallax bitmap if one exists, then disposes the parallax object.
Disposes characters by iterating through each element of @character_sprites with "sprite" and calling its dispose method.
Disposes the airship shadow sprite.
Disposes weather effects.
This method disposes of the game's pictures. Iterates through each element of @picture_sprites (.compact removes nil elements) and disposes it.
This method disposes the timer sprite.
This method disposes the three viewports.
This method refreshes characters, by first disposing them and then creating them again.
The frame update method is, as usual, a wrapper for calls to other update methods.
This method updates the tileset. If @tileset is different from that of $game_map, we call load_tileset and refresh_characters. That's about it really.
This method updates the tilemap (not to be confused with the tileset). We set @tilemap's map_data property to that of $game_map, its ox to the map's display x coordinate multiplied by 32, the same for oy and the y coordinate, and then call update on the tilemap. Updating the origins is what allows the map to "scroll" as the player moves; without updating these values, the characters would appear to be walking but the tiles would stay in place. As per the help file, calling the update method updates autotile animations and the like.
This method updates the parallax background.
If the parallax name is different from the one in $game_map, we update its value. If the parallax has a bitmap, we dispose it, then we get the named parallax from Cache and assign it to the bitmap. We call the frame_reset method of Graphics to reset game refresh timing.
Whether the name has changed or not, we update the ox and oy properties of the parallax to those of $game_map, passing in the bitmap as an argument; this updates the position of the background appropriately.
This method updates characters. Calls refresh_characters if the map ID has changed from the one in $game_map, then iterates through each element of @character_sprites and calls its update method.
This method updates the airship's shadow.
The local variable airship is set to the airship property of $game_map, then its x is set to the screen x of the airship. Its y is set to the airship's screen y plus the airship's altitude (so that the shadow moves down at the same rate as the airship moves up, or in other words stays still as the airship is taking off). Its opacity is set to the altitude multiplied by 8, so the higher the airship is the fainter the shadow. Finally, we call the update method on the sprite.
This method updates weather effects.
The type and power properties of @weather are set to the same values in $game_map.screen. Its ox and oy are set to 32 times their display values from $game_map, then we call @weather's update method.
This method updates the picture sprites. We iterate through each picture in $game_map.screen with "pic" then return either the element of @picture_sprites with the index of the picture's number, or a new instance of Sprite_Picture passing in @viewport2 and pic. ||= is shorthand for "return the object on the left if it exists or the object on the right otherwise". Then we update the element.
This method updates the timer sprite, and simply calls the update method of @timer_sprite.
This method updates the viewports. @viewport1's tone is set to that of $game_map.screen, and its ox is set to the shake property of $game_map.screen (which is what actually shakes the screen in the first place. Without this, all the other stuff related to screen shake does literally nothing). @viewport2 has its colour set to the flash_color property of $game_map.screen, @viewport3 has its colour set to black with an alpha equal to 255 minus the screen brightness, then all three viewports are updated (viewport 3 is used for fade in and fade out effects).
Spriteset_Battle
This class deals with all the sprites used in battle, and is used, funnily enough, in Scene_Battle.
The constructor is just your standard wrapper for calls to methods that create the various objects, and then a call to update.
As with the map, we create 3 viewports, with the second one at z 50 and the third at z 100.
This method creates the first battle background (floor). We set @back1_sprite to a new instance of Sprite passing in viewport 1, and set its bitmap to the result of calling battleback1_bitmap, which we'll see shortly. Its z is set to 0 so it appears on the bottom, and finally we call center_sprite passing in the new sprite as an argument.
This method creates the second battle background (wall). Pretty much identical to the method above except we set z to 1 instead of 0, so the walls appear above the floor.
This method gets the bitmap for the floor background. If battleback1_name doesn't return nil, we return battleback1 from the Cache, passing in the battleback's filename. Otherwise, we call create_blurry_background_bitmap (basically, if a battle background floor hasn't been set, one will be created as a blurry view of the current map).
This method gets the bitmap for the wall background. More or less the same as above, but in the case that battleback2_name returns nil, we create a new 1x1 Bitmap.
def create_blurry_background_bitmap
source = SceneManager.background_bitmap
bitmap = Bitmap.new(640, 480)
bitmap.stretch_blt(bitmap.rect, source, source.rect)
bitmap.radial_blur(120, 16)
bitmap
end
This method creates a battle background bitmap as a blurry copy of the map the player is on. Sets a local variable called source to the return value of the background_bitmap method in SceneManager, creates a new 640x480 Bitmap, performed a stretched block transfer into the rect of the bitmap from the rect of the source (essentially, this copies a snapshot of the map into the new 640x480 canvas) then performs a radial blur on it with angle 120 degrees and division 16 (the exact nuances of radial blur are beyond the scope of this series, but suffice to say this makes a kind of circular blurry version of the map that ends up looking a bit like the view from a kaleidoscope). Finally, we return the bitmap.
This method will be called if the player is on a non-overworld map and didn't specify a battleback in the map settings.
This method gets the filename of the battle background being used as the floor. If we're in a test battle, we return battleback 1 from $data_system (basically, whatever background was chosen in the test battle dialog). If we're not, and the battleback1_name property of $game_map returns a value, we return that value. Otherwise, if field type is overworld (tileset mode has been set to 0), we return the result of calling overworld_battleback1_name.
This method does exactly the same thing as the previous method, but for the wall background.
This method gets the filename of the battleback used on the floor in the overworld. If the player is riding a vehicle, we return the result of calling ship_battleback1_name, otherwise we return the result of calling normal_battleback1_name.
Exactly the same but for battleback2 (wall).
This method gets the filename of the normal battleback used on the floor. Returns either the result of calling terrain_battleback1_name passing in autotile_type(1), terrain_battleback1_name passing in autotile_type(0), or default_battleback1_name (subsequent calls will be made if the previous one returned false or nil).
Exactly the same but for battleback2 (wall).
This method gets the filename of a floor background based on terrain, and takes one parameter, type.
We have a case statement for type, which returns the string corresponding to the terrain represented by the types in each case, which are just tile IDs from the "World_A1" tileset. If you look at the tiles in the editor and look at tiles 4 and 5 for example (bearing in mind it's 0-indexed) you'll see that those tiles do indeed look like poisonous swamp.
Because these values are hardcoded, if you ever use a different tileset for A1 with differing autotiles or autotiles in different places you'll have to update this method accordingly, or they won't match up.
Same thing as before but with walls.
The calls to these two methods will result in a somewhat-dynamic battle background that matches as closely as possible the terrain of the tile the player is on when a battle occurs.
This method gets the filename of the default floor battle background and is hardcoded to return "Grassland" meaning any tile that doesn't have another associated background will use it.
Same thing for walls.
This method gets the floor battle background when on a vehicle, and is hardcoded to return "Ship".
Same for the wall background.
This method gets the type of the autotile the player is standing on, and returns the result of calling $game_map's autotile_type method, passing in the player's x and y, and the passed-in z value. From the calls to the method from methods we looked at above, this means z will either be 1 or 0. We looked at this method of $game_map in the Game_Map episode, if you remember.
This method moves a sprite to the centre of the screen, and takes one parameter, sprite, which is the sprite object to move. Its ox and oy are set to half the sprite's source bitmap's width and height, and its x/y are set to half the width and height of the screen.
This method creates the enemy sprites. We iterate through a reverse collect on members from $game_troop, with the block creating a new Sprite_Battler passing in @viewport1 and the current enemy object, and assign the returned array of sprites to @enemy_sprites.
This method creates actor sprites. By default in VX Ace actors are not actually displayed, but in order to treat enemies and allies the same in code dummy sprites are created for them.
Pretty simple really. @actor_sprites is set to a new 4-element Array, with each element initialised as a new instance of Sprite_Battler passing in @viewport1.
This method creates the initial state for picture sprites. As with Spriteset_Map, it's created as an empty array and will be populated in the update method.
This method creates the timer sprite in viewport 2, same as on the map spriteset.
The main dispose method is just a wrapper for calls to other dispose methods.
This method disposes the floor background. Disposes the sprite's bitmap if one is set, then disposes the sprite object to free up its memory.
Same thing for the wall background.
This method disposes enemy sprites. Iterates through each element of @enemy_sprites with "sprite" and calls its dispose method.
Same thing but for the actor sprites.
Same thing but for the picture sprites. Note the call to compact before each to remove nil elements.
This method disposes the timer sprite and just calls dispose on @timer_sprite.
This method calls dispose for the 3 viewports.
The frame update method is a wrapper for the calls to the other update methods.
This method updates the floor background sprite by calling the update method of @back1_sprite.
Same thing for the wall background sprite.
This method updates enemy sprites by iterating through each element of @enemy_sprites and calling its update method.
This method updates the actor sprites by iterating through each element of @actor_sprites with an index, then in the block setting the sprite's battler property to the party member with index i and calling the sprite's update method (if you'll recall, the update method of Sprite_Battler sets the bitmap property to nil if there's no associated battler, which is why we have to set one here first. I'm honestly not sure why this wasn't done by iterating through the party when creating the sprites in the first place, as with the enemies. It's not like the actor sprites actually do anything by default).
This method updates the pictures by iterating through each element of the pictures array of the screen property of $game_troop with "pic". In the block, we either get the element of @picture_sprites with an index of the picture's number, or a new instance of Sprite_Picture passing in @viewport2 and pic. Then we call the sprite's update method.
This method updates the timer sprite by calling the update method of @timer_sprite. The obvious explanations are starting to look silly, but I want to make sure I never completely lose people regardless of their programming knowledge so I keep pointing them out.
The viewport update method is identical to the one from Spriteset_Map with the exception that we're using the screen property of $game_troop instead of $game_map.
This method gets all of the battler sprites by adding the @enemy_sprites and @actor_sprites arrays together into one larger array.
This method determines whether an animation is being displayed. Returns true if any of the elements in battler_sprites return true when their animation? method is called, false otherwise.
Same thing but for effects.
And that's it! The classes and methods we've looked at over the past three or so articles comprise absolutely everything RPG Maker uses to make stuff appear on the screen, with the exception of the absolute baseline stuff in built-in classes like Bitmap and Sprite. Coming up next, we'll be breaking down the Window classes.
As always, comments are welcome.
Until next time.
Today we're going to round off the sprite class breakdown by looking at the three Spriteset classes. These combine sprites together into various effects: namely weather, the map, and battle displays. Let's do it.
Spriteset_Weather
This class is, as the name suggests, for weather effects. In VX Ace there are three kinds of weather: rain, storm, and snow. This spriteset is used in Spriteset_Map, and has four public instance variables:
attr_accessor :type # Weather type attr_accessor :ox # X coordinate of origin attr_accessor :oy # Y coordinate of orgin attr_reader :power # Intensity
We've got three attr_accessors: :type for the weather type, :ox for the x origin, and :oy for the y origin. We also have an attr_reader :power, which is the intensity of the effect.
def initialize(viewport = nil) @viewport = viewport init_members create_rain_bitmap create_storm_bitmap create_snow_bitmap end
The constructor takes a parameter viewport which defaults to nil. First, we set @viewport to the passed-in value. We call init_members, which initialises the member variables as we'll see shortly. We also call create_rain_bitmap, create_storm_bitmap and create_snow_bitmap, which creates the sprites for each effect.
def init_members @type = :none @ox = 0 @oy = 0 @power = 0 @sprites = [] end
The init_members method initialises instance variables. @type is set to :none, @ox, @oy and @power are set to 0, and @sprites is initialised as an empty array, which will hold the list of sprites used to achieve the effects.
def dispose @sprites.each {|sprite| sprite.dispose } @rain_bitmap.dispose @storm_bitmap.dispose @snow_bitmap.dispose end
The dispose method iterates through each element of @sprite with the iteration variable "sprite" and calls its dispose method. Then, @rain_bitmap, @storm_bitmap and @snow_bitmap are disposed to free up the memory their associated objects were occupying.
def particle_color1 Color.new(255, 255, 255, 192) end
This method defines the first colour used for weather particles, and returns a new Color object with 255 on R, G and B (white) and 192 alpha, so it will be partially transparent.
def particle_color2 Color.new(255, 255, 255, 96) end
This method defines the second colour used for weather particles, and returns a new Color objects with 255 on R, G and B (white) and 96 alpha, so it will be very transparent.
def create_rain_bitmap @rain_bitmap = Bitmap.new(7, 42) 7.times {|i| @rain_bitmap.fill_rect(6-i, i*6, 1, 6, particle_color1) } end
The method for creating a rain bitmap first sets @rain_bitmap to a new 7x42 Bitmap object. Then, we have a 7-iteration loop using the iteration variable "i" and calling fill_rect to draw a "raindrop" in the first particle colour. A drop in the rain effect is just 7 vertical 6-pixel lines which start at the top right, with each line being drawn 1 pixel further left than the one before it, ending at the bottom left. The result of each loop iteration is shown in the image below.
def create_storm_bitmap @storm_bitmap = Bitmap.new(34, 64) 32.times do |i| @storm_bitmap.fill_rect(33-i, i*2, 1, 2, particle_color2) @storm_bitmap.fill_rect(32-i, i*2, 1, 2, particle_color1) @storm_bitmap.fill_rect(31-i, i*2, 1, 2, particle_color2) end end
Creating a storm bitmap is pretty similar to rain, but the line is drawn slightly differently since the raindrops are angled more. The bitmap we create is 34x64, and our drawing loop is 32 iterations. The drop still starts at the top right and ends at the bottom left.
There are three calls to fill_rect per iteration, as storm drops are thicker than rain and we need to draw 3 small lines per "section". Each section consists of a vertical line of 2 pixels in the second particle colour, then a vertical line of 2 pixels in the first particle colour, then another vertical line of 2 pixels in the second colour. The result of this is shown below.
def create_snow_bitmap @snow_bitmap = Bitmap.new(6, 6) @snow_bitmap.fill_rect(0, 1, 6, 4, particle_color2) @snow_bitmap.fill_rect(1, 0, 4, 6, particle_color2) @snow_bitmap.fill_rect(1, 2, 4, 2, particle_color1) @snow_bitmap.fill_rect(2, 1, 2, 4, particle_color1) end
This method creates the bitmaps for the snow effect. Each snowflake is a 6x6 slightly shaded circle and is drawn via four calls to fill_rect. The process for this is shown below.
def power=(power) @power = power (sprite_max - @sprites.size).times { add_sprite } (@sprites.size - sprite_max).times { remove_sprite } end
This method sets the intensity of the weather, and takes one parameter, power. First, @power is set to the passed-in value. Then, we call add_sprite a number of times equal to the maximum number of sprites minus the number we already have. Finally, we call remove_sprite a number of times equal to the number of sprites we have minus the maximum number. remove_sprite will probably never actually be called, since we'll only ever be adding as many sprites as it takes to reach the maximum anyway.
You may not remember from one of the previous articles, but this method is called by Game_Screen using an algorithm to gradually ramp up the power value proportional to the duration. That's why weather starts off with just a few particles and builds up to whatever power you chose on the slider.
def sprite_max (@power * 10).to_i end
This method determines the maximum number of sprites, and is currently hardcoded as @power multiplied by 10. In other words, each point of power on the slider will allow for an additional 10 weather particles, making the absolute maximum 90.
def add_sprite sprite = Sprite.new(@viewport) sprite.opacity = 0 @sprites.push(sprite) end
This method adds a particle sprite. Creates a new instance of Sprite passing in the spriteset's viewport, sets its opacity to 0, and pushes it to the @sprites array.
def remove_sprite sprite = @sprites.pop sprite.dispose if sprite end
This method deletes a particle sprite. Removes and returns the last element of @sprites, storing it in the local variable "sprite", then calls its dispose method if it is not nil.
def update update_screen @sprites.each {|sprite| update_sprite(sprite) } end
The frame update method calls update_screen, which we'll look at in a sec, and then iterates through each element of @sprites with the iteration variable "sprite", using it as an argument when calling update_sprite.
def update_screen @viewport.tone.set(-dimness, -dimness, -dimness) end
This method updates the screen, and simply sets the R, G and B values of the viewport's tone to the negative of the value returned by calling the dimness method, which we're about to look at.
def dimness (@power * 6).to_i end
This method gets the dimness for the screen's RGB values, and returns @power multiplied by 6 as an integer. Effectively this means that dimness will start at (-0, -0, -0) and decrease by 6 for every point of power until reaching (-54, -54, -54) at 9 power, which will result in the screen darkening slightly over time as the weather effect gets more intense.
def update_sprite(sprite) sprite.ox = @ox sprite.oy = @oy case @type when :rain update_sprite_rain(sprite) when :storm update_sprite_storm(sprite) when :snow update_sprite_snow(sprite) end create_new_particle(sprite) if sprite.opacity < 64 end
The update_sprite method takes one parameter, "sprite". We set the sprite's ox to the ox of the spriteset, and the sprite's oy to the oy of the spriteset. Then we have a case statement for @type. When :rain, we call update_sprite_rain, passing in the sprite. When :storm, we do the same with update_sprite_storm. When :snow, we do the same with update_sprite_snow. Finally, we call create_new particle, passing in sprite, if the sprite's opacity is less than 64 (in other words, it's nearly disappeared).
def update_sprite_rain(sprite) sprite.bitmap = @rain_bitmap sprite.x -= 1 sprite.y += 6 sprite.opacity -= 12 end
This method updates rain sprites and takes one parameter, "sprite". Sets the sprite's bitmap to @rain_bitmap (which will essentially make it a 7x42 angled line), decrements its x coordinate by 1, adds 6 to its y, and reduces its opacity by 12. This means that every frame the raindrop will move 1 pixel left, 6 pixels downwards, and become slightly more transparent.
def update_sprite_storm(sprite) sprite.bitmap = @storm_bitmap sprite.x -= 3 sprite.y += 6 sprite.opacity -= 12 end
This method updates storm sprites and takes one parameter, "sprite". Sets the sprite's bitmap to @storm_bitmap (making it a 34x64 line), decrements its x coordinate by 3, adds 6 to its y, and reduces its opacity by 12. More or less the same as the rain sprite update except in this case we're moving 3 pixels to the left per frame instead of 1.
def update_sprite_snow(sprite) sprite.bitmap = @snow_bitmap sprite.x -= 1 sprite.y += 3 sprite.opacity -= 12 end
This method updates snow sprites and takes one parameter, "sprite". Sets the sprite's bitmap to @snow_bitmap (making it a 6x6 shaded circle), decrements its x coordinate by 1, adds 3 to its 6, and reduces its opacity by 12. This will cause it to move slowly left and slightly downwards, slower than rain or storm. Finally, we reduce opacity by 12.
def create_new_particle(sprite) sprite.x = rand(Graphics.width + 100) - 100 + @ox sprite.y = rand(Graphics.height + 200) - 200 + @oy sprite.opacity = 160 + rand(96) end
This method creates a new particle and takes one parameter, "sprite". Sets the sprite's x coordinate to a random number between 0 and 100 more than the screen width, minus 100, plus @ox. Then sets the y coordinate to a random number between 0 and 200 more than the screen height, minus 200, plus @oy. This basically allows particles to start a bit off-screen. Opacity is set to 160 plus a random number between 0 and 96, giving a range of 160-255. This is why some raindrops appear more faint than others, and is what gives the weather a pseudo-3D effect.
Spriteset_Map
This class brings together all of the sprites you see on screen, the tilesets, the pictures, shadows, timers, parallax backgrounds...basically it's responsible for creating the entire appearance of each map. That's a lot of responsibility for one class, but hopefully once we're done you'll have a full understanding of everything it's doing behind the scenes.
def initialize create_viewports create_tilemap create_parallax create_characters create_shadow create_weather create_pictures create_timer update end
As you should be used to seeing by now, the constructor for this class is essentially just a wrapper for calls to a bunch of other creation methods and the update method.
def create_viewports @viewport1 = Viewport.new @viewport2 = Viewport.new @viewport3 = Viewport.new @viewport2.z = 50 @viewport3.z = 100 end
This method creates the 3 viewports that make up a map. When no argument is specified in the call to Viewport.new, as is the case here, its dimensions are the size of the screen. We set the z of @viewport2 to 50, and the z of @viewport3 to 100, meaning the viewports are "layered"; viewport1 is on the bottom, viewport2 in the middle, and viewport3 on top.
Note that the z coordinate of a viewport takes precedence over that of a sprite being displayed on that viewport, so even if you set the z coordinate of something in viewport3 to, say, 25, it'll still appear above everything in viewport2.
def create_tilemap @tilemap = Tilemap.new(@viewport1) @tilemap.map_data = $game_map.data load_tileset end
In the method for creating the Tilemap (a class containing all of the map data), we can see that it's using viewport1. Its map_data property, which is a 3-dimensional Table, is set to $game_map.data, which contains the data from the map's rvdata2 file. Finally, we call load_tileset, which we'll look at now.
def load_tileset @tileset = $game_map.tileset @tileset.tileset_names.each_with_index do |name, i| @tilemap.bitmaps[i] = Cache.tileset(name) end @tilemap.flags = @tileset.flags end
The method for loading a tileset is essentially just plugging values into instance variables. @tileset is set to the tileset property of $game_map, which if you'll remember from that lesson returns $data_tilesets[@tileset_id].
We iterate through the tileset_names property with an index, using the iteration variable "name" and index variable "i". In each iteration, we set the bitmaps property of the element in tilemap with index i to the cached tileset with a name corresponding to that of the current tileset.
Essentially this goes through the various tileset graphics from the database (A1, A2, A3, A4, A5, B, C, D and E) and loads up the graphic files you chose.
Following this each loop, we set the flags property of @tilemap to the flags property of @tileset. Flags denote passability, ladder tile, bush tile, damaging floor, terrain tag etc. and the possible values are outlined in the help file.
def create_parallax @parallax = Plane.new(@viewport1) @parallax.z = -100 end
This method creates the canvas for a parallax background, by creating a new Plane on viewport1. As per the help file, Planes are special sprites which tile across the entire screen. Its z is set to -100 so that it will appear below the tilemap.
def create_characters @character_sprites = [] $game_map.events.values.each do |event| @character_sprites.push(Sprite_Character.new(@viewport1, event)) end $game_map.vehicles.each do |vehicle| @character_sprites.push(Sprite_Character.new(@viewport1, vehicle)) end $game_player.followers.reverse_each do |follower| @character_sprites.push(Sprite_Character.new(@viewport1, follower)) end @character_sprites.push(Sprite_Character.new(@viewport1, $game_player)) @map_id = $game_map.map_id end
This method creates the character sprites that represent the player, followers, and events.
First, @character_sprites is initialised as an empty array.
We iterate through each value in the events hash of $game_map, with the iteration variable "event" and in this loop we push a new instance of Sprite_Character to the @character_sprites array, passing in @viewport1 and the event value (this is an instance of Game_Event). We do the same with the vehicles property, which creates the sprites for the boat, ship and airship. There's another each loop for followers, but this one pushes them in reverse order so that followers closer to the player will appear on top (if we didn't have this, because the z coordinate of the "last" party member would be higher than the others, they would appear on top, causing the follower display to look weird). The last sprite we push to the array is, of course, $game_player. Finally, @map_id is set to the map_id property of $game_map.
def create_shadow @shadow_sprite = Sprite.new(@viewport1) @shadow_sprite.bitmap = Cache.system("Shadow") @shadow_sprite.ox = @shadow_sprite.bitmap.width / 2 @shadow_sprite.oy = @shadow_sprite.bitmap.height @shadow_sprite.z = 180 end
This method creates the shadow for the airship.
First, we create a new Sprite in @viewport1 and assign it to @shadow_sprite. We set its bitmap property to the Cached system graphic called "Shadow", and set its origin to bottom centre. Its z coordinate is set to 180, meaning it will appear above everything else in viewport1.
def create_weather @weather = Spriteset_Weather.new(@viewport2) end
This method creates the spriteset for the weather, using @viewport2. This means that weather effects will appear above the tiles and characters.
def create_pictures @picture_sprites = [] end
This method creates the picture sprites, or rather it initialises @picture_sprites as an empty array. The actual creation is done in the picture update method, as we'll see later.
def create_timer @timer_sprite = Sprite_Timer.new(@viewport2) end
This method creates the sprite for the in-game timer on @viewport2, meaning it appears above tiles and characters.
def dispose dispose_tilemap dispose_parallax dispose_characters dispose_shadow dispose_weather dispose_pictures dispose_timer dispose_viewports end
The dispose method for the spriteset is simply a wrapper for calls to the methods that dispose of everything else.
def dispose_tilemap @tilemap.dispose end
Disposes the tilemap object and frees up the memory from it.
def dispose_parallax @parallax.bitmap.dispose if @parallax.bitmap @parallax.dispose end
First disposes the parallax bitmap if one exists, then disposes the parallax object.
def dispose_characters @character_sprites.each {|sprite| sprite.dispose } end
Disposes characters by iterating through each element of @character_sprites with "sprite" and calling its dispose method.
def dispose_shadow @shadow_sprite.dispose end
Disposes the airship shadow sprite.
def dispose_weather @weather.dispose end
Disposes weather effects.
def dispose_pictures @picture_sprites.compact.each {|sprite| sprite.dispose } end
This method disposes of the game's pictures. Iterates through each element of @picture_sprites (.compact removes nil elements) and disposes it.
def dispose_timer @timer_sprite.dispose end
This method disposes the timer sprite.
def dispose_viewports @viewport1.dispose @viewport2.dispose @viewport3.dispose end
This method disposes the three viewports.
def refresh_characters dispose_characters create_characters end
This method refreshes characters, by first disposing them and then creating them again.
def update update_tileset update_tilemap update_parallax update_characters update_shadow update_weather update_pictures update_timer update_viewports end
The frame update method is, as usual, a wrapper for calls to other update methods.
def update_tileset if @tileset != $game_map.tileset load_tileset refresh_characters end end
This method updates the tileset. If @tileset is different from that of $game_map, we call load_tileset and refresh_characters. That's about it really.
def update_tilemap @tilemap.map_data = $game_map.data @tilemap.ox = $game_map.display_x * 32 @tilemap.oy = $game_map.display_y * 32 @tilemap.update end
This method updates the tilemap (not to be confused with the tileset). We set @tilemap's map_data property to that of $game_map, its ox to the map's display x coordinate multiplied by 32, the same for oy and the y coordinate, and then call update on the tilemap. Updating the origins is what allows the map to "scroll" as the player moves; without updating these values, the characters would appear to be walking but the tiles would stay in place. As per the help file, calling the update method updates autotile animations and the like.
def update_parallax if @parallax_name != $game_map.parallax_name @parallax_name = $game_map.parallax_name @parallax.bitmap.dispose if @parallax.bitmap @parallax.bitmap = Cache.parallax(@parallax_name) Graphics.frame_reset end @parallax.ox = $game_map.parallax_ox(@parallax.bitmap) @parallax.oy = $game_map.parallax_oy(@parallax.bitmap) end
This method updates the parallax background.
If the parallax name is different from the one in $game_map, we update its value. If the parallax has a bitmap, we dispose it, then we get the named parallax from Cache and assign it to the bitmap. We call the frame_reset method of Graphics to reset game refresh timing.
Whether the name has changed or not, we update the ox and oy properties of the parallax to those of $game_map, passing in the bitmap as an argument; this updates the position of the background appropriately.
def update_characters refresh_characters if @map_id != $game_map.map_id @character_sprites.each {|sprite| sprite.update } end
This method updates characters. Calls refresh_characters if the map ID has changed from the one in $game_map, then iterates through each element of @character_sprites and calls its update method.
def update_shadow airship = $game_map.airship @shadow_sprite.x = airship.screen_x @shadow_sprite.y = airship.screen_y + airship.altitude @shadow_sprite.opacity = airship.altitude * 8 @shadow_sprite.update end
This method updates the airship's shadow.
The local variable airship is set to the airship property of $game_map, then its x is set to the screen x of the airship. Its y is set to the airship's screen y plus the airship's altitude (so that the shadow moves down at the same rate as the airship moves up, or in other words stays still as the airship is taking off). Its opacity is set to the altitude multiplied by 8, so the higher the airship is the fainter the shadow. Finally, we call the update method on the sprite.
def update_weather @weather.type = $game_map.screen.weather_type @weather.power = $game_map.screen.weather_power @weather.ox = $game_map.display_x * 32 @weather.oy = $game_map.display_y * 32 @weather.update end
This method updates weather effects.
The type and power properties of @weather are set to the same values in $game_map.screen. Its ox and oy are set to 32 times their display values from $game_map, then we call @weather's update method.
def update_pictures $game_map.screen.pictures.each do |pic| @picture_sprites[pic.number] ||= Sprite_Picture.new(@viewport2, pic) @picture_sprites[pic.number].update end end
This method updates the picture sprites. We iterate through each picture in $game_map.screen with "pic" then return either the element of @picture_sprites with the index of the picture's number, or a new instance of Sprite_Picture passing in @viewport2 and pic. ||= is shorthand for "return the object on the left if it exists or the object on the right otherwise". Then we update the element.
def update_timer @timer_sprite.update end
This method updates the timer sprite, and simply calls the update method of @timer_sprite.
def update_viewports @viewport1.tone.set($game_map.screen.tone) @viewport1.ox = $game_map.screen.shake @viewport2.color.set($game_map.screen.flash_color) @viewport3.color.set(0, 0, 0, 255 - $game_map.screen.brightness) @viewport1.update @viewport2.update @viewport3.update end
This method updates the viewports. @viewport1's tone is set to that of $game_map.screen, and its ox is set to the shake property of $game_map.screen (which is what actually shakes the screen in the first place. Without this, all the other stuff related to screen shake does literally nothing). @viewport2 has its colour set to the flash_color property of $game_map.screen, @viewport3 has its colour set to black with an alpha equal to 255 minus the screen brightness, then all three viewports are updated (viewport 3 is used for fade in and fade out effects).
Spriteset_Battle
This class deals with all the sprites used in battle, and is used, funnily enough, in Scene_Battle.
def initialize create_viewports create_battleback1 create_battleback2 create_enemies create_actors create_pictures create_timer update end
The constructor is just your standard wrapper for calls to methods that create the various objects, and then a call to update.
def create_viewports @viewport1 = Viewport.new @viewport2 = Viewport.new @viewport3 = Viewport.new @viewport2.z = 50 @viewport3.z = 100 end
As with the map, we create 3 viewports, with the second one at z 50 and the third at z 100.
def create_battleback1 @back1_sprite = Sprite.new(@viewport1) @back1_sprite.bitmap = battleback1_bitmap @back1_sprite.z = 0 center_sprite(@back1_sprite) end
This method creates the first battle background (floor). We set @back1_sprite to a new instance of Sprite passing in viewport 1, and set its bitmap to the result of calling battleback1_bitmap, which we'll see shortly. Its z is set to 0 so it appears on the bottom, and finally we call center_sprite passing in the new sprite as an argument.
def create_battleback2 @back2_sprite = Sprite.new(@viewport1) @back2_sprite.bitmap = battleback2_bitmap @back2_sprite.z = 1 center_sprite(@back2_sprite) end
This method creates the second battle background (wall). Pretty much identical to the method above except we set z to 1 instead of 0, so the walls appear above the floor.
def battleback1_bitmap if battleback1_name Cache.battleback1(battleback1_name) else create_blurry_background_bitmap end end
This method gets the bitmap for the floor background. If battleback1_name doesn't return nil, we return battleback1 from the Cache, passing in the battleback's filename. Otherwise, we call create_blurry_background_bitmap (basically, if a battle background floor hasn't been set, one will be created as a blurry view of the current map).
def battleback2_bitmap if battleback2_name Cache.battleback2(battleback2_name) else Bitmap.new(1, 1) end end
This method gets the bitmap for the wall background. More or less the same as above, but in the case that battleback2_name returns nil, we create a new 1x1 Bitmap.
def create_blurry_background_bitmap
source = SceneManager.background_bitmap
bitmap = Bitmap.new(640, 480)
bitmap.stretch_blt(bitmap.rect, source, source.rect)
bitmap.radial_blur(120, 16)
bitmap
end
This method creates a battle background bitmap as a blurry copy of the map the player is on. Sets a local variable called source to the return value of the background_bitmap method in SceneManager, creates a new 640x480 Bitmap, performed a stretched block transfer into the rect of the bitmap from the rect of the source (essentially, this copies a snapshot of the map into the new 640x480 canvas) then performs a radial blur on it with angle 120 degrees and division 16 (the exact nuances of radial blur are beyond the scope of this series, but suffice to say this makes a kind of circular blurry version of the map that ends up looking a bit like the view from a kaleidoscope). Finally, we return the bitmap.
This method will be called if the player is on a non-overworld map and didn't specify a battleback in the map settings.
def battleback1_name if $BTEST $data_system.battleback1_name elsif $game_map.battleback1_name $game_map.battleback1_name elsif $game_map.overworld? overworld_battleback1_name end end
This method gets the filename of the battle background being used as the floor. If we're in a test battle, we return battleback 1 from $data_system (basically, whatever background was chosen in the test battle dialog). If we're not, and the battleback1_name property of $game_map returns a value, we return that value. Otherwise, if field type is overworld (tileset mode has been set to 0), we return the result of calling overworld_battleback1_name.
def battleback2_name if $BTEST $data_system.battleback2_name elsif $game_map.battleback2_name $game_map.battleback2_name elsif $game_map.overworld? overworld_battleback2_name end end
This method does exactly the same thing as the previous method, but for the wall background.
def overworld_battleback1_name $game_player.vehicle ? ship_battleback1_name : normal_battleback1_name end
This method gets the filename of the battleback used on the floor in the overworld. If the player is riding a vehicle, we return the result of calling ship_battleback1_name, otherwise we return the result of calling normal_battleback1_name.
def overworld_battleback2_name $game_player.vehicle ? ship_battleback2_name : normal_battleback2_name end
Exactly the same but for battleback2 (wall).
def normal_battleback1_name terrain_battleback1_name(autotile_type(1)) || terrain_battleback1_name(autotile_type(0)) || default_battleback1_name end
This method gets the filename of the normal battleback used on the floor. Returns either the result of calling terrain_battleback1_name passing in autotile_type(1), terrain_battleback1_name passing in autotile_type(0), or default_battleback1_name (subsequent calls will be made if the previous one returned false or nil).
def normal_battleback2_name terrain_battleback2_name(autotile_type(1)) || terrain_battleback2_name(autotile_type(0)) || default_battleback2_name end
Exactly the same but for battleback2 (wall).
def terrain_battleback1_name(type) case type when 24,25 # Wasteland "Wasteland" when 26,27 # Dirt field "DirtField" when 32,33 # Desert "Desert" when 34 # Rocks "Lava1" when 35 # Rocks (lava) "Lava2" when 40,41 # Snowfield "Snowfield" when 42 # Clouds "Clouds" when 4,5 # Poisonous swamp "PoisonSwamp" end end
This method gets the filename of a floor background based on terrain, and takes one parameter, type.
We have a case statement for type, which returns the string corresponding to the terrain represented by the types in each case, which are just tile IDs from the "World_A1" tileset. If you look at the tiles in the editor and look at tiles 4 and 5 for example (bearing in mind it's 0-indexed) you'll see that those tiles do indeed look like poisonous swamp.
Because these values are hardcoded, if you ever use a different tileset for A1 with differing autotiles or autotiles in different places you'll have to update this method accordingly, or they won't match up.
def terrain_battleback2_name(type) case type when 20,21 # Forest "Forest1" when 22,30,38 # Low hill "Cliff" when 24,25,26,27 # Wasteland, dirt field "Wasteland" when 32,33 # Desert "Desert" when 34,35 # Rocks "Lava" when 40,41 # Snowfield "Snowfield" when 42 # Clouds "Clouds" when 4,5 # Poisonous swamp "PoisonSwamp" end end
Same thing as before but with walls.
The calls to these two methods will result in a somewhat-dynamic battle background that matches as closely as possible the terrain of the tile the player is on when a battle occurs.
def default_battleback1_name "Grassland" end
This method gets the filename of the default floor battle background and is hardcoded to return "Grassland" meaning any tile that doesn't have another associated background will use it.
def default_battleback2_name "Grassland" end
Same thing for walls.
def ship_battleback1_name "Ship" end
This method gets the floor battle background when on a vehicle, and is hardcoded to return "Ship".
def ship_battleback2_name "Ship" end
Same for the wall background.
def autotile_type(z) $game_map.autotile_type($game_player.x, $game_player.y, z) end
This method gets the type of the autotile the player is standing on, and returns the result of calling $game_map's autotile_type method, passing in the player's x and y, and the passed-in z value. From the calls to the method from methods we looked at above, this means z will either be 1 or 0. We looked at this method of $game_map in the Game_Map episode, if you remember.
def center_sprite(sprite) sprite.ox = sprite.bitmap.width / 2 sprite.oy = sprite.bitmap.height / 2 sprite.x = Graphics.width / 2 sprite.y = Graphics.height / 2 end
This method moves a sprite to the centre of the screen, and takes one parameter, sprite, which is the sprite object to move. Its ox and oy are set to half the sprite's source bitmap's width and height, and its x/y are set to half the width and height of the screen.
def create_enemies @enemy_sprites = $game_troop.members.reverse.collect do |enemy| Sprite_Battler.new(@viewport1, enemy) end end
This method creates the enemy sprites. We iterate through a reverse collect on members from $game_troop, with the block creating a new Sprite_Battler passing in @viewport1 and the current enemy object, and assign the returned array of sprites to @enemy_sprites.
def create_actors @actor_sprites = Array.new(4) { Sprite_Battler.new(@viewport1) } end
This method creates actor sprites. By default in VX Ace actors are not actually displayed, but in order to treat enemies and allies the same in code dummy sprites are created for them.
Pretty simple really. @actor_sprites is set to a new 4-element Array, with each element initialised as a new instance of Sprite_Battler passing in @viewport1.
def create_pictures @picture_sprites = [] end
This method creates the initial state for picture sprites. As with Spriteset_Map, it's created as an empty array and will be populated in the update method.
def create_timer @timer_sprite = Sprite_Timer.new(@viewport2) end
This method creates the timer sprite in viewport 2, same as on the map spriteset.
def dispose dispose_battleback1 dispose_battleback2 dispose_enemies dispose_actors dispose_pictures dispose_timer dispose_viewports end
The main dispose method is just a wrapper for calls to other dispose methods.
def dispose_battleback1 @back1_sprite.bitmap.dispose @back1_sprite.dispose end
This method disposes the floor background. Disposes the sprite's bitmap if one is set, then disposes the sprite object to free up its memory.
def dispose_battleback2 @back2_sprite.bitmap.dispose @back2_sprite.dispose end
Same thing for the wall background.
def dispose_enemies @enemy_sprites.each {|sprite| sprite.dispose } end
This method disposes enemy sprites. Iterates through each element of @enemy_sprites with "sprite" and calls its dispose method.
def dispose_actors @actor_sprites.each {|sprite| sprite.dispose } end
Same thing but for the actor sprites.
def dispose_pictures @picture_sprites.compact.each {|sprite| sprite.dispose } end
Same thing but for the picture sprites. Note the call to compact before each to remove nil elements.
def dispose_timer @timer_sprite.dispose end
This method disposes the timer sprite and just calls dispose on @timer_sprite.
def dispose_viewports @viewport1.dispose @viewport2.dispose @viewport3.dispose end
This method calls dispose for the 3 viewports.
def update update_battleback1 update_battleback2 update_enemies update_actors update_pictures update_timer update_viewports end
The frame update method is a wrapper for the calls to the other update methods.
def update_battleback1 @back1_sprite.update end
This method updates the floor background sprite by calling the update method of @back1_sprite.
def update_battleback2 @back2_sprite.update end
Same thing for the wall background sprite.
def update_enemies @enemy_sprites.each {|sprite| sprite.update } end
This method updates enemy sprites by iterating through each element of @enemy_sprites and calling its update method.
def update_actors @actor_sprites.each_with_index do |sprite, i| sprite.battler = $game_party.members[i] sprite.update end end
This method updates the actor sprites by iterating through each element of @actor_sprites with an index, then in the block setting the sprite's battler property to the party member with index i and calling the sprite's update method (if you'll recall, the update method of Sprite_Battler sets the bitmap property to nil if there's no associated battler, which is why we have to set one here first. I'm honestly not sure why this wasn't done by iterating through the party when creating the sprites in the first place, as with the enemies. It's not like the actor sprites actually do anything by default).
def update_pictures $game_troop.screen.pictures.each do |pic| @picture_sprites[pic.number] ||= Sprite_Picture.new(@viewport2, pic) @picture_sprites[pic.number].update end end
This method updates the pictures by iterating through each element of the pictures array of the screen property of $game_troop with "pic". In the block, we either get the element of @picture_sprites with an index of the picture's number, or a new instance of Sprite_Picture passing in @viewport2 and pic. Then we call the sprite's update method.
def update_timer @timer_sprite.update end
This method updates the timer sprite by calling the update method of @timer_sprite. The obvious explanations are starting to look silly, but I want to make sure I never completely lose people regardless of their programming knowledge so I keep pointing them out.
def update_viewports @viewport1.tone.set($game_troop.screen.tone) @viewport1.ox = $game_troop.screen.shake @viewport2.color.set($game_troop.screen.flash_color) @viewport3.color.set(0, 0, 0, 255 - $game_troop.screen.brightness) @viewport1.update @viewport2.update @viewport3.update end
The viewport update method is identical to the one from Spriteset_Map with the exception that we're using the screen property of $game_troop instead of $game_map.
def battler_sprites @enemy_sprites + @actor_sprites end
This method gets all of the battler sprites by adding the @enemy_sprites and @actor_sprites arrays together into one larger array.
def animation? battler_sprites.any? {|sprite| sprite.animation? } end
This method determines whether an animation is being displayed. Returns true if any of the elements in battler_sprites return true when their animation? method is called, false otherwise.
def effect? battler_sprites.any? {|sprite| sprite.effect? } end
Same thing but for effects.
And that's it! The classes and methods we've looked at over the past three or so articles comprise absolutely everything RPG Maker uses to make stuff appear on the screen, with the exception of the absolute baseline stuff in built-in classes like Bitmap and Sprite. Coming up next, we'll be breaking down the Window classes.
As always, comments are welcome.
Until next time.