Hier dreht sich alles um die RPG-Maker-Reihe von ASCII/Enterbrain. Der RPG-Maker ist ein Tool, mit dem du dir dein eigenes kleines Rollenspiel erstellen kannst. Du findest hier alles, was du dazu brauchst. Aber natürlich umfasst die Community noch mehr!
Heute veröffentliche ich die neuste Version meines verbessterten Kollisions-Erkennungsskripts. Es ist minimal schneller, als der Vorgänger. (38 statt 8 Frames)
Das Script erneuret alle Funktionen, die Event-Positionen prüfen oder ändern.
Events, die "ghost" im Namen tragen werden als Ghost-Objekt gehandelt.
Objekt-typ "Ghost". Ghost sind alle Events, die "ghost" im Namen haben. (Auch der Spieler, hat dort aber keinen Einfluss) Eine Interaktion mit Ghost-Events ist nicht möglich. Umgekert schon. So kann z.B. eine Maus Wände und Events erkennen ohne, dass sie für solche ein Hindernis darstellt. Event-Tiles oder Vögel, welche keinerlei Interaktionen benötigen erleichtern somit anderen Events die Kollisionsabfragen.
Code:
#============================================================================== # ** Collision 1.3 #------------------------------------------------------------------------------ # Scripted by TheWhiteShadow #============================================================================== GHOST_FLAG = "ghost" # Kannste ändern, wenn ghost nicht gefällt oder so.^^
class Game_Map #-------------------------------------------------------------------------- # * Setup # map_id : map ID #-------------------------------------------------------------------------- def setup(map_id) # Put map ID in @map_id memory @map_id = map_id # Load map from file and set @map @map = load_data(sprintf("Data/Map%03d.rxdata", @map_id)) # erstelle eine Wegtabelle @paths = Table.new(width, height * 2) # - Ungerade Y-Werte enthalten horizontale Wege # - Gerade Y-Werte enthalten vertikale Wege # erstelle eine Positionstabelle @positions = Table.new(width, height) @overlay = {} # set tile set information in opening instance variables tileset = $data_tilesets[@map.tileset_id] @tileset_name = tileset.tileset_name @autotile_names = tileset.autotile_names @panorama_name = tileset.panorama_name @panorama_hue = tileset.panorama_hue @fog_name = tileset.fog_name @fog_hue = tileset.fog_hue @fog_opacity = tileset.fog_opacity @fog_blend_type = tileset.fog_blend_type @fog_zoom = tileset.fog_zoom @fog_sx = tileset.fog_sx @fog_sy = tileset.fog_sy @battleback_name = tileset.battleback_name @passages = tileset.passages @priorities = tileset.priorities @terrain_tags = tileset.terrain_tags # Initialize displayed coordinates @display_x = 0 @display_y = 0 # Clear refresh request flag @need_refresh = false # Set map event data @events = {} for i in @map.events.keys @events[i] = Game_Event.new(@map_id, @map.events[i]) end # Set common event data @common_events = {} for i in 1...$data_common_events.size @common_events[i] = Game_CommonEvent.new(i) end # Initialize all fog information @fog_ox = 0 @fog_oy = 0 @fog_tone = Tone.new(0, 0, 0, 0) @fog_tone_target = Tone.new(0, 0, 0, 0) @fog_tone_duration = 0 @fog_opacity_duration = 0 @fog_opacity_target = 0 # Initialize scroll information @scroll_direction = 2 @scroll_rest = 0 @scroll_speed = 4 # fülle die Wegtabelle for y in 0..(height * 2 - 2) for x in 0..(width - 1) @paths[x, y] = set_path(x, y) # 0 = Unpassierbar / >0 = Passierbar end end end #-------------------------------------------------------------------------- def set_path(x, y) d = y % 2 == 0 ? 6 : 2 y /= 2 new_x = x + (d == 6 ? 1 : 0) new_y = y + (d == 2 ? 1 : 0) bit = (1 << (d / 2 - 1)) & 0x0f # Loop searches in order from top of layer for i in [2, 1, 0] tile_id = data[x, y, i] if tile_id == nil return 0 else return 0 if not valid?(new_x, new_y) or @passages[tile_id] & bit == bit return check_second(new_x, new_y, 10-d) if @priorities[tile_id] == 0 end end return check_second(new_x, new_y, 10-d) end #-------------------------------------------------------------------------- # Prüfe den Rückweg vom Folgetile def check_second(x, y, d) new_x = x + (d == 4 ? -1 : 0) new_y = y + (d == 8 ? -1 : 0) bit = (1 << (d / 2 - 1)) & 0x0f # Loop searches in order from top of layer for i in [2, 1, 0] tile_id = data[x, y, i] if tile_id == nil return 0 else return 0 if @passages[tile_id] & bit == bit return 1 if @priorities[tile_id] == 0 end end return 1 end #-------------------------------------------------------------------------- # * gibt ein unpasierbares Event auf x/y zurück #-------------------------------------------------------------------------- def collision_on(x, y, self_event) return nil unless valid?(x, y) case @positions[x, y] <=> 0 when 1 # einfach belegt return $game_player if @positions[x, y] == 1 ev = @events[@positions[x, y] - 1] return ev unless ev.through or ev == self_event when -1 # mehrfach belegt @overlay[y * width + x].each do |i| return $game_player if i == 1 ev = @events[i-1] return ev unless ev.through or ev == self_event end end return nil end #-------------------------------------------------------------------------- # * fügt der Positionsliste ein Event hinzu #-------------------------------------------------------------------------- def add_position(x, y, id) x %= $game_map.width y %= $game_map.height id += 1 # damit auch der Spieler erkannt wird if @positions[x, y] == 0 # nicht belegt @positions[x, y] = id elsif @positions[x, y] > 0 # einfach belegt @overlay[y * width + x] = [@positions[x, y], id] @positions[x, y] = -1 else # mehrfach belegt @overlay[y * width + x].push(id) end end #-------------------------------------------------------------------------- # * entfernt ein Event aus der Positionsliste #-------------------------------------------------------------------------- def remove_position(x, y, id) id += 1 if @positions[x, y] == id # einfach belegt @positions[x, y] = 0 elsif @positions[x, y] == -1 # mehrfach belegt @overlay[y * width + x].delete(id) if @overlay[y * width + x].size == 1 @positions[x, y] = @overlay[y * width + x][0] @overlay.delete(y * width + x) end end end #-------------------------------------------------------------------------- # * Get all Events on position x/y #-------------------------------------------------------------------------- def events_on(x, y) events = [] if valid?(x, y) or @positions[x, y] == -2 case @positions[x, y] <=> 0 when 1 # einfach belegt events.push(@events[@positions[x, y] - 1]) if @positions[x, y] != 1 when -1 # mehrfach belegt @overlay[y * width + x].each do |i| next if i == 1 events.push(@events[i - 1]) end end end return events end #-------------------------------------------------------------------------- # * Determine if Passable # x : x-coordinate # y : y-coordinate # d : direction (0,2,4,6,8,10) # * 0,10 = determine if all directions are impassable # self_event : Self (If event is determined passable) # - Änderung: Eventdurchlauf auf relevantes Feld beschränkt #-------------------------------------------------------------------------- def passable?(x, y, d, self_event = nil) # If coordinates given are outside of the map unless valid?(x, y) # impassable return false end # Change direction (0,2,4,6,8,10) to obstacle bit (0,1,2,4,8,0) bit = (1 << (d / 2 - 1)) & 0x0f event = collision_on(x, y, self_event) if event != nil # If tiles other than self are consistent with coordinates if event.tile_id >= 0 and event != self_event # If obstacle bit is set if @passages[event.tile_id] & bit != 0 # impassable return false # If obstacle bit is set in all directions elsif @passages[event.tile_id] & 0x0f == 0x0f # impassable return false # If priorities other than that are 0 elsif @priorities[event.tile_id] == 0 # passable return true end end end # Loop searches in order from top of layer for i in [2, 1, 0] # Get tile ID tile_id = data[x, y, i] # Tile ID acquistion failure if tile_id == nil # impassable return false # If obstacle bit is set elsif @passages[tile_id] & bit != 0 # impassable return false # If obstacle bit is set in all directions elsif @passages[tile_id] & 0x0f == 0x0f # impassable return false # If priorities other than that are 0 elsif @priorities[tile_id] == 0 # passable return true end end # passable return true end #-------------------------------------------------------------------------- def tile_passable?(tile_id, d) # If tiles other than self are consistent with coordinates if tile_id > 0 # Change direction (0,2,4,6,8,10) to obstacle bit (0,1,2,4,8,0) bit = (1 << (d / 2 - 1)) & 0x0f # If obstacle bit is set if @passages[tile_id] & bit != 0 # impassable return false # If obstacle bit is set in all directions elsif @passages[tile_id] & 0x0f == 0x0f # impassable return false # If priorities other than that are 0 elsif @priorities[tile_id] == 0 # passable return true end end return true end #-------------------------------------------------------------------------- def path_exist?(x, y, d) return false unless @paths[x, y] y *= 2 if d == 2 or d == 8 y -= 1 y += 2 if d == 2 else x -= 1 if d == 4 end return @paths[x, y] > 0 end end
class Game_Character attr_reader :ghost # verhindert das Ein/Austragen in der Kollisionstabelle def ghost=(value) @ghost = value $game_map.remove_position(@x, @y, @id) end #-------------------------------------------------------------------------- # * change x-position #-------------------------------------------------------------------------- def new_x(x) $game_map.remove_position(@x, @y, @id) unless @ghost @x = x $game_map.add_position(@x, @y, @id) unless @ghost end #-------------------------------------------------------------------------- # * change y-position #-------------------------------------------------------------------------- def new_y(y) $game_map.remove_position(@x, @y, @id) unless @ghost @y = y $game_map.add_position(@x, @y, @id) unless @ghost end #-------------------------------------------------------------------------- # * change x/y-position #-------------------------------------------------------------------------- def new_pos(x, y) $game_map.remove_position(@x, @y, @id) unless @ghost @x = x @y = y $game_map.add_position(@x, @y, @id) unless @ghost end #-------------------------------------------------------------------------- # * Move to Designated Position # x : x-coordinate # y : y-coordinate # - Änderung: Positionsänderung über Funktionsaufruf #-------------------------------------------------------------------------- def moveto(x, y) new_pos(x % $game_map.width, y % $game_map.height) @real_x = @x * 128 @real_y = @y * 128 @prelock_direction = 0 end #-------------------------------------------------------------------------- # * Determine if Passable # x : x-coordinate # y : y-coordinate # d : direction (0,2,4,6,8) # * 0 = Determines if all directions are impassable (for jumping) # - Änderung: Diverses #-------------------------------------------------------------------------- def passable?(x, y, d) # Get new coordinates new_x = x + (d == 6 ? 1 : d == 4 ? -1 : 0) new_y = y + (d == 2 ? 1 : d == 8 ? -1 : 0) # existiert das neue Feld nicht? unless $game_map.valid?(new_x, new_y) # impassable return false end # If through is ON if @through # passable return true end full_test = false # Event-Tile hier vorhanden? event = $game_map.collision_on(x, y, self) if event != nil full_test = true end # Event-Tile dort vorhanden? event = $game_map.collision_on(new_x, new_y, self) if event != nil if event.character_name != "" or self != $game_player # impassable return false elsif event.tile_id >= 0 full_test = true end end #print("$game_map.path_exist?") # existiert der Weg zum Zielfeld nicht? if full_test return false unless $game_map.passable?(x, y, d, self) return false unless $game_map.passable?(new_x, new_y, 10 - d, self) else return false unless $game_map.path_exist?(x, y, d) end # passable return true end #-------------------------------------------------------------------------- # * Move Down # turn_enabled : a flag permits direction change on that spot # - Änderung: Positionsänderung über Funktionsaufruf #-------------------------------------------------------------------------- def move_down(turn_enabled = true) # Turn down if turn_enabled turn_down end # If passable if passable?(@x, @y, 2) # Turn down turn_down # Update coordinates new_y(@y + 1) # Increase steps increase_steps # If impassable else # Determine if touch event is triggered check_event_trigger_touch(@x, @y+1) end end #-------------------------------------------------------------------------- # * Move Left # turn_enabled : a flag permits direction change on that spot # - Änderung: Positionsänderung über Funktionsaufruf #-------------------------------------------------------------------------- def move_left(turn_enabled = true) # Turn left if turn_enabled turn_left end # If passable if passable?(@x, @y, 4) # Turn left turn_left # Update coordinates new_x(@x - 1) # Increase steps increase_steps # If impassable else # Determine if touch event is triggered check_event_trigger_touch(@x-1, @y) end end #-------------------------------------------------------------------------- # * Move Right # turn_enabled : a flag permits direction change on that spot # - Änderung: Positionsänderung über Funktionsaufruf #-------------------------------------------------------------------------- def move_right(turn_enabled = true) # Turn right if turn_enabled turn_right end # If passable if passable?(@x, @y, 6) # Turn right turn_right # Update coordinates new_x(@x + 1) # Increase steps increase_steps # If impassable else # Determine if touch event is triggered check_event_trigger_touch(@x+1, @y) end end #-------------------------------------------------------------------------- # * Move up # turn_enabled : a flag permits direction change on that spot # - Änderung: Positionsänderung über Funktionsaufruf #-------------------------------------------------------------------------- def move_up(turn_enabled = true) # Turn up if turn_enabled turn_up end # If passable if passable?(@x, @y, 8) # Turn up turn_up # Update coordinates new_y(@y - 1) # Increase steps increase_steps # If impassable else # Determine if touch event is triggered check_event_trigger_touch(@x, @y-1) end end #-------------------------------------------------------------------------- # * Move Lower Left # - Änderung: Positionsänderung über Funktionsaufruf #-------------------------------------------------------------------------- def move_lower_left # If no direction fix unless @direction_fix # Face down is facing right or up @direction = (@direction == 6 ? 4 : @direction == 8 ? 2 : @direction) end # When a down to left or a left to down course is passable if (passable?(@x, @y, 2) and passable?(@x, @y + 1, 4)) or (passable?(@x, @y, 4) and passable?(@x - 1, @y, 2)) # Update coordinates new_pos(@x - 1, @y + 1) # Increase steps increase_steps end end #-------------------------------------------------------------------------- # * Move Lower Right # - Änderung: Positionsänderung über Funktionsaufruf #-------------------------------------------------------------------------- def move_lower_right # If no direction fix unless @direction_fix # Face right if facing left, and face down if facing up @direction = (@direction == 4 ? 6 : @direction == 8 ? 2 : @direction) end # When a down to right or a right to down course is passable if (passable?(@x, @y, 2) and passable?(@x, @y + 1, 6)) or (passable?(@x, @y, 6) and passable?(@x + 1, @y, 2)) # Update coordinates new_pos(@x + 1, @y + 1) # Increase steps increase_steps end end #-------------------------------------------------------------------------- # * Move Upper Left # - Änderung: Positionsänderung über Funktionsaufruf #-------------------------------------------------------------------------- def move_upper_left # If no direction fix unless @direction_fix # Face left if facing right, and face up if facing down @direction = (@direction == 6 ? 4 : @direction == 2 ? 8 : @direction) end # When an up to left or a left to up course is passable if (passable?(@x, @y, 8) and passable?(@x, @y - 1, 4)) or (passable?(@x, @y, 4) and passable?(@x - 1, @y, 8)) # Update coordinates new_pos(@x - 1, @y - 1) # Increase steps increase_steps end end #-------------------------------------------------------------------------- # * Move Upper Right # - Änderung: Positionsänderung über Funktionsaufruf #-------------------------------------------------------------------------- def move_upper_right # If no direction fix unless @direction_fix # Face right if facing left, and face up if facing down @direction = (@direction == 4 ? 6 : @direction == 2 ? 8 : @direction) end # When an up to right or a right to up course is passable if (passable?(@x, @y, 8) and passable?(@x, @y - 1, 6)) or (passable?(@x, @y, 6) and passable?(@x + 1, @y, 8)) # Update coordinates new_pos(@x + 1, @y - 1) # Increase steps increase_steps end end #-------------------------------------------------------------------------- # * Jump # x_plus : x-coordinate plus value # y_plus : y-coordinate plus value # - Änderung: Positionsänderung über Funktionsaufruf #-------------------------------------------------------------------------- def jump(x_plus, y_plus) # If plus value is not (0,0) if x_plus != 0 or y_plus != 0 # If horizontal distnace is longer if x_plus.abs > y_plus.abs # Change direction to left or right x_plus < 0 ? turn_left : turn_right # If vertical distance is longer, or equal else # Change direction to up or down y_plus < 0 ? turn_up : turn_down end end # Calculate new coordinates new_x = @x + x_plus new_y = @y + y_plus # If plus value is (0,0) or jump destination is passable if (x_plus == 0 and y_plus == 0) or passable?(new_x, new_y, 0) # Straighten position straighten # Update coordinates new_pos(new_x, new_y) # Calculate distance distance = Math.sqrt(x_plus * x_plus + y_plus * y_plus).round # Set jump count @jump_peak = 10 + distance - @move_speed @jump_count = @jump_peak * 2 # Clear stop count @stop_count = 0 end end end
class Game_Event #-------------------------------------------------------------------------- # * Object Initialization # map_id : map ID # event : event (RPG::Event) # - Änderung: Ghost-Flag hinzugefügt #-------------------------------------------------------------------------- def initialize(map_id, event) super() @map_id = map_id @event = event @id = @event.id @erased = false @starting = false @through = true @ghost = @event.name[GHOST_FLAG] # Move to starting position moveto(@event.x, @event.y) refresh end end
class Game_Player #-------------------------------------------------------------------------- # * Same Position Starting Determinant # - Änderung: Eventprüfung auf relevantes Feld beschränkt #-------------------------------------------------------------------------- def check_event_trigger_here(triggers) result = false # If event is running if $game_system.map_interpreter.running? return result end # All event loops for event in $game_map.events_on(@x, @y) # If event coordinates and triggers are consistent if triggers.include?(event.trigger) # If starting determinant is same position event (other than jumping) if not event.jumping? and event.over_trigger? event.start result = true end end end return result end #-------------------------------------------------------------------------- # * Front Envent Starting Determinant # - Änderung: Eventprüfung auf relevantes Feld beschränkt #-------------------------------------------------------------------------- def check_event_trigger_there(triggers) result = false # If event is running if $game_system.map_interpreter.running? return result end # 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_on(new_x, new_y) # If event coordinates and triggers are consistent if triggers.include?(event.trigger) # If starting determinant is front event (other than jumping) if not event.jumping? and not event.over_trigger? event.start result = true end end end # If fitting event is not found if result == false # 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_on(new_x, new_y) # If event coordinates and triggers are consistent if triggers.include?(event.trigger) # If starting determinant is front event (other than jumping) if not event.jumping? and not event.over_trigger? event.start result = true end end end end end return result end #-------------------------------------------------------------------------- # * Touch Event Starting Determinant # - Änderung: Eventprüfung auf relevantes Feld beschränkt #-------------------------------------------------------------------------- def check_event_trigger_touch(x, y) result = false # If event is running if $game_system.map_interpreter.running? return result end # All event loops for event in $game_map.events_on(@x, @y) # If event coordinates and triggers are consistent if [1,2].include?(event.trigger) # If starting determinant is front event (other than jumping) if not event.jumping? and not event.over_trigger? event.start result = true end end end return result end end
Benutzung: Code ins Script oberhalb der Main-Funktion einfügen.
Du darfst keine neuen Themen in diesem Forum erstellen. Du darfst keine Antworten zu Themen in diesem Forum erstellen. Du darfst deine Beiträge in diesem Forum nicht ändern. Du darfst deine Beiträge in diesem Forum nicht löschen. Du darfst keine Dateianhänge in diesem Forum erstellen.