PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Suche RGSS Kenner - Passability Abfragen in Movementskript einbauen!



schmoggi
17.09.2009, 21:16
Hi,

Habe ne Zeit lang ein Skript bzw. einen Skripter gesucht, der mir ein Movementskript erstellen könnte. Genauer gesagt, ich möchte dass die Charaktere nicht 32 pixel weit bei einem schritt laufen sondern 16 pixel.

Ein Pixel Movement Skript ist in meinen Augen 1. sinnfrei und unnötig und 2. zu viel performance fressend.

Ich habe auch glücklicherweise das Skript bekommen. Derula (Techniker von Genocide) hat freundlicherweise sein Movementskript, mit welchem u.a. die bewegungen mit 16 pixel laufen frei zur verfügung gestellt.

Das ist das Skript


# Genocide_Movement 1.0 - 8 pixel precise movement for RPG Maker XP
#
# Author: derula
#
# This script is taken from the German RPGXP project "Genocide" and adjusted
# for standalone usage. Permission is granted by the author to freely use and
# edit it as long as the game "Genocide" and the code's original author remain
# credited in the code. Other means of crediting are voluntary, but appreciated.

module Genocide_Movement
# Hier: Konfiguration
# Um wie viele Viertelfelder soll sich ein Event standardmäßig bewegen?
# (um ein Event um weniger zu bewegen, muss ein Skript benutzt werden)
# Standard: 4, Minimum: 1, Maximum: 4
EVENT_DISTANCE = 4
# Um wie viele Viertelfelder soll sich der Spieler standardmäßig bewegen?
# (um den Spieler um weniger zu bewegen, muss ein Skript benutzt werden)
# Standard: 1, Minimum: 1, Maximum: 4
PLAYER_DISTANCE = 1
# Diagonallaufen aktivieren oder deaktivieren
# Standard: true, Deaktivieren: false
PLAYER_8_DIR = true
# Taste für Strafe: Während diese Taste gedrückt ist, dreht sich der Spieler
# nicht automatisch in die Richtung, in die er geht.
# Standard: Input::Shift, Deaktivieren: nil
STRAFE_KEY = Input::SHIFT
# Kosten für Diagonalgehen
# Standard: Math.sqrt(2), Deaktivieren: nil
DIAGONAL_COST = Math.sqrt(2)

class ::Numeric
# Mapfeldkoordinate berechnen aus Fließpunktkoordinate
def to_field
if (i = to_i) == self
i
else
(self-0.125).round
end
end
end

