O TEMA DO FÓRUM ESTÁ EM MANUTENÇÃO. FEEDBACKS AQUI: ACESSAR

SAPP - Sistema de Ação por Passos

Iniciado por Rhyan, 03/04/2020 às 19:10

03/04/2020 às 19:10 Última edição: 04/04/2020 às 17:22 por Rhyan
Não utilizem deste script (por mais que eu acho que ninguém iria tentar fazer isso), eu apenas postei ele aqui para fins de avaliação, ele é para um projeto próprio.
Script:

1° Versão:
module Teclas
  Left = 0x25
  Up = 0x26
  Right = 0x27
  Down = 0x28
  
  GetKeyState = Win32API.new("user32","GetAsyncKeyState",['i'],'i')
  
  module_function
  
  def key_input(keys)
    GetKeyState.call(keys) & 0x01 == 1
  end
end

class Game_Player < Game_Character
  alias :meu_alias_no_scene_map_start :initialize
  def initialize
    meu_alias_no_scene_map_start
    
    @item_1 = $data_items[1].note.scan(/steps:\s*(\d+)/).flatten.last
    
    @passos = 0
    
  end
  
  alias :meu_update :update
  def update
    super
    meu_update
    
    if Teclas.key_input(Teclas::Left) then
      @passos += 1
    end
    
    if Teclas.key_input(Teclas::Right) then
      @passos += 1
    end
    
    if Teclas.key_input(Teclas::Up) then
      @passos += 1
    end
    
    if Teclas.key_input(Teclas::Down) then
      @passos += 1
    end
    
    if @passos == @item_1.to_i then
      SceneManager.call(Scene_Title)
    end
    
    p @passos
  end
end


2° Versão (na pastebin): https://pastebin.com/piV9e4Kr. (Versão 1: 56 linhas. Versão 2: 29 linhas).  :coffee:

Por favor, avaliem se ficou bom ;-;... Sei que o método de detectar o movimento do jogador que eu fiz não foi um dos melhores então, se houver um melhor, cite-o nas respostas, por favor, se quiser.  :ok:

OBS: Irei estar atualizando esse tópico aqui de acordo com o aprimoramento dele.
^~^) -Rhyan.

Já que pediu avaliação bora  :malvado:

Primeira coisa, você fez as teclas com a Win32API porque queria aprender?
Você pode encontrar a implementação do Input para o RPG Maker aqui: https://www.rubydoc.info/github/cstrahan/open-rpg-maker/Input
Isso já inclui as teclas que você usou, no caso Teclas.key_input(Teclas::Left) , seria o mesmo que Input.press?(:LEFT)
Inclusive se olhar mais para baixo dessa página que mandei, tem implementação de todas as 4 teclas em um único método:


E considerando a parte que você está aprendendo no momento, esse module parece um catado de algum outro script  :XD:, por exemplo você está usando module_function, não que seja extremamente complexa, mas tem um certo nível ai, por isso acho que pode prosseguir com esse script usando o Input padrão do RPG Maker mesmo e ai futuramente ver sobre a WIn32API (que tem aulas muito boas aqui na CRM escritas pelo Kyo).

Agora chegando na classe Game_Player, não sei se sabe, mas já tem um contador de passos definido dentro do próprio código do Ace.

Você está refazendo o que já existe, não sei se sabia disso  :XD:, mas vamos deixar isso de lado e voltar ao aprendizado.

  def update
    super
    meu_update
   
    if Teclas.key_input(Teclas::Left) then
      @passos += 1
    end


perceba que sua variável de passos não está atrelado a nenhum momento ao passo em si e sim a tecla, o que isso significa, que não importa se o personagem der um passo, só de manter pressionado o contador sobe. Lembremos que o update roda em 60fps para o Ace, isso significa que a cada um segundo pressionado a tecla, vai contar 60 passos e é um número extremamente impreciso da real quantidade de passos.

Você tem que atrelar a incrementação dos passos ao ato de realizar o passo, quando você coloca na função de update isso não está tendo relação com os passos em si. É que já existe a função de incrementar os passos no Ace, mas supondo que não tenha, aonde seria o ideal para colocar esse @steps +=1?

