Mundo Maker
¡Bienvenid@ a Mundo Maker!

¿Quieres aprender todo sobre el RPG Maker?



Regístrate y forma parte de Mundo Maker.

Teletransporte aleatorio en mapa

Ver el tema anterior Ver el tema siguiente Ir abajo

RPG Maker XP Teletransporte aleatorio en mapa

Mensaje por wemento el 2016-04-20, 09:29

Buenas a todos.

{EDIT: Leer al final, donde dice "Actualizaciones del script"}

Me estoy iniciando en el mundo de los scripts y mi primera obra (aunque un poco chapucera de momento, supongo) es la que os voy a enseñar a continuación. Se trata de un script para habilidad de teletransporte aleatorio (se usa obviamente en el mapa).

Cómo funciona

Supongamos que tenemos un evento que deseamos que se teletransporte. Al hablar con él, se llamará al evento común "teletransporte", que hace lo siguiente:


Concretamente, hace la llamada a script

Código:
Teletransporte.new.generar_coord_aleat

Donde generar_coord_aleat es un método que se encarga de generar unas coordenadas aleatorias para el mapa en que nos encontramos en ese preciso instante. Esas coordenadas tienen que ser válidas (no puede haber un evento ni tampoco algo no atravesable). Una vez generadas esas coordenadas aleatorias, lo guarda en las variables #19 y #20 (X e Y, respectivamente). Con lo cual basta con indicar que el evento cambie su posición a esas coordenadas.

Os dejo el script en sí:

Código:
class Teletransporte

  def evento_en?(x, y)
    for event in $game_map.events.values
      if event.x == x and event.y == y
        return true
      end
    end
 return false
  end
  
  def generar_coord_aleat
    alto    = $game_map.height
    ancho   = $game_map.width
    
    loop do
      x = rand(ancho)
      y = rand(alto)
      if !evento_en?(x,y) && $game_map.passable?(x,y,0)
        $game_variables[19] = x
        $game_variables[20] = y        
        break
      end
    end
  end
  
end

Para cambiar en qué variables se almacena esta información, únicamente hay que tocar las líneas

Código:
       $game_variables[19] = x
        $game_variables[20] = y    

Y nada más.


Actualizaciones del script

Iré posteando actualizaciones a medida que se avance y se mejore este evento.

Script:

El funcionamiento del script es el siguiente: teletransportará al personaje principal o a un evento (se puede elegir) dentro de una zona cuadrada definida dentro del mapa actual. El evento/actor aparecerá en un tile aleatorio que sea pasable, esto quiere decir:

1. Que no sea un tile que no se puede atravesar (los marcados con una "X" en el tileset).
2. Que no exista un evento en dicho tile.
3. Que no se encuentre el personaje en dicho tile.

Sin más rodeos, el script en sí:

Spoiler:

Código:
#==============================================================================
# ** [XP] Tactic teleport
#==============================================================================

class Game_Character
  
  # sx = x mínimo en mapa (0 si no lo defines)
  # sy = y mínimo en mapa (0 si no lo defines)
  # ex = x máximo en mapa (el ancho del mapa si no lo defines)
  # ey = y máximo en mapa (el alto del mapa si no lo defines)
  
  def tactic_teleport(sx = 0, sy = 0, ex = nil, ey = nil)
    
    # Si ex no está definido vale el ancho del mapa
    if ex == nil
      ex = $game_map.width
    end
    
    # Si ey no está definido vale el alto del mapa
    if ey == nil
      ey = $game_map.height
    end
    
    # Definir ancho y alto del loop (rango)
    width = ex - sx
    height = ey - sy
    
    # Empezar loop
    
    # Usé un loop definido (for) para evitar posible crash si no hubiera ningún
    # tile pasable.
    # Si tras comprobarlo un número suficiente de veces no encuentra ninguno, se
    # aborta el método.
    
    effective = false # Por defecto no encontró ninguno
    
    # El número de veces equivale a width * height
    max_int = width * height
    
    for i in 0...max_int
      
      # Definir nuevas coordenadas aleatorias dentro del rango
      new_x = sx + rand(width)
      new_y = sy + rand(height)
      
      # Comprobar pasabilidad en el rango (la pasabilidad ya mira si hay un
      #evento no pasable o el jugador)
      if passable?(new_x, new_y, 0)
        # Si es pasable, salir del loop
        effective = true
        break
      end
    end
    
    # Si ha encontrado alguna coordenada viable, mover el evento a esa coordenada
    if effective == true
      # print new_x, new_y
      self.moveto(new_x, new_y)
      return true
    end
  end
