Sujet n°9353
Posté par Ku'rei le 9 Mar - 22:24 (2011)
Titre : Comment faire un script qui agit en processus parallèle ?
Bonjour tout le monde,
J'ai besoin, de faire un script qui tourne en permanence dans le jeu sans le bloquer (donc pas de boucle répétant l'action), comme le ferais un évènement commun en processus parallèle. Je sais que c'est possible mais je n'arrive pas à trouver le moyen d'y arriver :/

Quelqu'un saurait-il comment faire ?
Merci d'avance

Posté par Nuri Yuri le 9 Mar - 23:20 (2011)
Deux scripts en PP hum ... ... ... ... avec le RGSS Player c'est un peut impossible.
Pour exécuter deux script en PP il faut utiliser les thread, exemple :
Code:
Thread.new { sleep 0.5; for i in 0..10;p i;end };Thread.new { sleep 0.5; for i in 10...20;p i;end }; sleep 2

ça donne ça :
Code:
10
0
11
1
12
2
13
3
14
4
15
5
16
6
17
7
18
8
19
9
10

Mais sur le RGSS Player le simple fait d'utiliser un Thread fait laguer le jeu donc pas de processus parallèles en RGSS ça seras plutôt des pseudo processus parallèles car l'un doit attendre que l'autre ai terminé.
Voici un exemple simple.
Code:
class Image_Youri
  def update
    $mouse.update
    $interface.update if $scene.class != Pkmn_Scene_Title
    $og.update
    if @message[4] and !@working
      for i in 0..$config.msg_sp
        update_message
      end
    end
    for i in @images
      i[1].update_sprite
    end
  end
end

Qu'est ce qu'il se passe exactement ?
C'est simple à chaque fois que je fais $yi.update
La méthode update de Image_Youri va mettre la souris, l'interface, le online, le message puis toute les images animés à jours.
Ce qui est bien avec ça c'est qu'on peut parasiter le script appelant car tant que update de $yi n'est pas fini le script appelant ne se termine pas mais il ne faut surtout pas appeler le script appelant sous peine de tomber sur un strack error.
Pour te montrer l'utilisation de cette méthode en pseudo processus parallèle voici la méthode update de Scene_Map :
Code:
  def update
    # ループ
    loop do
      # マップ、インタプリタ、プレイヤーの順に更新
      # (この更新順序は、イベントを実行する条件が満たされているときに
      #  プレイヤーに一瞬移動する機会を与えないなどの理由で重要)
      $game_map.update
      $game_system.map_interpreter.update
      $game_player.update
      # システム (タイマー)、画面を更新
      $game_system.update
      $game_screen.update
      # プレイヤーの場所移動中でなければループを中断
      unless $game_temp.player_transferring
        break
      end
      # 場所移動を実行
      transfer_player
      # トランジション処理中の場合、ループを中断
      if $game_temp.transition_processing
        break
      end
    end
    $yi.update  #Utilisation de la méthode qui va mettre presque tout a jour ^_^
    # スプライトセットを更新
    @spriteset.update   #Elle est même utilisé avant ma mise a jour de la map :B
    # メッセージウィンドウを更新
    @message_window.update
    #[ etc ...]
  end

Avec ça je peux afficher les statut des Pokémon sans détruire Scene_Map je lui fait juste attendre un moment.
Fin le noyau d'RMXP est déjà un tas de pseudo processus parallèles donc lis les script pour mieux comprendre cette histoire.

Posté par Ku'rei le 10 Mar - 09:57 (2011)
Tout d'abord, merci Yuri Imbécile heureux

Ensuite, bon je viens à peine de comprendre comment fonctionne la programmation par objet donc tout ce qui touche a l'affichage je comprend que les grandes lignes. Mais ce n'est apparemment pas du tout ce dont tu parle.
Si je comprend bien, il ne faut pas utiliser de Thread à cause du lag, mais on peut créer un pseudo processus parallèle avec la méthode update (mise à jour).
Ce que je ne comprend pas, c'est que update est une méthode, il faut donc l'appeler ? A moins qu'elle soit appelée automatiquement à chaque frame, bref c'est flou dans ma tête.