Seria em uma função que faz o movimento do personagem e não no update, por exemplo eu mandei o personagem mover, então é ali que eu tenho que por esse @steps +=1. Vide exatamente o que o Ojima escreveu para o Ace (Tudo bem Ojima, dessa vez você está certo  :cowboy:)



Ele colocou no método "move_straight", que é a função que move de fato o personagem.
Veja um increase_steps dentro dele, pois bem, é ai que estaria o seu @steps += 1.




Mais alguns pontos sobre o código, você inicializou o @item_1, ele é uma string, esse @item_1 não é modificado em nenhum outro lugar, e depois lá na frente tem uma condição no update
@passos == @item_1.to_i,

veja o seguinte, to_i é um método que tem em vários objetos que convertem aquele objeto para Integer e retorna o valor, você faz isso em um update de um objeto que você não está mais modificando. Então pensando em como escrever melhor o código, esse to_i seria ideal direto na declaração da variável. Ex:

@item_1 = $data_items[1].note.scan(/steps:\s*(\d+)/).flatten.last.to_i


E não esqueça de tirar os print/p/puts do código quando for enviar para alguém  :XD: , tem um p @steps ai.





Espero que tudo isso tenha te ajudado, e continue escrevendo códigos por favor haha, com certeza vai aprender MUITO aqui  :XD:


Citação de: Raizen online 03/04/2020 às 21:58
Já que pediu avaliação bora  :malvado:

Primeira coisa, você fez as teclas com a Win32API porque queria aprender?
Você pode encontrar a implementação do Input para o RPG Maker aqui: https://www.rubydoc.info/github/cstrahan/open-rpg-maker/Input
Isso já inclui as teclas que você usou, no caso Teclas.key_input(Teclas::Left) , seria o mesmo que Input.press?(:LEFT)
Inclusive se olhar mais para baixo dessa página que mandei, tem implementação de todas as 4 teclas em um único método:


E considerando a parte que você está aprendendo no momento, esse module parece um catado de algum outro script  :XD:, por exemplo você está usando module_function, não que seja extremamente complexa, mas tem um certo nível ai, por isso acho que pode prosseguir com esse script usando o Input padrão do RPG Maker mesmo e ai futuramente ver sobre a WIn32API (que tem aulas muito boas aqui na CRM escritas pelo Kyo).

Agora chegando na classe Game_Player, não sei se sabe, mas já tem um contador de passos definido dentro do próprio código do Ace.

Você está refazendo o que já existe, não sei se sabia disso  :XD:, mas vamos deixar isso de lado e voltar ao aprendizado.

  def update
    super
    meu_update
   
    if Teclas.key_input(Teclas::Left) then
      @passos += 1
    end


perceba que sua variável de passos não está atrelado a nenhum momento ao passo em si e sim a tecla, o que isso significa, que não importa se o personagem der um passo, só de manter pressionado o contador sobe. Lembremos que o update roda em 60fps para o Ace, isso significa que a cada um segundo pressionado a tecla, vai contar 60 passos e é um número extremamente impreciso da real quantidade de passos.

Você tem que atrelar a incrementação dos passos ao ato de realizar o passo, quando você coloca na função de update isso não está tendo relação com os passos em si. É que já existe a função de incrementar os passos no Ace, mas supondo que não tenha, aonde seria o ideal para colocar esse @steps +=1?

Seria em uma função que faz o movimento do personagem e não no update, por exemplo eu mandei o personagem mover, então é ali que eu tenho que por esse @steps +=1. Vide exatamente o que o Ojima escreveu para o Ace (Tudo bem Ojima, dessa vez você está certo  :cowboy:)



Ele colocou no método "move_straight", que é a função que move de fato o personagem.
Veja um increase_steps dentro dele, pois bem, é ai que estaria o seu @steps += 1.




Mais alguns pontos sobre o código, você inicializou o @item_1, ele é uma string, esse @item_1 não é modificado em nenhum outro lugar, e depois lá na frente tem uma condição no update
@passos == @item_1.to_i,

veja o seguinte, to_i é um método que tem em vários objetos que convertem aquele objeto para Integer e retorna o valor, você faz isso em um update de um objeto que você não está mais modificando. Então pensando em como escrever melhor o código, esse to_i seria ideal direto na declaração da variável. Ex:

@item_1 = $data_items[1].note.scan(/steps:\s*(\d+)/).flatten.last.to_i