class :Game_Character
#--------------------------------------------------------------------------
# * Calculate new position
# x : x-coordinate
# y : y-coordinate
# d : direction (0,1,2,3,4,6,7,8,9)
# * 0 = no change
# s : steps (1..4)
#--------------------------------------------------------------------------
def get_new_coordinates(x, y, d, s = EVENT_DISTANCE)
# Get move distance
s *= 0.25
# Get new coordinates
if d != 0
dx = (d % 3 == 0 ? 1 : d % 3 == 1 ? -1 : 0)
dy = (d <= 3 ? 1 : d >= 7 ? -1 : 0)
new_x, new_y = x + dx * s, y + dy * s
else
dx = dy = 0
new_x, new_y = x, y
end
[new_x, new_y, dx, dy]
end
#--------------------------------------------------------------------------
# * Determine if Passable
# x : x-coordinate
# y : y-coordinate
# d : direction (0,1,2,3,4,6,7,8,9)
# * 0 = Determines if all directions are impassable (for jumping)
# s : steps (1..4)
# n : new coordinates as calculated by get_new_coordinates
# if not specified, they are calculated here
#--------------------------------------------------------------------------
def passable?(x, y, d, s = EVENT_DISTANCE, n = get_new_coordinates(x, y, d, s))
# Get new coordinates
new_x, new_y, dx, dy = *n
# If coordinates are outside of map: impassable
return false unless $game_map.valid?(new_x, new_y)
# If through is ON: passable
return true if @through
# Get move distance
s *= 0.25
# Standfeld berechnen
fx, fy = x.to_field, y.to_field
# Überprüfen, ob neues Feld betreten wird
cx = ((x - fx).abs < s and 0 < dx*(new_x - x))
cy = ((y - fy).abs < s and 0 < dy*(new_y - y))
if cx and cy
return false unless $game_map.passable?(fx, fy, d) and $game_map.passable?(fx + dx, fy + dy, 10 - d)
elsif cx
return false unless $game_map.passable?(fx, fy, 5 + dx) and $game_map.passable?(fx + dx, fy, 5 - dx)
# Wenn y-Koordinate *,5 ist, Feld daneben prüfen
unless y == fy or $game_map.passable?(fx, fy + (y <=> fy), 5 + dx) and
$game_map.passable?(fx + dx, fy + (y <=> fy), 5 - dx)
return false
end
elsif cy
return false unless $game_map.passable?(fx, fy, 5 - 3*dy) and $game_map.passable?(fx, fy + dy, 5 + 3*dy)
# Wenn x-Koordinate *,5 ist, Feld daneben prüfen
unless x == fx or $game_map.passable?(fx + (x <=> fx), fy, 5 - 3*dy) and
$game_map.passable?(fx + (x <=> fx), fy + dy, 5 + 3*dy)
return false
end
end
# Loop all events
for event in $game_map.events.values
next if event == self or event.through
# If through is OFF and (self is player => partner graphic as character)
# and event coordinates are consistent with move destination
if #not event.through and event.character_name != "" and
(self != $game_player or event.character_name != "") and
(event.x - new_x).abs < 1 and (event.y - new_y).abs < 1
# impassable
return false
end
end
# If self is not player, player through is OFF coordinates are consistent
# with move destination and your own graphic is the character
if self != $game_player and not $game_player.through and
@character_name != "" and ($game_player.x - new_x).abs < 1 and
($game_player.y - new_y).abs < 1
# impassable
return false
end
# passable
return true
end
#--------------------------------------------------------------------------
# * Move
# dir : direction (0,1,2,3,4,6,7,8,9)
# steps : number of steps to move (4 = 1 field)
# turn_enabled : a flag permits direction change on that spot
#--------------------------------------------------------------------------
def move(dir, steps = EVENT_DISTANCE, turn_enabled = true)
return if dir == 0
turned = false
# Turn to specified direction
if turn_enabled
turn(dir)
turned = true
end
# Calculate new coordinates
new_coords = get_new_coordinates(@x, @y, dir, steps)
# If passable and route free
if passable?(@x, @y, dir, steps, new_coords)
# Turn to specified direction
turn(dir) unless turned
# Update coordinates
@x, @y = new_coords
# Increase steps
increase_steps
# Slide if moving diagonally
elsif dir % 2 == 1 and
((m = dir % 6) == 1 and passable?(@x, @y, 4, steps, n = get_new_coordinates(@x, @y, 4, steps)) or
(m == 3 and passable?(@x, @y, 6, steps, n = get_new_coordinates(@x, @y, 6, steps))) or
(dir < 5 and passable?(@x, @y, 2, steps, n = get_new_coordinates(@x, @y, 2, steps))) or
(dir > 5 and passable?(@x, @y, 8, steps, n = get_new_coordinates(@x, @y, 8, steps))))
# Update coordinates
@x, @y = n#ew_coords
# Increase steps
increase_steps
# If impassable
else
# Determine if touch event is triggered
check_event_trigger_touch(new_coords[0], new_coords[1])
end
end
#--------------------------------------------------------------------------
# * Move Down
# turn_enabled : a flag permits direction change on that spot
# steps : number of steps to move (4 = 1 field)
#--------------------------------------------------------------------------
def move_down(turn_enabled = true, steps = EVENT_DISTANCE)
move(2, steps, turn_enabled)
end
#--------------------------------------------------------------------------
# * Move Left
# turn_enabled : a flag permits direction change on that spot
# steps : number of steps to move (4 = 1 field)
#--------------------------------------------------------------------------
def move_left(turn_enabled = true, steps = EVENT_DISTANCE)
move(4, steps, turn_enabled)
end
#--------------------------------------------------------------------------
# * Move Right
# turn_enabled : a flag permits direction change on that spot
# steps : number of steps to move (4 = 1 field)
#--------------------------------------------------------------------------
def move_right(turn_enabled = true, steps = EVENT_DISTANCE)
move(6, steps, turn_enabled)
end
#--------------------------------------------------------------------------
# * Move up
# turn_enabled : a flag permits direction change on that spot
# steps : number of steps to move (4 = 1 field)
#--------------------------------------------------------------------------
def move_up(turn_enabled = true, steps = EVENT_DISTANCE)
move(8, steps, turn_enabled)
end
#--------------------------------------------------------------------------
# * Move Lower Left
# steps : number of steps to move (4 = 1 field)
#--------------------------------------------------------------------------
def move_lower_left(steps = EVENT_DISTANCE)
move(1, steps)
end
#--------------------------------------------------------------------------
# * Move Lower Right
# steps : number of steps to move (4 = 1 field)
#--------------------------------------------------------------------------
def move_lower_right(steps = EVENT_DISTANCE)
move(3, steps)
end
#--------------------------------------------------------------------------
# * Move Upper Left
# steps : number of steps to move (4 = 1 field)
#--------------------------------------------------------------------------
def move_upper_left(steps = EVENT_DISTANCE)
move(7, steps)
end
#--------------------------------------------------------------------------
# * Move Upper Right
# steps : number of steps to move (4 = 1 field)
#--------------------------------------------------------------------------
def move_upper_right(steps = EVENT_DISTANCE)
move(9, steps)
end
#--------------------------------------------------------------------------
# * Turn
# d : direction (1,2,3,4,6,7,8,9)
#--------------------------------------------------------------------------
def turn(d)
# If no direction fix
unless @direction_fix
if d % 2 == 1
# If diagonal direction specified, replace it with good straight
# direction if the character is facing an opposite direction
if ((m = d % 6) == 1 and @direction == 6) or
(m == 3 and @direction == 4) or
(d < 5 and @direction == 8) or
(d > 5 and @direction == 2)
@direction = 10 - @direction
end
else
@direction = d
end
@stop_count = 0
end
end
#--------------------------------------------------------------------------
# * Update frame (move)
#--------------------------------------------------------------------------
def update_move
# Convert map coordinates from map move speed into move distance
distance = 2 ** @move_speed
# Apply cost for diagonal movement
if DIAGONAL_COST and @x * 128 != @real_x and @y * 128 != @real_y
distance = (distance / DIAGONAL_COST).round
end
# If logical coordinates are further down than real coordinates
if @y * 128 > @real_y
# Move down
@real_y = [@real_y + distance, @y * 128].min
end
# If logical coordinates are more to the left than real coordinates
if @x * 128 < @real_x
# Move left
@real_x = [@real_x - distance, @x * 128].max
end
# If logical coordinates are more to the right than real coordinates
if @x * 128 > @real_x
# Move right
@real_x = [@real_x + distance, @x * 128].min
end
# If logical coordinates are further up than real coordinates
if @y * 128 < @real_y
# Move up
@real_y = [@real_y - distance, @y * 128].max
end
# If move animation is ON
if @walk_anime
# Increase animation count by 1.5
@anime_count += 1.5
# If move animation is OFF, and stop animation is ON
elsif @step_anime
# Increase animation count by 1
@anime_count += 1
end
end
end