Enfin, je situe le script :
Je voudrais que mon script vérifie une certaine condition à chaque frame du jeu (ou si possible, à chaque déplacement du héros) et exécute une action si cette condition est remplie.

Posté par Nuri Yuri le 10 Mar - 11:50 (2011)
Il faut appeler update, c'est pas une méthode qui s'appelle toute seule d’ailleurs ce genre de méthode n'existe pas.
Pour que la condition s’exécute en fonction des déplacements du heros met une condition, puis pour lui faire réaliser certaine action met des condition et/ou paramètres.
Un code pour executer des actions en fonction de ce qu'on met en paramètres :
Code:
def update(var=nil)
  case var
  when 0
    print "salut"
  when 1
    print "oh !"
  when 2
    #commande
  else
    return
  end
  #code
end

Posté par Sphinx le 10 Mar - 17:48 (2011)
Quelle action veux tu répéter ?

Posté par Ku'rei le 12 Mar - 10:58 (2011)
A Yuri : l'update que tu me propose est en fait un fonction de mise à jour (update quoi >< ), mais c'est une fonction qu'il faut appeler. Hors j'ai déjà ma fonction à appeler à chaque déplacement du héros. Je ne vois pas l'intérêt de créer une fonction upadate pour appeler une autre fonction de mise à jour. Après c'est vrai que je n'ai pas bien décrit l'action que je voulais déclancher.

Donc (et là je m'adresse autant à Yuri qu'à Sphinx) , j'ai repris mon script des pokémons voyageurs (en entier, rien à voir avec l'ancien), j'ai donc créer une fonction "pokemon_rencontre" qui test si le héros est dans la même map, sur le même terrain qu'un des pokemons voyageurs et lance le combat si toutes les condition sont vraies.

Je voudrais que ce test aie lieu à chaque déplacement du héros.

Posté par Sphinx le 12 Mar - 11:12 (2011)
Tu as cette fonction, dans le script Pokemon_Party :

Code:
    def increase_steps
      @steps = [@steps + 1, 9999999].min
      # Repel
      if @repel_count > 0
        @repel_count -= 1
      end
      # Reduit le nombre de pas pour chaque oeuf
      for pokemon in @actors
        if pokemon.egg
          pokemon.decrease_step
        end
      end
      # Inspecte la pension
      Daycare.sequence
    end


Elle se lance à chaque pas du héros Clin d'œil foireux Tu peux donc mettre ta fonction là dedans si elle doit se lancer à chaque pas, où que tu marches Clin d'œil foireux

Posté par Ku'rei le 12 Mar - 11:14 (2011)
Cooool ! Merci Imbécile heureux
ça peut servir en effet !
Mais je suis curieux de savoir comment tu fais pour qu'elle se lance à chaque déplacement Clin d'œil foireux

Posté par Sphinx le 12 Mar - 12:58 (2011)
Cette fonction a été écrite par Krosk. Il l'a simplement appelée dans les différentes commandes de RMXP qui gèrent le mouvement du joueur Imbécile heureux

Par contre, cette fonction se lance à chaque pas que fait le personnage, y compris dans les maisons, sur l'eau, à l'intérieur comme en dehors des hautes herbes, ... Bref à chaque pas Imbécile heureux

Posté par Ku'rei le 12 Mar - 13:18 (2011)
D'accord, simple mais rusé de sa part. Oui, mais ne t'inquiète pas : c'est un problème simple à régler Imbécile heureux
Merci encore

Posté par Sphinx le 12 Mar - 17:34 (2011)
Imbécile heureux Disons que si ton évent n'est censé se déclencher que lorsque le héros est dans l'herbe, tu as d'autres endroits où placer l'appel de ta fonction ^^