E não esqueça de tirar os print/p/puts do código quando for enviar para alguém  :XD: , tem um p @steps ai.





Espero que tudo isso tenha te ajudado, e continue escrevendo códigos por favor haha, com certeza vai aprender MUITO aqui  :XD:

Como eu implemento o dir4 no "Input.press?"? Eu dei uma olhado no link e vi el sendo colocado como:

def self.dir4()
    {coisas aqui}
end

No meu:

def self.dir4()
     $game_player.increase_steps
end


Eu tentei usar "Teclas::dir4", mas não funcionou (possivelmente porque não faz sentido).
^~^) -Rhyan.

tá no doc lá, ele diz o seguinte.

Input.dir4 vai retornar 0 se o direcional não for pressionado, e ai retorna 2, 4, 6 ou 8 dependendo do direcional que for pressionado.

Você usa direto, exemplo condição pressionar para cima.

if Input.dir4 == 8

Input.dir4 != 0, retornaria true quando qualquer direcionar for pressionado. Leia bem toda a minha resposta haha, coisa por coisa  :XD:

Eu tinha feito uma avaliação mais detalhada do seu código, mas, por acidente, fechei a aba antes de enviar e acabei perdendo tudo o que havia escrito. Apesar disso, irei sintetizar os principais pontos pra você.

Organização, objetividade e clareza são três coisas essências que você pode melhorar no seu código.

O código não possui nenhum comentário, nenhuma instrução ou explicação do que é realizado nele, quais seus requisitos ou configurações. Um código bem organizado não só é limpo, mas também bem documentado. Mesmo que não o tenha feito com intuito de disponibilizar as outras pessoas, deixar explicações ou comentários simples sobre cada método já fazem toda a diferença. Isso não é só para quem vai ler, mas para você também. Deixe passar uns dias sem mexer com o código, volte e tente entendê-lo, se não estiver bem organizado certamente terá que se esforçar um pouquinho para recordar todos os processos que realizou nele. Está aí um bom habito a se criar.

Como o Raizen já disse anteriormente, você acabou fazendo algumas coisas desnecessárias. Talvez até tenha sido bom como um exercício, mas, na prática, mais da metade do seu código poderia ser resumido com uma única linha. Objetividade é sempre o melhor caminho - o que não significa que seu código precisa ser totalmente compacto. Sabia que o RPG Maker já te disponibiliza uma variável que armazena o número de passos do jogador?
$game_party.steps


Não apenas nisso você pecou, mas também com a clareza do seu código. Você realizou todos os processos principais na classe Game_Player, mas ela certamente não é a melhor classe para fazer isso. Por que não, por exemplo, a Scene_Map? E falando na danada, por que o alias do método initialize se chama meu_alias_no_scene_map_start? E o alias meu_update? Quando falamos de alias é recomendável que eles possuam um nome único para que não entre em incompatibilidade com outros códigos que também o façam com o mesmo nome. Nesse caso, meu_update (e outros semelhantes) é um nome extremamente genérico e que, portanto, deve ser evitado e meu_alias_no_scene_map_start sequer faz sentido já que o método aliasado é o initialize e a classe é a Game_Player. Como o Syu disse um dia desses, um bom código se documenta por si próprio. Se não houver clareza naquilo que se é feito isso jamais irá acontecer.



Eu até tinha refeito seu código aqui, mas acredito que ainda possa ser um bom exercício deixá-lo refazê-lo com base nos comentários que receberá aqui. Por fim, recomendo que estude as Aulas de Ruby feitas pelo Syureri. Melhor do que tentar acertar a base da tentativa e erro é pegar um material didático e ,com comprometimento, estudá-lo a risca. Não pense que já sabe de algo e pule alguma aula, assista tudo do começo e faça todos exercícios passados, se dedicando a isso será impossível terminar todas as aulas sem saber programar. Se realmente quer aprender, conteúdo disponível você tem e em português ainda por cima.


Citação de: Gabriel online 03/04/2020 às 23:46
Eu tinha feito uma avaliação mais detalhada do seu código, mas, por acidente, fechei a aba antes de enviar e acabei perdendo tudo o que havia escrito. Apesar disso, irei sintetizar os principais pontos pra você.

Organização, objetividade e clareza são três coisas essências que você pode melhorar no seu código.