end

(Give credits al grandioso Wecoc  notworthy  notworthy  notworthy  )


Instrucciones:

1. Copiar código y pegar en un script nuevo encima del main.

2a. Para teletransporte de un evento poner "llamar a script" y escribir el siguiente código:

Código:
$game_map.events[id_evento].tactic_teleport

donde id_evento sería el número de evento a teletransportar. Ejemplo: Si queremos que se teletransporte el evento EV003, ponemos

Código:
$game_map.events[3].tactic_teleport

2b. Para teletransporte del personaje principal poner "llamar a script" y escribir el siguiente código:

Código:
$game_player.tactic_teleport
.

Más info

Para más info o dudas de algún tipo no dudes en comentar.

Gracias!!


Última edición por wemento el 2016-04-26, 14:03, editado 3 veces
avatar
wemento
Iniciado
Iniciado

0/3

Créditos 61

Gracias : 5

Volver arriba Ir abajo

RPG Maker XP Re: Teletransporte aleatorio en mapa

Mensaje por wemento el 2016-04-20, 10:37

Aprovecho para preguntar yo mismo a los scripters avanzados de la comunidad (perdonad el doble post, pero así no saturo el primero, para no hacer la vida imposible a los que lleguen a él).

El script funciona perfectamente si queremos mover un evento en el mapa, pero no suele ser lo habitual (no tendría mucha utilidad). Yo lo había destinado para combates tácticos.

El problema que tengo es que el evento común aplica el teletransporte al evento al que lo llama. En el script de combates tácticos ZTBS, el evento que llama a los eventos comunes es un evento invisible que crea el propio script, con lo cual no sirve de mucho cambiarlo de posición. Me gustaría saber cómo puedo hacer para reconocer a qué evento va asociada la habilidad de teletransporte cuando se usa y cómo aplicarle el teletransporte a él (porque en elegir posición de evento aparece una lista, pero no deja seleccionar evento por medio de variables). Con lo cual supongo que habrá que hacer un script.

Os dejo un GIF con el fallido resultado para batallas tácticas:



A ver si se os ocurre algo porque de momento soy demasiado n00b. Mil gracias.

EDIT:

Os pongo una captura de la habilidad, vaya a ser que haya metido la pata en algo xD pero creo que no



Haciendo esto en "Elegir posición de evento" si funciona el script, teletransportando el evento que quiero. Pero me gustaría hacer un engine+script reutilizable



EDIT:

Ya nada, gracias igualmente. Lo solucioné yo solito xD En cuanto tenga un ratillo libre edito el primer post y explico cómo lo hice, para que quede como recurso.

Salu2
avatar
wemento
Iniciado
Iniciado

0/3

Créditos 61

Gracias : 5

Volver arriba Ir abajo

RPG Maker XP Re: Teletransporte aleatorio en mapa

Mensaje por Wecoc el 2016-04-22, 18:23

El script no está mal, pero puesto que lo estás aplicando todo a un evento (Game_Character --> Game_Event) no es necesario crear una clase, puedes hacerlo en su misma clase. De ese modo en la llamada puedes seleccionar en qué evento quieres aplicarlo, y no hacen falta variables.

Ya sé que ya lo solucionaste solo a tu manera, y eso está muy bien, pero te hago el edit para que te lo mires a ver si te ayuda. Por cierto, aunque tampoco es muy importante te recomiendo usar nombres en inglés para los métodos para que el script sea más universal.

Código:
#==============================================================================
# ** [XP] Tactic teleport
#==============================================================================