class :Game_Event
#--------------------------------------------------------------------------
# * Touch Event Starting Determinant
#--------------------------------------------------------------------------
def check_event_trigger_touch(x, y)
# If event is running
if $game_system.map_interpreter.running?
return
end
# If starting determinant other than jumping is front event and
# trigger is [touch from event] and consistent with player coordinates
if @trigger == 2 and not over_trigger? and not jumping? and
($game_player.x - @x).abs < 1 and ($game_player.y - @y).abs < 1
start
end
end
#--------------------------------------------------------------------------
# * Automatic Event Starting Determinant
#--------------------------------------------------------------------------
def check_event_trigger_auto
# If starting determinant other than jumping is same position event and
# trigger is [touch from event] and consistent with player coordinates
if @trigger == 2 and over_trigger? and not jumping? and
($game_player.x - @x).abs < 1 and ($game_player.y - @y).abs < 1
start
# If trigger is [auto run]
elsif @trigger == 3
start
end
end
end

# Schüsse/Treffer und Achtrichtungs- und Pixelmovement
class :Game_Player
def move(dir, steps = PLAYER_DISTANCE, turn_enabled = true)
super
end
#--------------------------------------------------------------------------
# * Frame Update
#--------------------------------------------------------------------------
def update
# Remember whether or not moving in local variables
last_moving = moving?
# Richtung fixieren
if STRAFE_KEY
if Input.press?(STRAFE_KEY)
if @pre_fix == nil
@pre_fix = @direction_fix
@direction_fix = true
end
elsif @pre_fix != nil
@direction_fix = @pre_fix
@pre_fix = nil
end
end
# If moving, event running, move route forcing, and message window
# display are all not occurring
if not (moving? or $game_system.map_interpreter.running? or
@move_route_forcing or $game_temp.message_window_showing)
# Move player in the direction the directional button is being pressed
move(PLAYER_8_DIR ? Input.dir8 : Input.dir4)
end
# Remember coordinates in local variables
last_real_x = @real_x
last_real_y = @real_y
super
# If character moves down and is positioned lower than the center
# of the screen
if @real_y > last_real_y and @real_y - $game_map.display_y > CENTER_Y
# Scroll map down
$game_map.scroll_down(@real_y - last_real_y)
end
# If character moves left and is positioned more let on-screen than
# center
if @real_x < last_real_x and @real_x - $game_map.display_x < CENTER_X
# Scroll map left
$game_map.scroll_left(last_real_x - @real_x)
end
# If character moves right and is positioned more right on-screen than
# center
if @real_x > last_real_x and @real_x - $game_map.display_x > CENTER_X
# Scroll map right
$game_map.scroll_right(@real_x - last_real_x)
end
# If character moves up and is positioned higher than the center
# of the screen
if @real_y < last_real_y and @real_y - $game_map.display_y < CENTER_Y
# Scroll map up
$game_map.scroll_up(last_real_y - @real_y)
end
# If not moving
unless moving?
# If player was moving last time
if last_moving
# Event determinant is via touch of same position event
result = check_event_trigger_here([1,2])
# If event which started does not exist
if result == false
# Disregard if debug mode is ON and ctrl key was pressed
unless $DEBUG and Input.press?(Input::CTRL)
# Encounter countdown
if @encounter_count > 0
@encounter_count -= 1
end
end
end
end
# If C button was pressed
if Input.trigger?(Input::C)
# Same position and front event determinant
check_event_trigger_here([0])
check_event_trigger_there([0,1,2])
end
end
end
#--------------------------------------------------------------------------
# * Passable Determinants
# x : x-coordinate
# y : y-coordinate
# d : direction (0,2,4,6,8)
# * 0 = Determines if all directions are impassable (for jumping)
# s : steps (1..4)
#--------------------------------------------------------------------------
def passable?(x, y, d, s = 4, n = get_new_coordinates(x, y, d, s))
# If coordinates are outside of map: impassable
return false unless $game_map.valid?(n[0], n[1])
# If debug mode is ON and ctrl key was pressed: passable
return true if $DEBUG and Input.press?(Input::CTRL)
super
end
#--------------------------------------------------------------------------
# * Same Position Starting Determinant
#--------------------------------------------------------------------------
def check_event_trigger_here(triggers)
# If no event is running
unless $game_system.map_interpreter.running?
# All event loops
for event in $game_map.events.values
# If triggers are consistent, starting determinant is same position event
# (other than jumping) and event coordinates are consistent
if event.over_trigger? and triggers.include?(event.trigger) and
(not event.jumping?) and (event.x - @x).abs < 1 and (event.y - @y).abs < 1
event.start
return true
end
end
end
return false
end
#--------------------------------------------------------------------------
# * Front Envent Starting Determinant
#--------------------------------------------------------------------------
def check_event_trigger_there(triggers)
# If no event is running
unless $game_system.map_interpreter.running?
# Calculate front event coordinates
new_x = @x + (@direction == 6 ? 1 : @direction == 4 ? -1 : 0)
new_y = @y + (@direction == 2 ? 1 : @direction == 8 ? -1 : 0)
# All event loops
for event in $game_map.events.values
# If triggers are consistent, starting determinant is front event
# (other than jumping) and event coordinates are consistent
if not event.over_trigger? and triggers.include?(event.trigger) and
not event.jumping? and (event.x - new_x).abs < 1 and (event.y - new_y).abs < 1
event.start
return true
end
end
# If front tile is a counter
if $game_map.counter?(new_x, new_y)
# Calculate 1 tile inside coordinates
new_x += (@direction == 6 ? 1 : @direction == 4 ? -1 : 0)
new_y += (@direction == 2 ? 1 : @direction == 8 ? -1 : 0)
# All event loops
for event in $game_map.events.values
# If triggers are consistent, starting determinant is front event
# (other than jumping) and event coordinates are consistent
if not event.over_trigger? and triggers.include?(event.trigger) and
not event.jumping? and (event.x - new_x).abs < 1 and (event.y - new_y).abs < 1
event.start
return true
end
end
end
end
return false
end
#--------------------------------------------------------------------------
# * Touch Event Starting Determinant
#--------------------------------------------------------------------------
def check_event_trigger_touch(x, y)
# If no event is running
unless $game_system.map_interpreter.running?
# All event loops
for event in $game_map.events.values
# If triggers are consistent, starting determinant is front event
# (other than jumping) and event coordinates are consistent
if not event.over_trigger? and not event.jumping? and
[1,2].include?(event.trigger) and (event.x - x).abs < 1 and (event.y - y).abs < 1
event.start
return true
end
end
end
return false
end
end
end