O código não possui nenhum comentário, nenhuma instrução ou explicação do que é realizado nele, quais seus requisitos ou configurações. Um código bem organizado não só é limpo, mas também bem documentado. Mesmo que não o tenha feito com intuito de disponibilizar as outras pessoas, deixar explicações ou comentários simples sobre cada método já fazem toda a diferença. Isso não é só para quem vai ler, mas para você também. Deixe passar uns dias sem mexer com o código, volte e tente entendê-lo, se não estiver bem organizado certamente terá que se esforçar um pouquinho para recordar todos os processos que realizou nele. Está aí um bom habito a se criar.

Como o Raizen já disse anteriormente, você acabou fazendo algumas coisas desnecessárias. Talvez até tenha sido bom como um exercício, mas, na prática, mais da metade do seu código poderia ser resumido com uma única linha. Objetividade é sempre o melhor caminho - o que não significa que seu código precisa ser totalmente compacto. Sabia que o RPG Maker já te disponibiliza uma variável que armazena o número de passos do jogador?
$game_party.steps


Não apenas nisso você pecou, mas também com a clareza do seu código. Você realizou todos os processos principais na classe Game_Player, mas ela certamente não é a melhor classe para fazer isso. Por que não, por exemplo, a Scene_Map? E falando na danada, por que o alias do método initialize se chama meu_alias_no_scene_map_start? E o alias meu_update? Quando falamos de alias é recomendável que eles possuam um nome único para que não entre em incompatibilidade com outros códigos que também o façam com o mesmo nome. Nesse caso, meu_update (e outros semelhantes) é um nome extremamente genérico e que, portanto, deve ser evitado e meu_alias_no_scene_map_start sequer faz sentido já que o método aliasado é o initialize e a classe é a Game_Player. Como o Syu disse um dia desses, um bom código se documenta por si próprio. Se não houver clareza naquilo que se é feito isso jamais irá acontecer.



Eu até tinha refeito seu código aqui, mas acredito que ainda possa ser um bom exercício deixá-lo refazê-lo com base nos comentários que receberá aqui. Por fim, recomendo que estude as Aulas de Ruby feitas pelo Syureri. Melhor do que tentar acertar a base da tentativa e erro é pegar um material didático e ,com comprometimento, estudá-lo a risca. Não pense que já sabe de algo e pule alguma aula, assista tudo do começo e faça todos exercícios passados, se dedicando a isso será impossível terminar todas as aulas sem saber programar. Se realmente quer aprender, conteúdo disponível você tem e em português ainda por cima.

Opa, na verdade, eu já estou com uma versão do código mais melhorado com as recomendações, vou só acabar ele que já atualizo! Obrigado Gabriel, vou passar lá!

EDIT: Nova versão já está no tópico.
^~^) -Rhyan.

Código atualizado.

- @passos foi trocado para @steps, uma variável que guarda "$game_party.steps".
- Alias de update e initialize alteradadas para "sapp_initialize" e "sapp_update".
- Agora, para a função ser executada, é necessário ter o item e a quantidade de passos especificada nas notas.
- Contagem de passos agora está funcionando direito.
- Número de if's reduzido para apenas um.
- Agora, a função que adiciona passos é "$game_player.increase_steps".
^~^) -Rhyan.

No seu código tem uma condição que nunca será satisfeita, que é:
Input.dir4 == [2,4,6,8]
#talvez estivesse querendo fazer isso?
[2,4,6,8].include?(Input.dir4)

O método dir4 do módulo Input sempre retorna um número inteiro, estes que não se comparam com Arrays. De todo modo, como já disseram, não é necessário neste caso chamar a função para acrescentar passos aí, o programa já faz isso por padrão. :XD:
Parando pra pensar mais um pouco, esse script não é algo tão simples pro seu nível. Hauhauae Tem que se considerar várias coisinhas pra fazer ele funcionar bunitinho. Mas espero que o seu aprendizado aqui seja útil. o/
E cadê o sistema de pulo? :grr:
Oxe


Começando de onde começa:


Scene_Map#initialize

Primeiro: o método initialize das cenas geralmente não é o melhor pra se usar. Prefira modificar o método start (vide Métodos do ciclo de vida em uma cena).

@item_1 = $data_items[1].note.scan(/steps:\s*(\d+)/).flatten.last.to_i