Posté par Ku'rei le 12 Mar - 20:49 (2011)
En fait, mon event est sensé se déclancher à chaque déplacement, car je détecte le pokémon voyageur avec la map et le terrain sur lequel est le joueur. Je ne pense pas pouvoir la mettre ailleurs... ou peut-être appeler ma fonction à chaque changements de terrain, mais c'est sans intérêt. Imbécile heureux nan je ne vois pas.
Dis-moi, tu connais les scripts Pokemon_Battle_Core de Krosk ? Parce que j'ai un problème avec eux, pour faire fuir le pokémon (j'ai modifié la phase3 #Round : attaque), tout marche bien sauf quand le pokémon du joueur attaque le premier, il enchaine les attaques. Je peux t'envoyer ma fonction modifiée par MP ?

Posté par Sphinx le 13 Mar - 10:39 (2011)
Postes la ici plutôt Clin d'œil foireux


Je ne suis pas vraiment disponible ces derniers temps, mais si tu postes ici, un autre scripteur trouvera peut être la solution Imbécile heureux

Posté par Ku'rei le 13 Mar - 11:53 (2011)
D'accord,
Voici la fonction qui pose problème (elle se situe à la ligne 530 du script Pokemon_Battle_Core_1) :
Code:
   # Round: Attaques
    def phase3
     
      if not($combat_contre_pokemon_fuyard)
       # print("Pokemon non fuyard")
        if @strike_first
        #  print("Le héros attaque le premier")
          if @actor_action == 1 and not(@actor.dead?)
            attack_action(@actor, @actor_skill, @enemy)
          end
        elsif not(@enemy_caught) and @enemy_action == 1 and not(@enemy.dead?)
          #print("Le pokemon sauvage attaque le premier")
          attack_action(@enemy, @enemy_skill, @actor)
        end
     
        faint_check
     
        if @actor.dead? or @enemy.dead? or $battle_var.battle_end?
          return
        end

     
        if not(@strike_first)
          if @actor_action == 1 and not(@actor.dead?)
            #print("Le héros attaque en second")
            attack_action(@actor, @actor_skill, @enemy)
          end
        elsif not(@enemy_caught) and @enemy_action == 1 and not(@enemy.dead?)
         # print("Le pokemon sauvage attaque en second")
          attack_action(@enemy, @enemy_skill, @actor)
        end
       
        faint_check
     
        if @actor.dead? or @enemy.dead? or $battle_var.battle_end?
          return
        end
      else
       # print("Pokemon fuyard")
        if @strike_first #Le pokemon du héros attaque avant que le pokemon sauvage s'enfuit
          #print("Le heros peut attaquer !")
          attack_action(@actor, @actor_skill,@enemy)
        else #Le pokemon sauvage s'enfuit avant de se faire attaquer
          #print("Le pokemon sauvage s'enfuit (V1)")
          run_enemy
          $combat_contre_pokemonn_fuyard = false
        end
       
        if @actor.dead? or @enemy.dead? or $battle_var.battle_end?
          return
        end
       
      #  print("Le pokemon sauvage s'enfuit (V2)")
        run_enemy                             # Le pokemon s'enuit avant que le heros ne puisse
        $combat_contre_pokemon_fuyard = false # attaquer => pas besoin de condition en plus
      end
    end

J'explique, la variable $combat_contre_pokemon_fuyard est utilisée comme un interrupteur : si elle est true on se bat contre un pokemon qui fuit à la première occasion sinon c'est un combat normal.
Si on fait un premier combat tout marche bien, mais au deuxième... Quand le pokémon du héros attaque, il enchaine les attaques sans que rien d'autre ne se passe et ce jusqu'à ce que le combat se termine.
Je pense que le problème viens de la fonction attack_action ou du script Pokemon_Battle_Wild (script que j'ai remplacer par celui de PSP 0.7 car la fonction de conservation de paramètres ne fonctionnait pas, et je n'ai pas les compétence pour aller tripatouiller là-bas dedans)

Voilà si quelqu'un peut m'aider Imbécile heureux