class Game_Character
  
  # sx = x mínimo en mapa (0 si no lo defines)
  # sy = y mínimo en mapa (0 si no lo defines)
  # ex = x máximo en mapa (el ancho del mapa si no lo defines)
  # ey = y máximo en mapa (el alto del mapa si no lo defines)
  
  def tactic_teleport(sx = 0, sy = 0, ex = nil, ey = nil)
    
    # Si ex no está definido vale el ancho del mapa
    if ex == nil
      ex = $game_map.width
    end
    
    # Si ey no está definido vale el alto del mapa
    if ey == nil
      ey = $game_map.height
    end
    
    # Definir ancho y alto del loop (rango)
    width = ex - sx
    height = ey - sy
    
    # Empezar loop
    
    # Usé un loop definido (for) para evitar posible crash si no hubiera ningún tile pasable.
    # Si tras comprobarlo un número suficiente de veces no encuentra ninguno, se aborta el método.
    
    effective = false # Por defecto no encontró ninguno, claro
    
    # El número de veces equivale a width * height
    max_int = width * height
    
    for i in 0...max_int
      
      # Definir nuevas coordenadas aleatorias dentro del rango
      new_x = sx + rand(width)
      new_y = sy + rand(height)
      
      # Comprobar pasabilidad en el rango (la pasabilidad ya mira si hay un evento no pasable o el jugador)
      if passable?(new_x, new_y, 0)
        # Si es pasable, salir del loop
        effective = true
        break
      end
    end
    
    # Si ha encontrado alguna coordenada viable, mover el evento a esa coordenada
    if effective == true
      # print new_x, new_y
      self.moveto(new_x, new_y)
      return true
    end
  end
end

Pasa usarlo, en llamar script usa:
$game_map.events[ID de evento].tactic_teleport

También puedes hacerlo con el actor:
$game_player.tactic_teleport

Y para definir el rango simplemente:

$game_map.events[ID de evento].tactic_teleport(X mínima, Y mínima, X máxima, Y máxima)
avatar
Wecoc
Administrador
Administrador



Créditos 12297

Gracias : 648

Volver arriba Ir abajo

RPG Maker XP Re: Teletransporte aleatorio en mapa

Mensaje por wemento el 2016-04-24, 18:51

He hecho lo siguiente, a ver qué te parece:

Código:
class Teletransporte
 
  $objetivo = nil
  @coord_x = nil
  @coord_y = nil

  def evento_en?(x, y)
    for event in $game_map.events.values
      if event.x == x and event.y == y
        return true
      end
    end
    return false
  end
 
  def get_eventid(x, y)
    for event in $game_map.events.values
      if event.x == x and event.y == y
        return event.id
      end
    end
  end
 
  def generar_coord_aleat
    alto    = $game_map.height
    ancho  = $game_map.width
   
    loop do
      x = rand(ancho)
      y = rand(alto)
      if !evento_en?(x,y) && $game_map.passable?(x,y,0)
        @coord_x = x
        @coord_y = y
       
        break
      end
    end
  end
 
  def teletransportar
    id = get_eventid($objetivo.x,$objetivo.y)
    generar_coord_aleat
   
    for event in $game_map.events.values
      if event.id == id
        event.moveto(@coord_x,@coord_y)
        return nil
      end
    end
  end
 
 
end

Y luego la habilidad "Teletransporte" llama al script:

Código:
Teletransporte.new.teletransportar

y saco la posición de evento de las variables [19] y [20].

Sé que podría haber movido el evento desde scripts, pero como digo soy un poco novato (demasiado es que haya hecho un script xD). Pero usaré eso como dices. ¡Mil gracias, Wecoc! ¡Eres un fiera!
avatar
wemento
Iniciado
Iniciado

0/3

Créditos 61

Gracias : 5

Volver arriba Ir abajo

RPG Maker XP Re: Teletransporte aleatorio en mapa

Mensaje por Alex_Game_Maker el 2016-04-24, 19:19

Hey wemento ¡YO HICE ESTO CON ENGINE!
hace unos 15 minutos .~.
avatar
Alex_Game_Maker
Soñador
Soñador

0/3

Créditos 209

