Page 1 sur 1

Scroll Pictures

Publié : jeu. mai 24, 2012 9:07 pm
par Zeus81
Compatible XP, VX et VXace.
Ce script permet de rajouter quelques petits effets de la more aux maps pour les embellir (ça s'adresse à ceux qui ont plein de temps à perdre dans des détails).
Pour faire simple ce script permet d'afficher des images qui bouclent un peu à la manière des brouillards mais juste dans le cadre d'une image et avec la forme qu'on veut.
Pour ça on a besoin de deux choses, une image en noir et blanc qui servira de masque et une texture.

Plutôt que du blabla des exemples :
- Une lumière avec de la poussière qui flotte.
Image
Le masque et la texture utilisés :
Image Image

- Une fumée dans un couloir.
Image
Le masque et la texture utilisés (texture que j'ai par ailleurs mis a 400% de zoom dans les réglages pour avoir cet effet) :
Image Image

J'ai essayé de rendre ça le plus simple possible à configurer donc on va utiliser la commande Afficher une image.
Mais avant d'utiliser la commande on insère un script en écrivant : scroll_picture_mask
Comme ça les commandes qui suivent ne seront pas gérées comme étant des images normales.
Dans la commande Afficher une image on sélectionne l'image de masque, la position sur la map en pixels, etc... toutes les réglages seront pris en compte comme sur une image normale.
Ensuite pour configurer la texture on va réutiliser la commande Afficher une image mais cette fois avant on met un script avec : scroll_picture_texture
Cette fois on choisis l'image de texture mais les autres réglages auront un autre effet, la position X indiquera la vitesse de défilement sur X, la position Y la vitesse de défilement sur Y, le zoom ici est celui de la texture qui est indépendant du zoom de l'image elle même, les autres réglages ne sont pas utilisés.
Ce qui donne quelque chose comme ça :
Image
Si on a besoin d'en configurer plusieurs d’affiler, on a pas besoin de faire :
<> Script : scroll_picture_mask
<> Afficher image : N°1 ...
<> Script : scroll_picture_mask
<> Afficher image : N°2 ...


On peut simplifier en :
<> Script : scroll_picture_mask
<> Afficher image : N°1 ...
<> Afficher image : N°2 ...


De même on peut aussi utiliser les commandes Déplacer une image, Faire tourner une image, Modifier le ton d'une image et Effacer une image.
Toutes les commandes liées aux images suivant directement scroll_picture_mask sont considéré comme telles.
Idem pour scroll_picture_texture

Enfin il y'a deux réglages supplémentaires qu'on ne peut faire qu'en script.

scroll_picture(id).z = valeur
Avec id le numéro de l'image et valeur la priorité de superposition, la valeur par défaut est 1000 ce qui correspond à Au dessus de tout, mais on peut mettre par exemple 1 pour que l'image soit juste au dessus du sol, ou un nombre négatif pour qu'elle apparaisse derrière la map.

scroll_picture(id).map_anchor = valeur
Avec id le numéro de l'image et valeur le rapport entre la position de l'image et la map, la valeur par défaut est 1 ce qui signifie que l'image bouge avec la map, à 0 l'image n'est pas fixée à la map, à 2 l'image bouge avec la map et deux fois plus vite, à 0.5 l'image bouge avec la map mais deux fois moins vite.

Le script, à mettre au dessus du main comme d'hab :
Spoiler!

Code : Tout sélectionner

# Scroll Pictures 1.0 for XP, VX & VXAce by Zeus81

class Game_Scroll_Picture < Game_Picture
  attr_accessor :z, :map_anchor, :texture, :texture_ox, :texture_oy, :erased
  def initialize(number)
    @z  , @map_anchor, @texture                , @texture_ox, @texture_oy, @erased = 
    1000, 1          , Game_Picture.new(number), 0          , 0          , false
    super(number)
  end
  def erase() @erased = true end
  def update
    super
    @texture.update
    @texture_ox -= @texture.x / 10.0
    @texture_oy -= @texture.y / 10.0
  end
end

class Sprite_Scroll_Picture < Sprite
  dll = FileTest.directory?('System') ? 'System/ZEUS' : 'ZEUS'
  GrayscaleMaskBlt = Win32API.new(dll, 'GrayscaleMaskBlt', 'iiiiiiiiii', 'i')
  def initialize(viewport, picture)
    super(viewport)
    @picture, @last_args = picture, []
  end
  def dispose
    bitmap.dispose if bitmap
    super
  end
  def update
    return unless self.visible = !@picture.name.empty? && !@picture.texture.name.empty?
    if @last_mask_name != @picture.name
      @last_mask_name = @picture.name.dup
      bitmap.dispose if bitmap
      mask = cache(@picture.name)
      self.bitmap = Bitmap.new(mask.width, mask.height)
    end
    if @picture.origin != 0
      self.ox = bitmap.width / 2
      self.oy = bitmap.height / 2
    else self.ox = self.oy = 0
    end
    self.x = @picture.x - @picture.map_anchor * map_display_x
    self.y = @picture.y - @picture.map_anchor * map_display_y
    self.z = @picture.z
    self.zoom_x = @picture.zoom_x / 100.0
    self.zoom_y = @picture.zoom_y / 100.0
    self.opacity = @picture.opacity
    self.blend_type = @picture.blend_type
    self.angle = @picture.angle
    self.tone = @picture.tone
    return unless self.visible = on_screen?
    super
    args = [bitmap.__id__ << 1, 0, cache(@picture.name).__id__ << 1, 0,
            cache(@picture.texture.name).__id__ << 1, 0,
            @picture.texture_ox.to_i, @picture.texture_oy.to_i,
            @picture.texture.zoom_x.to_i, @picture.texture.zoom_y.to_i]
    return if @last_args == args
    @last_args.replace(args)
    GrayscaleMaskBlt.call(*args)
  end
  def on_screen?
    x1, y1, w1, h1 = x, y, (bitmap.width*zoom_x).to_i, (bitmap.height*zoom_y).to_i
    w2, h2 = screen_width, screen_height
    if angle == 0
      x1, y1 = x1-w1/2, y1-h1/2 if ox != 0
      x1<w2 and x1+w1>0 and y1<h2 and y1+h1>0
    else
      x1, y1, r1 = (x1-w2/=2).abs, (y1-h2/=2).abs, Math.hypot(w1, h1)
      r1 /= 2 if ox != 0
      x1<=w2+r1 and y1<=h2+r1 and (x1<=w2 or y1<=h2 or Math.hypot(x1-w2,y1-h2)<=r1)
    end
  end
  if defined?(Hangup) #xp
    def cache(filename) RPG::Cache.picture(filename) end
    def screen_width()  640                          end
    def screen_height() 480                          end
    def map_display_x() $game_map.display_x / 4      end
    def map_display_y() $game_map.display_y / 4      end
  else                #vx & vxace
    def cache(filename) Cache.picture(filename)      end
    def screen_width()  Graphics.width               end
    def screen_height() Graphics.height              end
    if RUBY_VERSION == '1.8.1' #vx
      def map_display_x() $game_map.display_x / 8    end
      def map_display_y() $game_map.display_y / 8    end
    else                       #vxace
      def map_display_x() $game_map.display_x * 32   end
      def map_display_y() $game_map.display_y * 32   end
    end
  end
end

class Game_Map
  attr_reader :scroll_pictures
  alias zeus81_scroll_pictures_setup setup
  def setup(map_id)
    @scroll_pictures = {}
    zeus81_scroll_pictures_setup(map_id)
  end
  alias zeus81_scroll_pictures_update update
  def update(*args)
    @scroll_pictures.delete_if {|i, p| p.erased}
    @scroll_pictures.each_value {|p| p.update}
    zeus81_scroll_pictures_update(*args)
  end
end

class Spriteset_Map
  alias zeus81_scroll_pictures_dispose dispose
  def dispose
    @scroll_picture_sprites.each_value {|s| s.dispose}
    zeus81_scroll_pictures_dispose
  end
  alias zeus81_scroll_pictures_update update
  def update
    @scroll_picture_sprites ||= {}
    @scroll_picture_sprites.delete_if do |i, s|
      s.dispose if result = !$game_map.scroll_pictures.has_key?(i)
      result
    end
    for i, p in $game_map.scroll_pictures
      s = @scroll_picture_sprites[i] ||= Sprite_Scroll_Picture.new(@viewport1, p)
      s.update
    end
    zeus81_scroll_pictures_update
  end
end

if defined?(Hangup) #xp
  
  class Interpreter
    def execute_command
      if @index < @list.size-1
        @parameters = @list[@index].parameters
        method_name = "command_#{@list[@index].code}"
        return send(method_name) if respond_to?(method_name)
      else command_end
      end
      return true
    end
    def scroll_picture(id)
      $game_map.scroll_pictures[id] ||= Game_Scroll_Picture.new(id)
    end
    def scroll_picture_mask()    scroll_picture_setup(0) end
    def scroll_picture_texture() scroll_picture_setup(1) end
    def scroll_picture_setup(type)
      i = @index
      while(@list[i += 1].code.between?(231, 235))
        @list[i].parameters << type if @list[i].code < 233
        @list[i].code += 810000
      end
      return true
    end
    def command_810231
      picture = scroll_picture(@parameters[0])
      picture = picture.texture if @parameters[-1] != 0
      x, y = @parameters[4], @parameters[5]
      x, y = $game_variables[x], $game_variables[y] if @parameters[3] != 0
      picture.show(@parameters[1], @parameters[2], x, y, @parameters[6],
                   @parameters[7], @parameters[8], @parameters[9])
      return true
    end
    def command_810232
      picture = scroll_picture(@parameters[0])
      picture = picture.texture if @parameters[-1] != 0
      x, y = @parameters[4], @parameters[5]
      x, y = $game_variables[x], $game_variables[y] if @parameters[3] != 0
      picture.move(@parameters[1]*2, @parameters[2], x, y, @parameters[6],
                   @parameters[7], @parameters[8], @parameters[9])
      return true
    end
    def command_810233
      scroll_picture(@parameters[0]).rotate(@parameters[1])
      return true
    end
    def command_810234
      scroll_picture(@parameters[0]).start_tone_change(@parameters[1], @parameters[2]*2)
      return true
    end
    def command_810235
      id = @parameters[0]
      scroll_picture(id).erase if $game_map.scroll_pictures.has_key?(id)
      return true
    end
  end
  
else                #vx & vxace
  
  class Game_Interpreter
    if RUBY_VERSION == '1.8.1' #vx
      def wait(duration) @wait_count = duration end
      def execute_command
        if @index < @list.size-1
          @params, @indent = @list[@index].parameters, @list[@index].indent
          method_name = "command_#{@list[@index].code}"
          return send(method_name) if respond_to?(method_name)
        else command_end
        end
        return true
      end
    end
    def scroll_picture(id)
      $game_map.scroll_pictures[id] ||= Game_Scroll_Picture.new(id)
    end
    def scroll_picture_mask()    scroll_picture_setup(0) end
    def scroll_picture_texture() scroll_picture_setup(1) end
    def scroll_picture_setup(type)
      i = @index
      while(@list[i += 1].code.between?(231, 235))
        @list[i].parameters << type if @list[i].code < 233
        @list[i].code += 810000
      end
    end
    def command_810231
      picture = scroll_picture(@params[0])
      picture = picture.texture if @params[-1] != 0
      x, y = @params[4], @params[5]
      x, y = $game_variables[x], $game_variables[y] if @params[3] != 0
      picture.show(@params[1], @params[2], x, y, @params[6],
                   @params[7], @params[8], @params[9])
      return true
    end
    def command_810232
      picture = scroll_picture(@params[0])
      picture = picture.texture if @params[-1] != 0
      x, y = @params[4], @params[5]
      x, y = $game_variables[x], $game_variables[y] if @params[3] != 0
      picture.move(@params[2], x, y, @params[6], @params[7],
                   @params[8], @params[9], @params[10])
      wait(@params[10]) if @params[11]
      return true
    end
    def command_810233
      scroll_picture(@params[0]).rotate(@params[1])
      return true
    end
    def command_810234
      scroll_picture(@params[0]).start_tone_change(@params[1], @params[2])
      wait(@params[2]) if @params[3]
      return true
    end
    def command_810235
      id = @params[0]
      scroll_picture(id).erase if $game_map.scroll_pictures.has_key?(id)
      return true
    end
  end
  
end
La dll, à mettre direct dans le dossier du jeu sauf pour VXace où il faut mettre ça dans le sous-dossier System :
http://www.mediafire.com/?1g4shddbhh1qh
Y'a aussi le code source pour ceux que ça intéresse, c'est un projet VC++2010 Express.

Pour les scripteurs y'a d'autres possibilités avec la fonction GrayscaleMaskBlt qui ne sont pas exploitées dans ce scripts.

Code : Tout sélectionner

GrayscaleMaskBlt .call(
    bitmap.__id__<<1, #Le bitmap dans lequel on veut dessiner
    bitmap_rect.__id__<<1, #Rect de la zone à remplir, si c'est tout le bitmap on peut mettre 0
    mask.__id__<<1, #(Facultatif) Bitmap d'un masque en niveau de gris à appliquer au remplissage, si la taille du masque est différente de celle du bitmap il est automatiquement étiré
    mask_rect.__id__<<1, #Rect de la zone du masque qu'on désire utiliser, si c'est tout le bitmap on peut mettre 0
    texture.__id__<<1, #Bitmap de la texture à dessiner
    texture_rect.__id__<<1, #Rect du morceau de texture à dessiner, si c'est tout le bitmap on peut mettre 0
    texture_ox, #Le décalage en pixels de la texture sur x
    texture_oy, #Le décalage en pixels de la texture sur y
    texture_zoom_x, #L'étirement de la texture sur x, défaut 100, ne peut pas être égal à 0, si négatif la texture est inversée sur x
    texture_zoom_y #L'étirement de la texture sur y, défaut 100, ne peut pas être égal à 0, si négatif la texture est inversée sur y
)
La fonction retourne aussi un message, 0 = pas d'erreur, 1 = zoom invalide, 2 = rect invalide

Publié : ven. mai 25, 2012 1:57 am
par KaYsEr
(j'ai dû mettre des liens à la place des balises images qui sont complètement buguées.)
Ha désolé, c'est uniquement avec l'hébergeur XOOIMAGE que ça fait ça, un vilain hébergeur pis voilà.
(tu peux réup en utilisant le système embarqué de ce forum si tu veux, et ainsi avoir la garanti que ça ne sera pas supprimé)

Sinon le script est super, pis on ne perd pas tant de temps que ça contrairement au :
ça s'adresse à ceux qui ont plein de temps à perdre dans des détails
C'est + efficace que d'autres méthodes et ça mange pas de pain une fois qu'on en a déjà bien chié sur le reste, vu que ça représente un temps négligeable de l'ensemble de la procédure graphique.

(Considérant le cas d'un mec qui aurait mis au point ses propres ressources, et qui n'est donc pas à une poignée d'heure de boulot en rab pour en sublimer un peu l'ensemble)


A vrai dire t'as quand même raison, ce sera plutôt une perte de temps pour une écrasante majorité... Saupoudrer avec des paillettes du RTP ne changera pas ça en autre chose de moins commun et impersonnel. (et puis ok pour eux ce sera du temps en moins)


Autre point positif de cette méthode, c'est le poids.
Après je sais pas si c'est un point négatif mais le fait de devoir ajouter une DLL de plus c'est toujours ça d'ennuyeux m'enfin.

(ou alors faudrait l'exploiter en faisant plein d'autres effets, mais là encore difficile d'avoir la motivation pour bosser en sachant à qui ça va être offert -_- donc bravo pour ce courage, mais y a moyen que ça s'arrange... je tenterai de faire au mieux de mon coté malgré une grosse somme de boulot qui s'amplifie au lieu de diminuer)

:bravo:

Publié : ven. mai 25, 2012 8:37 am
par Zeus81
Malheureusement le passage par la dll est obligatoire, question de rapidité.
Les masques devraient être implémentés directement dans les Sprite et puis dans les Viewport, ça permettrait de faire plein de choses.

Voilà j'ai réup les images, les fichiers joint c'est nul faut être connecté pour les voir. :p

Publié : lun. mai 28, 2012 6:21 pm
par Rikov
Pour des raisons Gameplayesque je trouve ton input ultimate plus intéressant (si quelqu’un dépasse un jour le stade des 3 maps pour se toucher sur des concours de screen) mais on peut pas nier que ça aussi c’est vraiment super, je garde au chaud.