Tem dois problemas centrais aí, e um de menor relevância mas ainda importante.

O primeiro problema é que você pega valores das notas de um único item, que é sempre o mesmo. Não sei qual sua intenção para o script no futuro, mas existem situações onde faz sentido usar as notas do database, e situações onde não faz.

Um caso onde não faz sentido usar notas: quando você tem um único valor para o script todo, como é o seu caso, atualmente.
Nesse caso, ao invés de pegar as notas de um script, é mais simples e eficiente usar uma constante.

Um caso onde faz sentido usar notas: quando você tem vários valores para uma determinada variável no script, como seria seu caso se você tratasse não apenas um item, mas todos os itens no inventário, por exemplo.
Aliás, fica a sugestão: programe sempre para o caso mais amplo (N itens no inventário, qualquer um pode ou não ter a nota que ativa o script).

Nesse caso, seu código ficaria assim:

@step_items = $game_party.items.map { |item| item.note.scan(/steps:\s*(\d+)/).flatten.last.to_i }


O segundo problema mais grave nesse trecho é o .to_i sendo usado direto.

No caso feliz (o item tem a nota, e ela está bem formada), isso funciona. O scan retorna a string com o número de passos e panz, to_i converte.
Porém, imagine o caso em que o item não tem a nota: nessa circunstância, item.note.scan(/steps:\s*(\d+)/) retorna [], e portanto item.note.scan(/steps:\s*(\d+)/).flatten.last é o mesmo que [].flatten.last, que é o mesmo que [].last (afinal, [] não tem nenhum Array interno), que é nil.

Resumo da ópera: se o item 1 não tiver nas notas o que você espera, o valor dessa variável vira nil.to_i, que é 0.

Como não queremos isso, é necessário verificar esse caso e tratá-lo de forma diferente:

note_match = item.note.scan(/steps:\s*(\d+)/).flatten.last
if note_match.nil?
  @item_1 = nil # Sendo nil, podemos usar esse valor depois para não ativar o script
else
  @item_1 = note_match.to_i
end


Para o caso em que lidamos com todos os itens do inventário, a mesma lógica vale, mas o código fica até mais enxuto:

@step_items = $game_party.items.map { |item| item.note.scan(/steps:\s*(\d+)/).flatten.last }.compact.map(&:to_i)


Nesse código, o .compact é uma função que returna uma cópia do Array com todos os valores nil removidos, e o .map é uma função de ordem superior que retorna uma cópia do Array com uma função aplicada sobre cada elemento. O &:to_i é um atalho de sintaxe do ruby para { |x| x.to_i }.

O outro problema, menos grave mas ainda relevante, é o nome dessa variável. O que seria um item_1? Qualquer coisa que você colocar nessa variável que não seja um item, pra mim não faz o menor sentido. E porque _1? Onde estão os amigos dele, @item_2 e @item_3? Aliás, melhor, se a ideia é ter mais que um, porque não usar um Array (veja aqui, aqui, aqui e no Google)?

Em scripts menores não costuma ser muito problema, e pode não parecer muito importante logo que você escreve o script, mas nomes claros em variáveis ajudam muito a evitar problemas de compreensão no futuro.


Scene_Map#update

@steps = $game_party.steps


Me diga uma vantagem de usar uma variável de instância ao invés de acessar direto a variável global que te direi três desvantagens. Essa linha não deveria existir.

n = [2, 4, 6, 8]
   
if Input.dir4 == n then
  $game_player.increase_steps
end


Imagine um mundo onde existem Cabras e Leões: Cabras são definidas por números inteiros, e Leões são definidos pelas Cabras que comeram.

Alice é um Leão, que comeu quatro cabras: 2, 4, 6 e 8.
Suponha que Bob é alguma Cabra, com número de 0 a 9.

O que seu código me diz é: se Alice é igual a Bob, então aumente a contagem de passos do jogador.

Só tem um problema: Alice é um leão, Bob é uma cabra. Evidentemente, é impossível que Alice seja igual a Bob, porque são bichos diferentes por natureza.
Por outro lado, é possível que Alice tenha comido Bob: isso acontece nos casos em que Bob é a Cabra de número 2, 4, 6 ou 8. Agora troque Leão por Array, Cabra por Integer e "tenha comido" pelo método .include?, e tudo se aplica a Ruby.