Gracias : 22

Volver arriba Ir abajo

RPG Maker XP Re: Teletransporte aleatorio en mapa

Mensaje por Wecoc el 2016-04-24, 19:36

Es que hacerlo con una clase a parte y buscando la id de evento por coordenada te encuentras con toda una série de problemas, por ejemplo si hay más de un evento en un mismo tile ahí tendrás un bug muy difícil de solucionar. Por eso decía que mejor aplicarlo directamente al evento que nos interesa, que todos los métodos de transporte y todo ya lo tenemos en su misma clase y no puede haber bugs de ese tipo.

Además ésta construcción no me gusta para nada:

Código:
Teletransporte.new.teletransportar

Eso no lo uses. Suponiendo que tuvieras que hacer una clase sí o sí para hacer esa llamada (que repito que no), tienes construcciones más interesantes, desde ésto, que es exactamente lo mismo pero te permite hacer más cosas con la misma clase creada en vez de crearla cada vez:

Código:
t = Teletransporte.new
t.teletransportar

Hasta algo un poco más interesante que es en el método usar 'def self.(nombre)' y luego llamarlo sin crear la clase, sinó en la propia clase así: 'Teletransporte.(nombre)'

Por ejemplo:

Código:
class Teletransporte
  def self.teletransportar
    p "Prueba"
  end
end

Teletransporte.teletransportar

Eso lo encontrarás mucho mejor explicado en un tutorial, porque aquí me podría liar a explicar cosas y creo que no me toca ahora.

Luego, como dije, para los métodos mejor usa el inglés siempre que puedas. Puedes ponerte comentarios en español para entender qué hacen (aunque normalmente el nombre del método ya es bastante intuitivo: teleport, get_event, is_event?... Al traducir el código a cualquier otro idioma solo puedes traducir los comentarios; si además tienes que traducir métodos todos los otros scripts que se basen en tu script y todas las compatibilidades con otros scripts dejaran de ser viables. Por eso conviene “universalizar” el código tanto como se pueda.

Internamente y dejando de lado lo que he dicho hasta ahora, tu script no está mal, solo tiene algunos detalles:

1) Definiste cosas fuera de métodos. Eso está bien para constantes de la clase o módulo, por ejemplo:

Código:
class Example
  HELLO_WORLD = true # Solo lo puedes definir aquí, es una constante

  def say_something
    if HELLO_WORLD == true
      p “Hello World”
    else
      p “I don’t know what to say, buddy”
    end
  end
end


Para lo que no son constantes y por lo tanto se pueden redefinir en otro método o lo que sea, conviene definirlas al iniciar la clase, osea dentro del método initialize:

Código:
class Example
  def initialize
    @hello_world = true
  end
end

No explicaré cómo funcionan las constantes en detalle aquí, ni tampoco me quiero extender en los tipos de variables y todo eso, busca un tutorial si no lo tienes claro.

2) Usaste una variable global suelta: $objetivo. Eso se usa en casos muy aislados, ni siquiera se me ocurre ninguno. Para almacenar “globales” ya tenemos dos clases que lo controlan mejor; Game_System y Game_Temp. Ámbas funcionan igual, pero Game_System guarda esas variables y las recupera al cargar partida, y Game_Temp las reinicia cada vez que abres el juego/la partida.

Para ello hay que hacer un alias del initialize para definir ahí las nuevas variables y usar attr_reader para poderlas leer o attr_accessor para poder leerlas y modificarlas.

Código:
class Game_System
  attr_accessor :hello_world
  alias ex_wecoc_ini initialize unless $@
  def initialize
    ex_wecoc_ini
    @hello_world = true
  end
end

# Ahora puedes usar $game_system.hello_world y $game_system.hello_world = true/false

3. Otros detalles que comenté en mi script, como el del loop definido.

Alex_Game_Maker: En éste caso recomiendo 100% hacerlo por script porque es muy corto (26 líneas si quitas los comentarios del mío) y muy sencillo de usar luego en el mapa (solo un método; una simple línea de script; sin gastar variables ni interruptoers) además que no es incompatible con nada y se contemplan bugs que puede que con engine sean muy difíciles de evitar.
avatar
Wecoc
Administrador
Administrador



