- Сообщений: 188
- Спасибо получено: 280
[VX Ace] Фикс скрипта мыши
5 года 2 мес. назад - 3 года 5 мес. назад #121717
от Phileas
Phileas создал тему: [VX Ace] Фикс скрипта мыши
Некоторым людям, особенно после выхода MV, стало не хватать возможности манипулирования курсором мыши в проектах на VX Ace.
Однако многие скрипты мышей вызывают исключение при выходе на титульник через f12, потому что f12 просто вызывает скрипт Main, в котором вызывается SceneManager.run, где заново инициализируется вся база данных, что приводит к обращению переменной мыши в nil.
Выше был краткий пересказ проблемы, теперь расскажу, как я это вылечил.
Лечил я только 1 скрипт (под авторством Shaz), однако аналогичное решение должно помочь и другим таким скриптам.
Сначала приведу код самого скрипта (исправленный):
В скрипте я просто добавил в 130 строчку вот это:
Ещё я такой же код добавил в 208 строчку, но это, скорее всего, лишнее (данная функция вообще не должна вызваться, если переменная мыши не проинициализирована).
Однако это позволяет лишь избежать исключения. Как же нам "воскресить" мышь при перезапуске игры? Очень просто, надо всего лишь вызвать конструктор заново.
Заходим в SceneManager (в скриптах в самом верху списка), находим self.run.
Там добавляем одну строчку:
На всякий случай, уточню, я добавил вот эту строчку:
UPD! (04.12.2022)
По просьбе форумчанина, добавил ещё вот такой код в скрипт:
Он убирает курсор со скриншота экрана, который ставится фоном игрового меню. Может возникнуть конфликт с другим скриптом, который тоже переопределяет этот метод.
Также добавил исправление от Dmy, которое решает проблему игр с кириллицей в названии.
Собственно, всё. Вот пустой проект, в котором демонстрируется работа исправленного скрипта:
проект
Если у вас что-то не получается, что-то не работает - пишите в этой теме, постараюсь помочь.
Однако многие скрипты мышей вызывают исключение при выходе на титульник через f12, потому что f12 просто вызывает скрипт Main, в котором вызывается SceneManager.run, где заново инициализируется вся база данных, что приводит к обращению переменной мыши в nil.
Выше был краткий пересказ проблемы, теперь расскажу, как я это вылечил.
Лечил я только 1 скрипт (под авторством Shaz), однако аналогичное решение должно помочь и другим таким скриптам.
Сначала приведу код самого скрипта (исправленный):
скрипт мыши
Code:
#============================================================================
# SUPER SIMPLE MOUSE SCRIPT
# v1.11 by Shaz (fixed by Phileas and Dmy)
#----------------------------------------------------------------------------
# This is a conversion of the XP Mouse script by Near Fantastica and
# SephirothSpawn modified by Amaranth Games, to run under VX Ace.
#----------------------------------------------------------------------------
# To Install:
# Copy and paste into a new slot in materials, below all other scripts
#----------------------------------------------------------------------------
# To Customize:
# Add keyword icon index pairs to the ICON hash (below this documentation).
# Each of the keywords can be used in an event comment to make the mouse
# cursor change into that icon when hovering over the event.
#----------------------------------------------------------------------------
# To Use:
# Add the following comment to an event page:
# <mouse icon [x y] [name]>
# where icon is the keyword from the ICON hash below
# x and y are the offsets to override player movement (optional)
# name is the text to display next to the icon when hovering over the event (optional)
#
# Examples:
# <mouse fight>
# will change the cursor into the 'fight' icon when over the event
# <mouse touch 0 1>
# will change the cursor into the 'touch' icon when over the event, and
# make the player walk to the tile below the event when the mouse button is
# clicked
# <mouse talk Gloria>
# will change the cursor into the 'talk' icon and display the name Gloria
# <mouse talk 0 2 Henry Smith>
# will change the cursor into the 'talk' icon and display the name Henry Smith,
# and when the mouse button is clicked, the player will walk to the tile
# two below the event (good to use for shops where there's a counter in between)
#
# To force pathfinding on the player or an event, simply add a move route with
# the player or event as the subject, with a Script command, and call
# find_path(x, y) where x and y are the coordinates of the tile you want to move to
# Examples:
# Set Move Route (Player): Script: find_path(5, 8)
# will make the player find a path to tile 5, 8
# Set Move Route (This Event): Script: find_path(10, 5)
# will make the event find a path to tile 10, 5
#
# NOTE: The path will be ATTEMPTED. If there is no path TO that exact tile,
# a path to an adjacent tile will be attempted. If no path is found there
# either, no movement will occur.
# If a route is found, the player or event will begin moving towards it. But
# if their path is blocked while they are moving, movement will be cancelled.
#----------------------------------------------------------------------------
# Author's Notes:
# This script should work with any RTP script.
# I do not guarantee that it will work with ANY other script (especially anything
# that overrides player or event movement, such as pixel movement scripts, or
# custom window scripts).
#
# Script OVERWRITES the following methods:
# Game_Map.setup_starting_map_event
# Game_Map.setup_autorun_common_event
#
# If you have other scripts that ALIAS these methods, this mouse script should
# be placed above them.
#----------------------------------------------------------------------------
# Terms:
# Use in free and commercial games
# Credit: Near Fantastica, SephirothSpawn, Amaranth Games, Shaz
#----------------------------------------------------------------------------
# Versions:
# 1.0 - 6 Sept 2013 - initial release
# 1.02 - 7 Sept 2013 - fixed crash when loading games saved prior to adding script
# - fixed player gets stuck on impassable area on world map
# when clicking while leaving air ship
# 1.03 - 8 Sept 2013 - fixed actor moving to diagonal tile instead of adjacent
# 1.04 - 10 Sept 2013 - fixed vehicle pathfinding on world map
# - fixed event trigger when no path found
# 1.05 - 14 Sept 2013 - tweaked accessing of tilemap offset
# 1.06 - 3 Nov 2013 - disabled mouse movement when waiting for NPC move route
# - fixed events not triggering after player finishes walking
# 1.07 - 6 Nov 2013 - slow down mouse scrolling, and don't loop save files
# 1.08 - 24 Nov 2013 - cater for YEA Core large resolution with too-small maps
# - fixed early event activation bug introduced in 1.06
# - replaced calc of Windows_Selectable boundaries with item_rect
# - added ability to completely disable mouse
# 1.09 - 21 Dec 2013 - fixed mouse re-enable when calling common events
# 1.10 - 6 Apr 2014 - add interaction for top part of > 32pixel high event
# - activate an event without walking up to it
# (add <autoactivate> comment at top of event page)
# - arrow keys override mouse movement when pathfinding
# - ignore mouse in menus when using keyboard
# - make player walk to counter opposite shopkeepers
#============================================================================
#============================================================================
# SUPER SIMPLE MOUSE SCRIPT
# Mouse Sprite
#============================================================================
# Add/remove/change icon names here. The icon name is what will be used in the
# event <mouse ...> command to show a different mouse icon when hovering over
# the event. These MUST be in lower case here!
ICON = {'arrow' => 386, 'talk' => 4, 'look' => 3, 'fight' => 116,
'touch' => 491, 'exit' => 121, 'empty' => 1}
DEFAULT_ICON = 'arrow'
class Sprite_Mouse < Sprite
#--------------------------------------------------------------------------
# * Initialization
#--------------------------------------------------------------------------
def initialize
super
self.z = 10100
self.ox = 4
update
@dummy = Bitmap.new(32, 32)
self.bitmap = Bitmap.new(32, 32)
@enabled = true
@ignored = false
end
#--------------------------------------------------------------------------
# * Frame Update
#--------------------------------------------------------------------------
def update
return if $mouse == nil
return if !@enabled
super
if !SceneManager.scene.nil?
if !Mouse.position.nil?
mx, my = *Mouse.position
if @cursor == DEFAULT_ICON
self.x = mx unless mx.nil?
else
self.x = [mx, Graphics.width - self.bitmap.width].min unless mx.nil?
end
self.y = my unless my.nil?
end
if @scene != SceneManager.scene.class || Mouse.trigger?
@scene = SceneManager.scene.class
set_bitmap
end
end
end
#--------------------------------------------------------------------------
# * Set Bitmap
#--------------------------------------------------------------------------
def set_bitmap(cursor = DEFAULT_ICON, text = nil)
if @ignored
cursor = DEFAULT_ICON
text = nil
end
if @cursor != cursor || @text != text
@cursor = cursor
@text = text
item_cursor = ICON[cursor]
rect = Rect.new(item_cursor % 16 * 24, item_cursor / 16 * 24, 24, 24)
if @text.nil?
self.bitmap = Bitmap.new(24, 32)
self.bitmap.blt(0, 0, Cache.system('Iconset'), rect)
else
w = @dummy.text_size(@text).width
h = @dummy.font.size
bitmap = Bitmap.new(26 + w, [32, h+2].max)
bitmap.font.size = @dummy.font.size
bitmap.font.shadow = true
if self.x + 26 + w > Graphics.width
bitmap.draw_text(0, 0, w, h, @text)
bitmap.blt(w, 0, Cache.system('Iconset'), rect)
else
bitmap.blt(0, 0, Cache.system('Iconset'), rect)
bitmap.draw_text(26, 0, w, h, @text)
end
self.bitmap = bitmap
end
end
end
#--------------------------------------------------------------------------
# * Update Event Cursors
#--------------------------------------------------------------------------
def update_event_cursors
# Remove mouse icon and text if we're off the grid
if Mouse.grid.nil?
set_bitmap
return
end
# Set cursor and text according to event
x, y = *Mouse.grid
event = $game_map.lowest_mouse_event_xy(x, y)
unless event.nil? && y < 410
if !event.mouse_icon.nil? || !event.mouse_text.nil?
set_bitmap(event.mouse_icon, event.mouse_text)
return
end
end
# default bitmap if not over an event
set_bitmap
end
#--------------------------------------------------------------------------
# * Enable Mouse
#--------------------------------------------------------------------------
def enabled=(value)
return if $mouse == nil
@enabled = value
self.visible = value
end
#--------------------------------------------------------------------------
# * Mouse Enabled?
#--------------------------------------------------------------------------
def enabled?
@enabled
end
#--------------------------------------------------------------------------
# * Ignore Mouse
#--------------------------------------------------------------------------
def ignored=(value)
@ignored = value
end
#--------------------------------------------------------------------------
# * Mouse Ignored?
#--------------------------------------------------------------------------
def ignored?
@ignored
end
end
$mouse = Sprite_Mouse.new
#============================================================================
# SUPER SIMPLE MOUSE SCRIPT
# Mouse Module
#============================================================================
#==============================================================================
# ** Mouse Module
#------------------------------------------------------------------------------
# by Near Fantastica and SephirothSpawn
# adapted and converted to VX Ace by Shaz
#==============================================================================
module Mouse
#--------------------------------------------------------------------------
# * Mouse to Input Triggers
# key => Input::KeyCONSTANT (key: 0 - left, 1 - middle, 2 - right)
#--------------------------------------------------------------------------
Mouse_to_Input_Triggers = {0 => Input::C, 1 => Input::B, 2 => Input::A}
#--------------------------------------------------------------------------
# * API Declarations
#--------------------------------------------------------------------------
GAKS = Win32API.new('user32', 'GetAsyncKeyState', 'i', 'i')
GSM = Win32API.new('user32', 'GetSystemMetrics', 'i', 'i')
Cursor_Pos = Win32API.new('user32', 'GetCursorPos', 'p', 'i')
Scr2cli = Win32API.new('user32', 'ScreenToClient', %w(l p), 'i')
Client_rect = Win32API.new('user32', 'GetClientRect', %w(l p), 'i')
Findwindow = Win32API.new('user32', 'FindWindowA', %w(p p), 'l')
Readini = Win32API.new('kernel32', 'GetPrivateProfileStringA', %w(p p p p l p), 'l')
ShowCursor = Win32API.new('user32', 'ShowCursor', 'i', 'l')
#--------------------------------------------------------------------------
# * Module Variables
#--------------------------------------------------------------------------
@triggers = [[0, 1], [0, 2], [0, 4]]
@old_pos = 0
@pos_i = 0
@sys_cursor_visible = false
#--------------------------------------------------------------------------
# * Mouse Grid Position
#--------------------------------------------------------------------------
def self.grid
return nil if @pos.nil?
mx, my = SceneManager.scene.instance_variable_get(:@spriteset).tilemap_offset
x = (@pos[0] + mx) / 32
y = (@pos[1] + my) / 32
return [x, y]
end
#--------------------------------------------------------------------------
# * Mouse Position
#--------------------------------------------------------------------------
def self.position
return @pos.nil? ? [0, 0] : @pos
end
#--------------------------------------------------------------------------
# * Mouse Global Position
#--------------------------------------------------------------------------
def self.global_pos
pos = [0, 0].pack('ll')
return Cursor_Pos.call(pos) == 0 ? nil : pos.unpack('ll')
end
#--------------------------------------------------------------------------
# * Screen to Client
#--------------------------------------------------------------------------
def self.screen_to_client(x=0, y=0)
pos = [x, y].pack('ll')
return Scr2cli.call(self.hwnd, pos) == 0 ? nil : pos.unpack('ll')
end
#--------------------------------------------------------------------------
# * Mouse Position
#--------------------------------------------------------------------------
def self.pos
gx, gy = global_pos
x, y = screen_to_client(gx, gy)
# Test boundaries
begin
if (x >= 0 && y >= 0 && x <= Graphics.width && y <= Graphics.height)
return x, y
else
return -20, -20
end
rescue
return 0, 0
end
end
#--------------------------------------------------------------------------
# * Update Mouse Position
#--------------------------------------------------------------------------
def self.update
old_pos = @pos
@pos = self.pos
# Has mouse been moved?
if old_pos != @pos
Input.method = :mouse
end
# Which mouse to show - custom, or system?
if $mouse.enabled? == @sys_cursor_visible
@sys_cursor_visible = !@sys_cursor_visible
ShowCursor.call(@sys_cursor_visible ? 1 : 0)
end
return if !$mouse.enabled?
# Leaving / Entering Range?
if old_pos != [-20, -20] && @pos == [-20, -20] # leaving range
ShowCursor.call(1)
elsif old_pos == [-20, -20] && @pos != [-20, -20] # entering range
ShowCursor.call(0)
end
# Update Triggers
for i in @triggers
n = GAKS.call(i[1])
if [0, 1].include?(n)
i[0] = (i[0] > 0 ? i[0] * -1 : 0)
else
i[0] = (i[0] > 0 ? i[0] + 1 : 1)
end
end
end
#--------------------------------------------------------------------------
# * Trigger?
# id : 0:Left, 1:Right, 2:Center
#--------------------------------------------------------------------------
def self.trigger?(id = 0)
if pos != [-20, -20]
return @triggers[id][0] == 1
end
return false
end
#--------------------------------------------------------------------------
# * Repeat?
# id : 0:Left, 1:Right, 2:Center
#--------------------------------------------------------------------------
def self.repeat?(id = 0)
return @triggers[id][0] > 0 && @triggers[id][0] % 5 == 1
end
#--------------------------------------------------------------------------
# * Hwnd
#--------------------------------------------------------------------------
def self.hwnd
if @hwnd.nil?
title = "\0" * 256
Readini.call('Game', 'Title', '', title, 255, '.\\Game.ini')
title.force_encoding("ASCII-8bit")
title.delete!("\0")
@hwnd = Findwindow.call('RGSS Player', title)
ShowCursor.call(0)
end
return @hwnd
end
#--------------------------------------------------------------------------
# * Client Size
#--------------------------------------------------------------------------
def self.client_size
rect = [0, 0, 0, 0].pack('l4')
Client_rect.call(self.hwnd, rect)
return rect.unpack('l4')[2..3]
end
end
#============================================================================
# SUPER SIMPLE MOUSE SCRIPT
# Input
#============================================================================
class << Input
#--------------------------------------------------------------------------
# * Public Instance Variables
#--------------------------------------------------------------------------
attr_accessor :method
#--------------------------------------------------------------------------
# * Alias Listings
#--------------------------------------------------------------------------
alias :seph_mouse_input_update :update
alias :seph_mouse_input_trigger? :trigger?
alias :seph_mouse_input_repeat? :repeat?
#--------------------------------------------------------------------------
# * Frame Update
#--------------------------------------------------------------------------
def update
$mouse.update
Mouse.update
seph_mouse_input_update
# Are we using the mouse or the keyboard?
@method = :keyboard if dir4 != 0 || dir8 != 0
end
#--------------------------------------------------------------------------
# * Trigger? Test
#--------------------------------------------------------------------------
def trigger?(constant)
return true if seph_mouse_input_trigger?(constant)
if $mouse.enabled? && !Mouse.pos.nil?
if Mouse::Mouse_to_Input_Triggers.has_value?(constant)
return true if Mouse.trigger?(Mouse::Mouse_to_Input_Triggers.index(constant))
end
end
return false
end
#--------------------------------------------------------------------------
# * Repeat? Test
#--------------------------------------------------------------------------
def repeat?(constant)
return true if seph_mouse_input_repeat?(constant)
if $mouse.enabled? && !Mouse.pos.nil?
if Mouse::Mouse_to_Input_Triggers.has_value?(constant)
return true if Mouse.repeat?(Mouse::Mouse_to_Input_Triggers.index(constant))
end
end
return false
end
end
#============================================================================
# SUPER SIMPLE MOUSE SCRIPT
# Map
#============================================================================
class Spriteset_Map
#--------------------------------------------------------------------------
# * Tilemap Offset
#--------------------------------------------------------------------------
def tilemap_offset
if $imported && $imported["YEA-CoreEngine"]
[@tilemap.ox - @viewport1.rect.x, @tilemap.oy - @viewport1.rect.y]
else
[@tilemap.ox, @tilemap.oy]
end
end
end
class Game_Map
#--------------------------------------------------------------------------
# * Detect/Set Up Starting Map Event
#--------------------------------------------------------------------------
def setup_starting_map_event
event = @events.values.find {|event| event.starting }
event.clear_starting_flag if event
@interpreter.setup(event.list, event.id, event.trigger_in?([0,1,2,3])) if event
event
end
#--------------------------------------------------------------------------
# * Detect/Set Up Autorun Common Event
#--------------------------------------------------------------------------
def setup_autorun_common_event
event = $data_common_events.find do |event|
event && event.autorun? && $game_switches[event.switch_id]
end
@interpreter.setup(event.list, 0, true) if event
event
end
#--------------------------------------------------------------------------
# * Get ID of Lowest Mouse-enabled Event at Designated Coordinates
#--------------------------------------------------------------------------
def lowest_mouse_event_xy(x, y)
list = events_xy(x, y) + events_xy(x, y+1)
list.sort! {|a, b| b.y - a.y}
evt = nil
list.each do |event|
if (event.pos?(x, y) || (event.pos?(x, y+1) && event.height > 32)) &&
(evt.nil? || event.y > evt.y)
evt = event
break
end
end
return evt
end
end
class Scene_Map
#--------------------------------------------------------------------------
# * Frame Update
#--------------------------------------------------------------------------
alias shaz_mouse_scene_map_update update
def update
$mouse.update_event_cursors
shaz_mouse_scene_map_update
end
end
#============================================================================
# SUPER SIMPLE MOUSE SCRIPT
# Event
#============================================================================
module RPG
class Event
class Page
#--------------------------------------------------------------------
# * Public Instance Variables
#--------------------------------------------------------------------
attr_reader :mouse_icon
attr_reader :mouse_text
attr_reader :mouse_position
attr_reader :mouse_autoactivate
#--------------------------------------------------------------------
# * Build Stats
#--------------------------------------------------------------------
def build_stats
# Mouse icons (icon mandatory, others optional)
# <mouse icon destx desty name>
@mouse_icon = nil
@mouse_text = nil
@mouse_position = [0, 0]
@mouse_autoactivate = false
# look for mouse instructions
list.each do |command|
if [108, 408].include?(command.code)
comment = command.parameters[0]
case comment
when /<mouse/i
params = /<mouse (.*)>/i.match(comment)[1].split(' ')
@mouse_icon = params.shift
if params.size > 1 && params[0] =~ /\d+/ && params[1] =~ /\d+/
@mouse_position = [params.shift.to_i, params.shift.to_i]
end
if params.size > 0
@mouse_text = params.join(' ')
end
when /<autoactivate>/
@mouse_autoactivate = true
end
end #if
end #do
end #def
end
end
end
class Game_Event < Game_Character
#--------------------------------------------------------------------------
# * Public Instance Variables
#--------------------------------------------------------------------------
attr_reader :mouse_icon
attr_reader :mouse_text
attr_reader :mouse_position
attr_reader :mouse_autoactivate
#--------------------------------------------------------------------------
# * Start Event
#--------------------------------------------------------------------------
alias shaz_mouse_game_event_start start
def start
$game_player.start_event(@id) if !empty?
shaz_mouse_game_event_start
end
#--------------------------------------------------------------------------
# * Clear Event Page Settings
#--------------------------------------------------------------------------
alias shaz_mouse_game_event_clear_page_settings clear_page_settings
def clear_page_settings
shaz_mouse_game_event_clear_page_settings
@mouse_icon = nil
@mouse_text = nil
@mouse_position = [0, 0]
@mouse_autoactivate = false
@height = 0
end
#--------------------------------------------------------------------------
# * Set Up Event Page Settings
#--------------------------------------------------------------------------
alias shaz_mouse_game_event_setup_page_settings setup_page_settings
def setup_page_settings
shaz_mouse_game_event_setup_page_settings
@page.build_stats
@mouse_icon = @page.mouse_icon
@mouse_text = @page.mouse_text
@mouse_position = @page.mouse_position
@mouse_autoactivate = @page.mouse_autoactivate
set_size
end
end
#============================================================================
# SUPER SIMPLE MOUSE SCRIPT
# Character
#============================================================================
class Game_CharacterBase
attr_reader :height # Height of character bitmap
#--------------------------------------------------------------------------
# * Initialize Public Member Variables
#--------------------------------------------------------------------------
alias shaz_mouse_game_characterbase_init_public_members init_public_members
def init_public_members
shaz_mouse_game_characterbase_init_public_members
@height = 0
end
#--------------------------------------------------------------------------
# * Change Graphics
# character_name : new character graphic filename
# character_index : new character graphic index
#--------------------------------------------------------------------------
alias shaz_mouse_game_characterbase_set_graphic set_graphic
def set_graphic(character_name, character_index)
shaz_mouse_game_characterbase_set_graphic(character_name, character_index)
set_size
end
#--------------------------------------------------------------------------
# * Set character width/height size
#--------------------------------------------------------------------------
def set_size
bw = Cache.character(@character_name).width
bh = Cache.character(@character_name).height
sign = @character_name[/^[\!\$]./]
if sign && sign.include?('$')
@width = bw / 3
@height = bh / 4
else
@width = bw / 12
@height = bh / 8
end
end
#--------------------------------------------------------------------------
# * Detect Collision with Event
#--------------------------------------------------------------------------
def collide_with_events?(x, y)
$game_map.events_xy_nt(x, y).any? do |event|
self != event && (event.normal_priority? || self.is_a?(Game_Event))
end
end
#--------------------------------------------------------------------------
# * Detect Collision with Vehicle
#--------------------------------------------------------------------------
def collide_with_vehicles?(x, y)
!self.is_a?(Game_Player) && ($game_map.boat.pos_nt?(x, y) || $game_map.ship.pos_nt?(x, y))
end
#--------------------------------------------------------------------------
# * Frame Update
#--------------------------------------------------------------------------
alias shaz_mouse_game_characterbase_update update
def update
run_path if @runpath
shaz_mouse_game_characterbase_update
end
#--------------------------------------------------------------------------
# * Run Path
#--------------------------------------------------------------------------
def run_path
return if moving?
@step = @map.nil? || @map[@x, @y].nil? ? 0 : @map[@x, @y] - 1
if @step < 1
clear_path
else
x, y = @x, @y
dirs = []
dirs.push(6) if @map[@x+1, @y] == @step && passable?(@x, @y, 6)
dirs.push(2) if @map[@x, @y+1] == @step && passable?(@x, @y, 2)
dirs.push(4) if @map[@x-1, @y] == @step && passable?(@x, @y, 4)
dirs.push(8) if @map[@x, @y-1] == @step && passable?(@x, @y, 8)
while dirs.size > 0
dir = dirs.delete_at(rand(dirs.size))
move_straight(dir)
break if x != @x || y != @y
end
# clear the path if we couldn't move
clear_path if x == @x && y == @y
end
end
#--------------------------------------------------------------------------
# * Find Path
#--------------------------------------------------------------------------
def find_path(x, y)
sx, sy = @x, @y
@tx, @ty = x, y
result = setup_map(sx, sy)
@runpath = result[0]
@map = result[1]
@map[sx, sy] = result[2] if result[2] != nil
end
#--------------------------------------------------------------------------
# * Clear Path
#--------------------------------------------------------------------------
def clear_path
@map = nil
@runpath = false
end
#--------------------------------------------------------------------------
# * Setup Map
#--------------------------------------------------------------------------
def setup_map(sx, sy)
map = Table.new($game_map.width, $game_map.height)
update_counter = 0
map[@tx, @ty] = 1
old_positions = [[@tx, @ty]]
new_positions = []
# if tile is impassable, but CAN move to adjacent tiles, use the adjacent tiles instead
if (!passable?(@tx, @ty, 2) && !passable?(@tx, @ty, 4) &&
!passable?(@tx, @ty, 6) && !passable?(@tx, @ty, 8)) ||
$game_map.events_xy_nt(@tx, @ty).any? { |evt| evt.normal_priority? && evt != self }
old_positions = []
# Can we move from the destination tile in any direction?
if map_passable?(@tx, @ty, 2)
map[@tx, @ty+1] = 1
old_positions.push([@tx, @ty+1])
end
if map_passable?(@tx, @ty, 8)
map[@tx, @ty-1] = 1
old_positions.push([@tx, @ty-1])
end
if map_passable?(@tx, @ty, 4)
map[@tx-1, @ty] = 1
old_positions.push([@tx-1, @ty])
end
if map_passable?(@tx, @ty, 6)
map[@tx+1, @ty] = 1
old_positions.push([@tx+1, @ty])
end
# If not, can we at least move up to the destination tile?
if old_positions.size == 0
if map_passable?(@tx-1,@ty,6)
map[@tx-1,@ty] = 1
old_positions.push([@tx-1,@ty])
end
if map_passable?(@tx+1,@ty,4)
map[@tx+1,@ty] = 1
old_positions.push([@tx+1,@ty])
end
if map_passable?(@tx,@ty-1,2)
map[@tx,@ty-1] = 1
old_positions.push([@tx,@ty-1])
end
if map_passable?(@tx,@ty+1,8)
map[@tx,@ty+1] = 1
old_positions.push([@tx,@ty+1])
end
end
end
# If there are any counters, can we move to the tile on the other side?
if map_passable?(@tx-2,@ty,6) && $game_map.counter?(@tx-1,@ty)
map[@tx-2,@ty] = 1
old_positions.push([@tx-2,@ty])
end
if map_passable?(@tx+2,@ty,4) && $game_map.counter?(@tx+1,@ty)
map[@tx+2,@ty] = 1
old_positions.push([@tx+2,@ty])
end
if map_passable?(@tx,@ty-2,2) && $game_map.counter?(@tx,@ty-1)
map[@tx,@ty-2] = 1
old_positions.push([@tx,@ty-2])
end
if map_passable?(@tx,@ty+2,2) && $game_map.counter?(@tx,@ty+1)
map[@tx,@ty+2] = 1
old_positions.push([@tx,@ty+2])
end
depth = 2
depth.upto(100) { |step|
break if old_positions[0].nil?
@step = step
loop do
break if old_positions[0].nil?
x, y = old_positions.shift
return [true, map, @step-1] if x == sx && y == sy
if map[x, y + 1] == 0 && passable?(x, y, 2)
map[x, y + 1] = @step
new_positions.push([x, y + 1])
end
if map[x - 1, y] == 0 && passable?(x, y, 4)
map[x - 1, y] = @step
new_positions.push([x - 1, y])
end
if map[x + 1, y] == 0 && passable?(x, y, 6)
map[x + 1, y] = @step
new_positions.push([x + 1, y])
end
if map[x, y - 1] == 0 && passable?(x, y, 8)
map[x, y - 1] = @step
new_positions.push([x, y - 1])
end
# Update graphics? (to reduce lag)
update_counter += 1
if update_counter > 50
Graphics.update
update_counter = 0
end
end
old_positions = new_positions
new_positions = []
}
return [false, nil, nil]
end
end
class Game_Character < Game_CharacterBase
#--------------------------------------------------------------------------
# * Force Move Route
#--------------------------------------------------------------------------
alias shaz_mouse_game_character_force_move_route force_move_route
def force_move_route(move_route)
clear_path
shaz_mouse_game_character_force_move_route(move_route)
end
end
#============================================================================
# SUPER SIMPLE MOUSE SCRIPT
# Player
#============================================================================
class Game_Player < Game_Character
#--------------------------------------------------------------------------
# * Trigger Map Event
# triggers : Trigger array
# normal : Is priority set to [Same as Characters] ?
#--------------------------------------------------------------------------
alias shaz_mouse_game_player_start_map_event start_map_event
def start_map_event(x, y, triggers, normal)
@started_events = []
shaz_mouse_game_player_start_map_event(x, y, triggers, normal)
end
#--------------------------------------------------------------------------
# * Start Event
#--------------------------------------------------------------------------
def start_event(event_id)
@started_events = [] if @started_events.nil?
@started_events.push(event_id)
end
#--------------------------------------------------------------------------
# * Processing of Movement via Input from Directional Buttons
#--------------------------------------------------------------------------
alias shaz_mouse_game_player_move_by_input move_by_input
def move_by_input
if Input.dir4 > 0
clear_path
shaz_mouse_game_player_move_by_input
else
# Move by mouse input
if !$game_message.busy? && !$game_message.visible && !@move_route_forcing &&
!@vehicle_getting_on && !@vehicle_getting_off &&
Mouse.trigger?(0) && !Mouse.grid.nil? && !$mouse.ignored?
mx, my = *Mouse.grid
# turn in direction
if (@x - mx).abs >= (@y - my).abs
set_direction(@x > mx ? 4 : 6)
else
set_direction(@y > my ? 8 : 2)
end
# find path
@event = $game_map.lowest_mouse_event_xy(mx, my)
if @event.nil?
find_path(mx, my)
elsif @event.mouse_autoactivate
@event.start
@started_events = []
clear_path
else
find_path(@event.x + @event.mouse_position[0],
@event.y + @event.mouse_position[1])
end
end
end
end
#--------------------------------------------------------------------------
# * Frame Update
#--------------------------------------------------------------------------
alias shaz_mouse_game_player_update update
def update
shaz_mouse_game_player_update
update_pathfinding if !@event.nil? && !moving?
end
#--------------------------------------------------------------------------
# * Check event after pathfinding
#--------------------------------------------------------------------------
def update_pathfinding
if @map.nil? || @map[@x, @y] <= 1
dir = @x < @event.x ? 6 : @x > @event.x ? 4 : @y < @event.y ? 2 : @y > @event.y ? 8 : 0
# Face event and trigger it (only if not triggered by start_map_event)
turn_toward_character(@event) if !@event.pos?(@x, @y)
if !@started_events.include?(@event.id) && !@map.nil? && !in_airship?
@event.start
@started_events = []
end
clear_path
end
end
#--------------------------------------------------------------------------
# * Clear Path
#--------------------------------------------------------------------------
def clear_path
@event = nil
super
end
end
#============================================================================
# SUPER SIMPLE MOUSE SCRIPT
# Interpreter
#============================================================================
class Game_Interpreter
#--------------------------------------------------------------------------
# * Event Setup
#--------------------------------------------------------------------------
alias shaz_mouse_game_interpreter_setup setup
def setup(list, event_id = 0, lock_player = false)
shaz_mouse_game_interpreter_setup(list, event_id)
@lock_player = lock_player
end
#--------------------------------------------------------------------------
# * Execute
#--------------------------------------------------------------------------
alias shaz_mouse_game_interpreter_run run
def run
$mouse.ignored = true if @lock_player
shaz_mouse_game_interpreter_run
$mouse.ignored = false if @lock_player
end
end
#============================================================================
# Этот код нужен для фикса ситуации, в которой при создании игрового меню
# на фоне оставался "призрак" курсора. Phileas.
#============================================================================
module SceneManager
def self.snapshot_for_background
flag = $mouse.enabled?
$mouse.enabled = false
@background_bitmap.dispose if @background_bitmap
@background_bitmap = Graphics.snap_to_bitmap
@background_bitmap.blur
$mouse.enabled = flag
end
end
#============================================================================
# SUPER SIMPLE MOUSE SCRIPT
# Windows
#============================================================================
class Window_Selectable < Window_Base
#--------------------------------------------------------------------------
# * Frame Update
#--------------------------------------------------------------------------
alias shaz_mouse_window_selectable_update update
def update
shaz_mouse_window_selectable_update
process_mouse_handling if Input.method == :mouse
end
#--------------------------------------------------------------------------
# * Mouse Movement Processing
#--------------------------------------------------------------------------
def process_mouse_handling
return unless $mouse.enabled? && cursor_movable?
# Add a delay to prevent too-fast scrolling
@delay = @delay ? @delay + 1 : 0
return if @delay % 3 > 0
mx, my = *Mouse.position
vx = self.viewport ? self.x - self.viewport.ox + self.viewport.rect.x : self.x
vy = self.viewport ? self.y - self.viewport.oy + self.viewport.rect.y : self.y
if mx.between?(vx, vx + self.width) &&
my.between?(vy, vy + self.height)
mx -= vx
mx -= padding
my -= vy
my -= padding
my += oy
for i in 0 ... item_max
rect = item_rect(i)
if mx.between?(rect.x, rect.x + rect.width) &&
my.between?(rect.y, rect.y + rect.height)
last_index = @index
select(i)
if @index != last_index
Sound.play_cursor
end
break
end
end
end
end
end
class Window_NameInput < Window_Selectable
#--------------------------------------------------------------------------
# * Mouse Movement Processing
#--------------------------------------------------------------------------
def process_mouse_handling
return unless $mouse.enabled?
# Add a delay to prevent too-fast scrolling
@delay = @delay ? @delay + 1 : 0
return if @delay % 3 > 0
mx, my = *Mouse.position
vx = (self.viewport ? self.x - self.viewport.ox + self.viewport.rect.x : self.x) + padding
vy = (self.viewport ? self.y - self.viewport.oy + self.viewport.rect.y : self.y) + padding
if mx.between?(vx, vx + self.width - padding * 2) &&
my.between?(vy, vy + self.height - padding * 2)
mx -= vx
my -= vy
x = (mx > 5*32+16 ? mx-16 : mx) / 32
y = my / line_height
last_index = @index
@index = y * 10 + x
Sound.play_cursor if @index != last_index
end
end
end
class Scene_File < Scene_MenuBase
#--------------------------------------------------------------------------
# * Update Cursor
#--------------------------------------------------------------------------
alias shaz_mouse_scene_file_update_cursor update_cursor
def update_cursor
shaz_mouse_scene_file_update_cursor
process_mouse_handling if Input.method == :mouse
end
#--------------------------------------------------------------------------
# * Mouse Movement Processing
#--------------------------------------------------------------------------
def process_mouse_handling
return unless $mouse.enabled?
# Add a delay to prevent too-fast scrolling
@delay = @delay ? @delay + 1 : 0
return if @delay % 3 > 0
mx, my = *Mouse.position
vx = @savefile_viewport.ox + mx
vy = @savefile_viewport.oy + my
last_index = @index
new_index = vy / savefile_height
if @index != new_index
if new_index > @index
cursor_down(false)
else
cursor_up(false)
end
Sound.play_cursor
@savefile_windows[last_index].selected = false
@savefile_windows[@index].selected = true
end
end
end
В скрипте я просто добавил в 130 строчку вот это:
Code:
return if $mouse == nil
Однако это позволяет лишь избежать исключения. Как же нам "воскресить" мышь при перезапуске игры? Очень просто, надо всего лишь вызвать конструктор заново.
Заходим в SceneManager (в скриптах в самом верху списка), находим self.run.
Там добавляем одну строчку:
Code:
def self.run
$mouse = Sprite_Mouse.new
DataManager.init
Audio.setup_midi if use_midi?
@scene = first_scene_class.new
@scene.main while @scene
end
На всякий случай, уточню, я добавил вот эту строчку:
Code:
$mouse = Sprite_Mouse.new
UPD! (04.12.2022)
По просьбе форумчанина, добавил ещё вот такой код в скрипт:
Code:
module SceneManager
def self.snapshot_for_background
flag = $mouse.enabled?
$mouse.enabled = false
@background_bitmap.dispose if @background_bitmap
@background_bitmap = Graphics.snap_to_bitmap
@background_bitmap.blur
$mouse.enabled = flag
end
end
Он убирает курсор со скриншота экрана, который ставится фоном игрового меню. Может возникнуть конфликт с другим скриптом, который тоже переопределяет этот метод.
Также добавил исправление от Dmy, которое решает проблему игр с кириллицей в названии.
Собственно, всё. Вот пустой проект, в котором демонстрируется работа исправленного скрипта:
проект
Если у вас что-то не получается, что-то не работает - пишите в этой теме, постараюсь помочь.
Последнее редактирование: 3 года 5 мес. назад пользователем Phileas.
Пожалуйста Войти или Регистрация, чтобы присоединиться к беседе.
5 года 2 мес. назад - 5 года 2 мес. назад #121737
от Местами человек
Местами человек ответил в теме [VX Ace] Фикс скрипта мыши
А какими припарками лечить вот такую ошибку? Ситуация одинаковая и в чистых проектах, и в тех, в которых есть другие скрипты. Преследует не только с этим скриптом, но и с аналогичным от Falcao. В чужих проектах всё нормально, но при перенесении в мои всё ломается.
Последнее редактирование: 5 года 2 мес. назад пользователем Местами человек.
Спасибо сказали: Dmy
Пожалуйста Войти или Регистрация, чтобы присоединиться к беседе.
5 года 2 мес. назад - 5 года 2 мес. назад #121739
от Dmy
Вариант 1.Не обещаю, что поможет, не проверял ещё. Проверил, работает.
Найдите вот этот отрезок кода:
и перед строчкой title.delete!("\0") добавьте такую строчку:
Чтобы получилось вот так:
Не могу обещать, что это сработает, но попробовать стоит. Я проверил: это работает. @Phileas, если вам не сложно, добавьте и это исправление в свою версию скрипта?
Для других скриптов надо сделать похожие исправления (но вместо title там будет что-то другое). Лучше создайте отдельную тему для этой ошибки (или по отдельной теме на каждый скрипт) и укажите в ней сам скрипт (ещё лучше, если получится приложить проект-пример), я отвечу.
Вариант 2. Дешёвый и сердитый. Просто переименуйте игру, чтобы в названии была одна латиница.
Эта ошибка возникает из-за того, что авторы скрипта не тестировали его на названиях проектов, где есть какие-то буквы, кроме английской латиницы.
Dmy ответил в теме [VX Ace] Фикс скрипта мыши
[strike]У меня сейчас мейкера нет под рукой, но попробуйте такое:[/strike]Местами человек пишет: А какими припарками лечить вот такую ошибку? Ситуация одинаковая и в чистых проектах, и в тех, в которых есть другие скрипты.
Вариант 1.
Найдите вот этот отрезок кода:
Code:
def self.hwnd
if @hwnd.nil?
title = "\0" * 256
Readini.call('Game', 'Title', '', title, 255, '.\\Game.ini')
title.delete!("\0")
@hwnd = Findwindow.call('RGSS Player', title)
ShowCursor.call(0)
end
return @hwnd
end
и перед строчкой title.delete!("\0") добавьте такую строчку:
Code:
title.force_encoding("ASCII-8bit")
Чтобы получилось вот так:
Code:
def self.hwnd
if @hwnd.nil?
title = "\0" * 256
Readini.call('Game', 'Title', '', title, 255, '.\\Game.ini')
title.force_encoding("ASCII-8bit")
title.delete!("\0")
@hwnd = Findwindow.call('RGSS Player', title)
ShowCursor.call(0)
end
return @hwnd
end
Для других скриптов надо сделать похожие исправления (но вместо title там будет что-то другое). Лучше создайте отдельную тему для этой ошибки (или по отдельной теме на каждый скрипт) и укажите в ней сам скрипт (ещё лучше, если получится приложить проект-пример), я отвечу.
Вариант 2. Дешёвый и сердитый. Просто переименуйте игру, чтобы в названии была одна латиница.
Эта ошибка возникает из-за того, что авторы скрипта не тестировали его на названиях проектов, где есть какие-то буквы, кроме английской латиницы.
Последнее редактирование: 5 года 2 мес. назад пользователем Dmy.
Пожалуйста Войти или Регистрация, чтобы присоединиться к беседе.
3 года 5 мес. назад - 3 года 5 мес. назад #128444
от Phileas
Phileas ответил в теме [VX Ace] Фикс скрипта мыши
Dmy, прошу прощения, я увидел новые сообщения в теме только сейчас) Мне почему-то не приходят письма о новых сообщениях.
Добавил ваше исправление.
Также, по просьбе одного форумчанина, убрал "призрак" курсора с фона игрового меню.
Обновил шапку темы и проект по ссылке.
Также рекомендую, по возможности, переходить на MV/MZ, где всё это работает из коробки. Ну а графику курсора можно поменять всякими плагинами, например, от DK. MZ всё ещё поддерживается разработчиками, а вот VX Ace со всеми своими проблемами безнадёжно в прошлом.
Добавил ваше исправление.
Также, по просьбе одного форумчанина, убрал "призрак" курсора с фона игрового меню.
Обновил шапку темы и проект по ссылке.
Также рекомендую, по возможности, переходить на MV/MZ, где всё это работает из коробки. Ну а графику курсора можно поменять всякими плагинами, например, от DK. MZ всё ещё поддерживается разработчиками, а вот VX Ace со всеми своими проблемами безнадёжно в прошлом.
Последнее редактирование: 3 года 5 мес. назад пользователем Phileas.
Пожалуйста Войти или Регистрация, чтобы присоединиться к беседе.
Время создания страницы: 0.122 секунд