É isto que seu código deveria perguntar, caso você quisesse que ele funcionasse:

if [2, 4, 6, 8].include?(Input.dir4)
  $game_player.increase_steps
end


Por outro lado, é positivo que ele não funcione: você não quer chamar o método $game_player.increase_steps.

Lembrando do comentário do Raizen:

Citação de: Raizãoperceba que sua variável de passos não está atrelado a nenhum momento ao passo em si e sim a tecla, o que isso significa, que não importa se o personagem der um passo, só de manter pressionado o contador sobe. Lembremos que o update roda em 60fps para o Ace, isso significa que a cada um segundo pressionado a tecla, vai contar 60 passos e é um número extremamente impreciso da real quantidade de passos.

Você não corrigiu isso. Chamando o $game_player.increase_steps você só troca a variável @passos pela $game_party.steps, mas ainda faz a contagem de forma errada. Aliás, mesmo que fizesse corretamente seria problema: o Game_Player já faz essa contagem pra você! Se você fizer a contagem de novo, vai contar dobrado.

if $game_party.has_item?($data_items[1]) && @steps == 60 then
  msgbox_p('affs, affs, affs, chatão :P')
end


Outro problema: aqui você compara @steps com 60, o número, constante. Pra que serve a @item_1, então? (ノಠ益ಠ)ノ彡┻━┻


Observações Gerais

Como você deve ter percebido, não tem uma linha do script que não tenha problemas, e acho que o mais grave é que o script não faz exatamente o que devia (você chegou a testar andar 60 passos com ele para ver se a mensagem aparecia? Tentou andar menos que 60 passos, pra ter certeza que a mensagem não aparecia antes do esperado?).

Sugiro que leia com bastante atenção as sugestões do pessoal, estude melhor o RGSS3 e o Ruby, e garanta que, no mínimo, tem domínio da lógica por trás da programação imperativa. Feliz ou infelizmente, linguagens de programação não têm consciência ou capacidade cognitiva própria e portanto não têm meios de entender sua intenção, por isso é preciso saber expressá-la da forma como a linguagem espera e o computador consegue reproduzir.

Algumas escolhas de design também estão estranhas, como por exemplo deixar a lógica do script na Scene_Map. No geral, prefira manter lógica de sistemas do jogo em objetos Game_. Nesse caso, seria interessante modificar as classes Game_Player e/ou Game_Party, que são as que têm a ver com inventário e passos.

Fiz o que considero que seria um bom script que solta alertas quando o número de passos determinado por um item é excedido, e enchi de comentários, sugiro que dê uma lida:

https://pastebin.com/CKjpNsJW

Como não tenho como testar agora, pode ser que falhe um método aqui ou ali, mas a ideia está toda aí e espero que os comentários ajudem bastante na compreensão.

Aliás, no geral, não comentamos código dessa forma que eu fiz aí; isso é só pra fins didáticos. Na maior parte do tempo você nem precisa comentar a menos que seja algo confuso ou que será usado por muita gente que não conhece o funcionamento interno do seu código. Por outro lado, visto que você está aprendendo, recomendo que você tente comentar seus scripts descrevendo bem o que eles estão fazendo a cada passo. Isso pode ser útil pra você mesmo criar consciência do que faz ou não faz sentido e de como funciona a programação.
~ Masked

Brandt, como sua resposta é longa, deixarei a mesma em um spoiler.
Spoiler

Citação de: Brandt online 04/04/2020 às 16:26

Começando de onde começa:


Scene_Map#initialize

Primeiro: o método initialize das cenas geralmente não é o melhor pra se usar. Prefira modificar o método start (vide Métodos do ciclo de vida em uma cena).

@item_1 = $data_items[1].note.scan(/steps:\s*(\d+)/).flatten.last.to_i


Tem dois problemas centrais aí, e um de menor relevância mas ainda importante.

O primeiro problema é que você pega valores das notas de um único item, que é sempre o mesmo. Não sei qual sua intenção para o script no futuro, mas existem situações onde faz sentido usar as notas do database, e situações onde não faz.

Um caso onde não faz sentido usar notas: quando você tem um único valor para o script todo, como é o seu caso, atualmente.
Nesse caso, ao invés de pegar as notas de um script, é mais simples e eficiente usar uma constante.