Funktioniert auch wunderbar... allerdings ist ein Problem vorhanden. Da man in meinem Fall ja jetzt 16 pixel mit einem schritt macht, kann man quasi auch zwischen 2 events stehen (von der position her). Das sähe so aus:
http://imagesload.net/img/Problem.jpg

Wie man vllt. schon ahnen kann, geht es mir genau um so einen Problemfall. Denn momentan ist es so, dass der Held im aufgeführten Beispiel nach unten gehen könnte. Das ist und soll aber nicht möglich sein. Denn, wenn der Held jetzt nach unten geht, steht er zwischen 2 Feldern bei denen keine passability nach links bzw. nach rechts vorhanden ist.

Lösung:
http://imagesload.net/img/Abfrage.png

Oben, wenn der Held nach rechts oder links läuft und eben zwischen 2 Feldern steht.

Unten, wenn der Held nach oben oder unten läuft und zwischen 2 Feldern ist.

Beim Roten Punkt sollte keine Bewegung möglich sein, beim Grünen Punkt schon. Das heißt, eine zusätzliche Abfrage bei jeder Richtung, Links und Rechts die selbe Abfrage sowie bei Oben und Unten.

Links und Rechts: Hat oberes Feld eine Begehbarkeit nach unten und unteres Feld eine Begehbarkeit nach oben?