Créditos 12297

Gracias : 648

Volver arriba Ir abajo

RPG Maker XP Re: Teletransporte aleatorio en mapa

Mensaje por Alex_Game_Maker el 2016-04-24, 22:07

no fue fácil hacer el engine, necesite 4 variables y elegir el terreno de los tiles, pero por lo demás fue sencillo.
si, puede que por Script sea mas fácil y se puedan evitar Bugs, pero aun así prefiero hacerlo con engine, así es 100% y no le tengo que dar créditos a nadie, y aunque no pida créditos no me gusta deberle nada a nadie.
Además, en mi juegos se teletransporta uno de los héroes, no el enemigo.
avatar
Alex_Game_Maker
Soñador
Soñador

0/3

Créditos 209

Gracias : 22

Volver arriba Ir abajo

RPG Maker XP Re: Teletransporte aleatorio en mapa

Mensaje por wemento el 2016-04-25, 06:43

Buenas, Wecoc.

Muchas gracias por tu respuesta. La verdad es que me es de mucha utilidad porque me ha servido para ver mis fallos. Estoy iniciándome en esto del ruby RGSS y me resulta un mundo muy interesante, con lo cual todo lo que pueda aprender (de ti o de donde sea), bienvenido sea.

Te comento algunas cosillas.

@Wecoc escribió:Eso no lo uses. Suponiendo que tuvieras que hacer una clase sí o sí para hacer esa llamada (que repito que no), tienes construcciones más interesantes, desde ésto, que es exactamente lo mismo pero te permite hacer más cosas con la misma clase creada en vez de crearla cada vez:

Toda la razón. Sé que en programación deben evitarse siempre que se pueda este tipo de cosas, asegurando crear variables/objetos sólo una vez. La verdad es que esa construcción tan burda fue para probar que funcionaba, tengo que cambiarlo.

@Wecoc escribió:Hasta algo un poco más interesante que es en el método usar 'def self.(nombre)' y luego llamarlo sin crear la clase, sinó en la propia clase así: 'Teletransporte.(nombre)'

Desconozco cómo funciona el "self". ¿Es como el "this" de Java? No termino de tenerlo muy claro.

@Wecoc escribió:Luego, como dije, para los métodos mejor usa el inglés siempre que puedas

Soy consciente, lo haré. Escuché tu consejo la primera vez y creo que llevas toda la razón. Es un auténtico c***zo luego para el guiri que usa el script tener que renombrar variables y métodos. Siempre hay algo que se queda por ahí y es molesto. Como te digo, acepté el consejo la primera vez el problema es que no he tenido tiempo de tocarlo Sweat

@Wecoc escribió:Usaste una variable global suelta: $objetivo

$objetivo es una variable global que meto luego en el script de ZTBS para conocer quién es el target del ataque teletransportar (para conocer qué evento es el que lo usa). Si lo meto allí en attr_reader y luego accedo a el con $game_system.objetivo funcionará? El attr_reader es producto de RPG Maker y no de Ruby entonces, ¿no?

Por último sólo preguntarte si conoces algún tutorial recomendable enfocado al RGSS. Tutoriales de Ruby puro hay a montones, pero me gustaría alguno para centrarme más en RGSS. El que yo tengo es la guía RGSS de Ánemus, que ya vi que está publicada entre los recursos del foro.

Espero no haber pasado nada por alto. Y como te digo, mil gracias Wecoc. Me has sido de gran ayuda.

@Alex_Game_Maker escribió:no fue fácil hacer el engine, necesite 4 variables y elegir el terreno de los tiles, pero por lo demás fue sencillo.
si, puede que por Script sea mas fácil y se puedan evitar Bugs, pero aun así prefiero hacerlo con engine, así es 100% y no le tengo que dar créditos a nadie, y aunque no pida créditos no me gusta deberle nada a nadie.
Además, en mi juegos se teletransporta uno de los héroes, no el enemigo.