Um caso onde faz sentido usar notas: quando você tem vários valores para uma determinada variável no script, como seria seu caso se você tratasse não apenas um item, mas todos os itens no inventário, por exemplo.
Aliás, fica a sugestão: programe sempre para o caso mais amplo (N itens no inventário, qualquer um pode ou não ter a nota que ativa o script).

Nesse caso, seu código ficaria assim:

@step_items = $game_party.items.map { |item| item.note.scan(/steps:\s*(\d+)/).flatten.last.to_i }


O segundo problema mais grave nesse trecho é o .to_i sendo usado direto.

No caso feliz (o item tem a nota, e ela está bem formada), isso funciona. O scan retorna a string com o número de passos e panz, to_i converte.
Porém, imagine o caso em que o item não tem a nota: nessa circunstância, item.note.scan(/steps:\s*(\d+)/) retorna [], e portanto item.note.scan(/steps:\s*(\d+)/).flatten.last é o mesmo que [].flatten.last, que é o mesmo que [].last (afinal, [] não tem nenhum Array interno), que é nil.

Resumo da ópera: se o item 1 não tiver nas notas o que você espera, o valor dessa variável vira nil.to_i, que é 0.

Como não queremos isso, é necessário verificar esse caso e tratá-lo de forma diferente:

note_match = item.note.scan(/steps:\s*(\d+)/).flatten.last
if note_match.nil?
  @item_1 = nil # Sendo nil, podemos usar esse valor depois para não ativar o script
else
  @item_1 = note_match.to_i
end


Para o caso em que lidamos com todos os itens do inventário, a mesma lógica vale, mas o código fica até mais enxuto:

@step_items = $game_party.items.map { |item| item.note.scan(/steps:\s*(\d+)/).flatten.last }.compact.map(&:to_i)


Nesse código, o .compact é uma função que returna uma cópia do Array com todos os valores nil removidos, e o .map é uma função de ordem superior que retorna uma cópia do Array com uma função aplicada sobre cada elemento. O &:to_i é um atalho de sintaxe do ruby para { |x| x.to_i }.

O outro problema, menos grave mas ainda relevante, é o nome dessa variável. O que seria um item_1? Qualquer coisa que você colocar nessa variável que não seja um item, pra mim não faz o menor sentido. E porque _1? Onde estão os amigos dele, @item_2 e @item_3? Aliás, melhor, se a ideia é ter mais que um, porque não usar um Array (veja aqui, aqui, aqui e no Google)?

Em scripts menores não costuma ser muito problema, e pode não parecer muito importante logo que você escreve o script, mas nomes claros em variáveis ajudam muito a evitar problemas de compreensão no futuro.


Scene_Map#update

@steps = $game_party.steps


Me diga uma vantagem de usar uma variável de instância ao invés de acessar direto a variável global que te direi três desvantagens. Essa linha não deveria existir.

n = [2, 4, 6, 8]
   
if Input.dir4 == n then
  $game_player.increase_steps
end


Imagine um mundo onde existem Cabras e Leões: Cabras são definidas por números inteiros, e Leões são definidos pelas Cabras que comeram.

Alice é um Leão, que comeu quatro cabras: 2, 4, 6 e 8.
Suponha que Bob é alguma Cabra, com número de 0 a 9.

O que seu código me diz é: se Alice é igual a Bob, então aumente a contagem de passos do jogador.

Só tem um problema: Alice é um leão, Bob é uma cabra. Evidentemente, é impossível que Alice seja igual a Bob, porque são bichos diferentes por natureza.
Por outro lado, é possível que Alice tenha comido Bob: isso acontece nos casos em que Bob é a Cabra de número 2, 4, 6 ou 8. Agora troque Leão por Array, Cabra por Integer e "tenha comido" pelo método .include?, e tudo se aplica a Ruby.

É isto que seu código deveria perguntar, caso você quisesse que ele funcionasse:

if [2, 4, 6, 8].include?(Input.dir4)
  $game_player.increase_steps
end


Por outro lado, é positivo que ele não funcione: você não quer chamar o método $game_player.increase_steps.

Lembrando do comentário do Raizen:

Você não corrigiu isso. Chamando o $game_player.increase_steps você só troca a variável @passos pela $game_party.steps, mas ainda faz a contagem de forma errada. Aliás, mesmo que fizesse corretamente seria problema: o Game_Player já faz essa contagem pra você! Se você fizer a contagem de novo, vai contar dobrado.

if $game_party.has_item?($data_items[1]) && @steps == 60 then
  msgbox_p('affs, affs, affs, chatão :P')
end


Outro problema: aqui você compara @steps com 60, o número, constante. Pra que serve a @item_1, então? (ノಠ益ಠ)ノ彡┻━┻


Observações Gerais

Como você deve ter percebido, não tem uma linha do script que não tenha problemas, e acho que o mais grave é que o script não faz exatamente o que devia (você chegou a testar andar 60 passos com ele para ver se a mensagem aparecia? Tentou andar menos que 60 passos, pra ter certeza que a mensagem não aparecia antes do esperado?).

Sugiro que leia com bastante atenção as sugestões do pessoal, estude melhor o RGSS3 e o Ruby, e garanta que, no mínimo, tem domínio da lógica por trás da programação imperativa. Feliz ou infelizmente, linguagens de programação não têm consciência ou capacidade cognitiva própria e portanto não têm meios de entender sua intenção, por isso é preciso saber expressá-la da forma como a linguagem espera e o computador consegue reproduzir.

Algumas escolhas de design também estão estranhas, como por exemplo deixar a lógica do script na Scene_Map. No geral, prefira manter lógica de sistemas do jogo em objetos Game_. Nesse caso, seria interessante modificar as classes Game_Player e/ou Game_Party, que são as que têm a ver com inventário e passos.

Fiz o que considero que seria um bom script que solta alertas quando o número de passos determinado por um item é excedido, e enchi de comentários, sugiro que dê uma lida:

https://pastebin.com/CKjpNsJW

Como não tenho como testar agora, pode ser que falhe um método aqui ou ali, mas a ideia está toda aí e espero que os comentários ajudem bastante na compreensão.

Aliás, no geral, não comentamos código dessa forma que eu fiz aí; isso é só pra fins didáticos. Na maior parte do tempo você nem precisa comentar a menos que seja algo confuso ou que será usado por muita gente que não conhece o funcionamento interno do seu código. Por outro lado, visto que você está aprendendo, recomendo que você tente comentar seus scripts descrevendo bem o que eles estão fazendo a cada passo. Isso pode ser útil pra você mesmo criar consciência do que faz ou não faz sentido e de como funciona a programação.
[close]

Na verdade, o script será para vários itens, não apenas um, coloquei apenas um só para testar mesmo. Verdade, irei implementar isso, o script lida com todos os itens do inventário. Os amigos do @item_1 ainda não chegaram ao mundo ainda, eles pegaram um grande trânsito aéreo, mas eles irão chegar!  Fui ver no post do Raizen que você colocou, sobre as arrays e decidi que realmente é uma melhor opção. Quanto ao @steps, foi apenas para encurtar, mas mudarei para o $game_party.steps mesmo. Irei consertar isso!
KKK, sobre isso, eu mesmo quando fui rever o script, vi essa burrada, já foi trocada.

Vou estudar mais, rever as aulas do Khas, ver os vídeos que o Raizen mandou e ler mais! Obrigado, Brandt!

E sim, eu testei e estava funcionando corretamente (conta de um em um, aparecendo a mensagem se estivesse com o item e com o número de passos necessários, etc.
^~^) -Rhyan.

Citação de: Jorge_Maker online 04/04/2020 às 16:25
No seu código tem uma condição que nunca será satisfeita, que é:
Input.dir4 == [2,4,6,8]
#talvez estivesse querendo fazer isso?
[2,4,6,8].include?(Input.dir4)

O método dir4 do módulo Input sempre retorna um número inteiro, estes que não se comparam com Arrays. De todo modo, como já disseram, não é necessário neste caso chamar a função para acrescentar passos aí, o programa já faz isso por padrão. :XD:
Parando pra pensar mais um pouco, esse script não é algo tão simples pro seu nível. Hauhauae Tem que se considerar várias coisinhas pra fazer ele funcionar bunitinho. Mas espero que o seu aprendizado aqui seja útil. o/
E cadê o sistema de pulo? :grr:

Implementando! Obrigado, Jorge Maker!!!
^~^) -Rhyan.