Oben und Unten: Hat linkes Feld eine Begehbarkeit nach rechts und rechtes Feld eine Begehbarkeit nach links?

Ich habe jetzt nur die relevanten Begehbarkeitspfeile reingezeichnet, da es ja sowieso nicht möglich ist, wenn man zwischen zwei Feldern ist, sich z.B. von links nach rechts zu bewegen, wenn eins der 2 Felder keine Begehbarkeit nach links besitzt. Das heißt also auch, dass eben nur die eingezeichneten Pfeile abgefragt werden müssen.

Es wäre wirklich nett, wenn ein fähiger Skripter diese Abfragen in das Skript noch einbauen könnte.

greetz

Shining Advances
17.09.2009, 22:27
muh

module Genocide_Movement
class :Game_Character
def passable?(x, y, d, s = EVENT_DISTANCE, n = get_new_coordinates(x, y, d, s))
# Get new coordinates
new_x, new_y, dx, dy = *n
# If coordinates are outside of map: impassable
return false unless $game_map.valid?(new_x, new_y)
# If through is ON: passable
return true if @through
# Get move distance
s *= 0.25
# Standfeld berechnen
fx, fy = x.to_field, y.to_field
# Überprüfen, ob neues Feld betreten wird
cx = ((x - fx).abs < s and 0 < dx*(new_x - x))
cy = ((y - fy).abs < s and 0 < dy*(new_y - y))
#if cx and cy
# return false unless $game_map.passable?(fx, fy, d) and $game_map.passable?(fx + dx, fy + dy, 10 - d)
if cx
return false unless $game_map.passable?(fx, fy, 5 + dx) and $game_map.passable?(fx + dx, fy, 5 - dx)
# Wenn y-Koordinate *,5 ist, Feld daneben prüfen
if y != fy
unless $game_map.passable?(fx, fy + (y <=> fy), 5 + dx) and
$game_map.passable?(fx + dx, fy + (y <=> fy), 5 - dx)
return false
end
unless $game_map.passable?(fx + dx, fy + (y <=> fy), 8) and
$game_map.passable?(fx + dx, fy + (y <=> fy), fy + dy, 2)
return false
end
end
end
if cy
return false unless $game_map.passable?(fx, fy, 5 - 3*dy) and $game_map.passable?(fx, fy + dy, 5 + 3*dy)
# Wenn x-Koordinate *,5 ist, Feld daneben prüfen
if x != fx
unless $game_map.passable?(fx + (x <=> fx), fy, 5 - 3*dy) and
$game_map.passable?(fx + (x <=> fx), fy + dy, 5 + 3*dy)
return false
end
unless $game_map.passable?(fx + (x <=> fx), fy + dy, 4) and
$game_map.passable?(fx + (x <=> fx), fy + dy, 6)
return false
end
end
end
# Loop all events
for event in $game_map.events.values
next if event == self or event.through
# If through is OFF and (self is player => partner graphic as character)
# and event coordinates are consistent with move destination
if #not event.through and event.character_name != "" and
(self != $game_player or event.character_name != "") and
(event.x - new_x).abs < 1 and (event.y - new_y).abs < 1
# impassable
return false
end
end
# If self is not player, player through is OFF coordinates are consistent
# with move destination and your own graphic is the character
if self != $game_player and not $game_player.through and
@character_name != "" and ($game_player.x - new_x).abs < 1 and
($game_player.y - new_y).abs < 1
# impassable
return false
end
# passable
return true
end
end
end