Mil gracias, alex. Pero prefiero hacerlo por script porque ofrece más posibilidades y además es más fácil de depurar que los engines. Y no saturo los interruptores del juego, que ya los tengo bien cargaditos. Además, como te comento, busco teletransportar eventos, no el personaje. Pero de todos modos muchas gracias por tu respuesta.

Gracias makeros!

EDIT: Estaba consultando tu script, Wecoc. Y lo del bucle definido está muy bien para evitar crashes pero existe la posibilidad de que no encuentre algún sitio donde teletransportarse aunque éste exista. Obviamente, aumentando el número de iteraciones del bucle aumentan las posibilidades de encontrar un objetivo despejado, pero continúa existiendo la posibilidad de no lograr el teletransporte, que pensé para que fuera una técnica infalible. ¿Qué tal un bucle definido buscando la aleatoriedad seguido de otro bucle definido recorriendo el mapa hasta encontrar un hueco libre? Elimina aleatoriedad al problema en un segundo caso, pero eso es algo que el usuario no notaría y que permite evitar este tipo de bugs. No sé si es la mejor opción, pero es una idea.

Salu2
avatar
wemento
Iniciado
Iniciado

0/3

Créditos 61

Gracias : 5

Volver arriba Ir abajo

RPG Maker XP Re: Teletransporte aleatorio en mapa

Mensaje por Wecoc el 2016-04-25, 12:50

Igualmente eso de 'self.' en métodos se usa más bien poco, y no quiero liarte. No conozco ningún tutorial, yo aprendí "a las malas" toqueteando scripts, un poco como estás haciendo tú... Busca en Maker Book, seguro que te encuentra varios en español.

La comprobación se hace un número alto de veces (width * height), pero es cierto que puede que aunque haya algún tile no logre encontrarlo, si tienes muy mala suerte xD

La forma de evitar eso, aunque el rendimiento es un poco más bajo, es la siguiente:

1. Comprobar todos los tiles posibles dentro del rango y almacenarlos en una array.
2. Seleccionar un índice aleatorio de la array.

No lo puedo comprobar pero creo que sería así:

Código:
   tiles_array = []
    
    # Empezar doble loop
    
    for iy in 0...height
      for ix in 0...width
        if passable?(sx + ix, sy + iy, 0)
          tiles_array.push([ix, iy])
        end
      end
    end
    
    # Seleccionar al azar entre los tiles pasables
    
    if tiles_array.size > 0
      tile = tiles_array[rand(tiles_array.size)]
      new_x = sx + tile[0]
      new_y = sy + tile[1]
      self.moveto(new_x, new_y)
      return true
    end
avatar
Wecoc
Administrador
Administrador



Créditos 12297

Gracias : 648

Volver arriba Ir abajo

RPG Maker XP Re: Teletransporte aleatorio en mapa

Mensaje por wemento el 2016-04-25, 15:10

También es buena idea, mil gracias!! Y gracias también por el enlace, le echaré un ojo.

He probado a ponerlo y funciona perfectamente. Lo de obtener evento a partir de las coordenadas era porque no tenía muy claro cómo identificar el evento que ejecutaba la habilidad (el script ZTBS es algo engorroso).

Pero he descubierto la forma de identificarlo y es usando una variable local llamada "@active_battler.id", que se encuentra en la clase Enemies Action (que añade/sobreescribe métodos a Scene_Map). El problema es que no tengo muy claro cómo sacarla de ahí por medio de los atributos. He probado a hacer

Código:
$target_id = @active_battler.id

Para poder usar esa variable global donde quiera (con eso me ha funcionado el teletransporte). Pero me gustaría hacerlo bien, usando el attr como tú decías.

Gracias!

Salu2
avatar
wemento
Iniciado
Iniciado

0/3

Créditos 61

Gracias : 5

Volver arriba Ir abajo

RPG Maker XP Re: Teletransporte aleatorio en mapa

Mensaje por Contenido patrocinado


Contenido patrocinado


Volver arriba Ir abajo

Ver el tema anterior Ver el tema siguiente Volver arriba


Permisos de este foro:
No puedes responder a temas en este foro.