diese boolsche algebra ist die hölle ._.
wie immer ein ostereierscript...viel spaß beim eier bugs finden. habs nicht ausreichend getestet.^^

falls du was finden solltest bescheid geben und mir auf die finger haun.

schmoggi
17.09.2009, 23:06
Man, du hättest aber echt mal sagen können, wie mans einbaut lol xD. Ich hab erst probiert und geguckt, ob mans vllt. ins skript selber einfügt und was überschreibt etc. Aber habs jetzt als neues Skript natürlich reingemacht.

Und... FUNKTIONIERT! Geil ^^... Vielen Dank! Ich denke mal, es werden keine Bugs auftreten (hoffentlich). Wenn doch, meld ich mich entsprechend ;).

greetz

Scha
22.10.2009, 02:11
Hab beide Skripte kurz angetestet, und durch die 8-Dir Steuerung tauchen immer noch Fehler auf.
Bei PLAYER_DISTANCE = 1 und 2, schiebt sich der Charakter diagonal so ungeschickt in die Kanten, das er dann dort drinnen stecken bleibt (und höchstens mit Maker-Strg rauskommt).

http://img96.imageshack.us/img96/1530/genocidepixelmovment.jpg

Bei DISTANCE 3, bleibt er nur Teils hängen, geht aber auch diagonal mitten durch den Zaun (und 4 ist ja Standart).

Wenn man die 8-Dir Steuerung jedoch auf False setzt, läuft es auf den ersten Blick einwandfrei (ausser das man recht häufig gegen die Kanten läuft). ^^