Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #==============================================================================
- # ** Quasi Sight v0.8
- # Requires Module Quasi and Quasi Movement
- # http://quasixi.wordpress.com/2014/09/23/quasi/
- # http://quasixi.wordpress.com/2014/09/23/quasi-movement/
- # (Make sure they're up to date)
- #==============================================================================
- # A true line of sight for events. Events can not see through impassible
- # tiles (Regions that are set inside Quasi Movement script) unless the region
- # is set to be able to see over in the module below. Events also can not see
- # through other events unless they are marked Through or have the comment
- # <seethrough>
- #==============================================================================
- # Change Log
- #------------------------------------------------------------------------------
- # v0.8 - Released
- #------------------------------------------------------------------------------
- # To do / Upcoming
- #------------------------------------------------------------------------------
- # - Make a method for the event sight checking, so it doesn't require as much
- # eventing (Even though it is not much)
- # - Simplify algorithm even more, was already shortend 120 lines.
- # - Write a guide?
- #==============================================================================
- module Quasi
- module Sight
- #------------------------------------------------------------------------------
- # Instructions:
- # Step 1. Set SEERGIONS to a list of impassible regions you want to be able to
- # see over. Example region 44 is the same as region 54 inside
- # Quasi Movement, but you can see over 44 which can be used for
- # holes/water tiles.
- #------------------------------------------------------------------------------
- SEEREGIONS = [
- 44,
- ]
- #------------------------------------------------------------------------------
- # Step 2. Methods
- # To run a check if someone is in sight you do:
- # obj.sight(range, who, shape)
- # *obj is usually the event but it can be the game player
- # - for event it will be $game_map.events[ID NUMBER HERE]
- # *range is the number of tiles (32x32 tiles) the obj can see
- # - default is 6
- # *who is who are you checking if the obj can see?
- # - most cases you will want to check if the event can see the player
- # so who would be $game_player
- # - default is $game_player
- # *shape (don't use, it's incomplete, only 1 shape exists)
- # Examples:
- # $game_map.events[1].sight(6, $game_player)
- # Will return true if event 1 can see the game player or false if it
- # can not.
- # $game_map.events[1].sight
- # Exactly the same as previous example since 6 is default range
- # and $game_player is default who.
- #
- # Be aware you don't want to constantly keep calling them, like in an parallel
- # event, specially if the events are moving, or it can cause lag. The method
- # benchmarked 0.003 to 0.005 in testing for 1 event, with 10 it was around
- # 0.07 to 1.00, but that was from previous algrithm, changed it up so it should
- # be a lot faster.
- # So I added a new method which you can wrap it around the previous
- # obj.update_sight?
- # it will return true if that obj's x, y or direction has changed
- # since the last call, if not it returns false.
- # But this probably only makes it so calls every couple of frames instead of
- # every frame.
- #------------------------------------------------------------------------------
- end
- end
- #==============================================================================#
- # By Quasi (http://quasixi.wordpress.com/)
- # - 10/3/14
- #==============================================================================#
- # ** Stop! Do not edit anything below, unless you know what you **
- # ** are doing! **
- #==============================================================================#
- $imported = {} if $imported.nil?
- $imported["Quasi_Sight"] = 0.8
- if $imported["Quasi"] >= 0.2 && $imported["Quasi_Movement"] >= 0.85
- #==============================================================================
- # ** Game_Character
- #------------------------------------------------------------------------------
- # A character class with mainly movement route and other such processing
- # added. It is used as a super class of Game_Player, Game_Follower,
- # GameVehicle, and Game_Event.
- #==============================================================================
- class Game_Character < Game_CharacterBase
- alias qs_init init_public_members
- #--------------------------------------------------------------------------
- # * Initialize Public Member Variables
- #--------------------------------------------------------------------------
- def init_public_members
- qs_init
- @last_pos = [0,0]
- @last_dir = 0
- end
- def update_sight?
- if @last_pos != [(@px/32.0).truncate, (@py/32.0).truncate] || @last_dir != @direction
- @last_pos = [(@px/32.0).truncate, (@py/32.0).truncate]
- @last_dir = @direction
- return true
- end
- return false
- end
- #--------------------------------------------------------------------------
- # * Checks event's range
- # Use angles
- # radian = angle/180 * pi
- # hypot = adj / cos(radian)
- # opp = hypot * sin(radian)
- #--------------------------------------------------------------------------
- def sight(range=6, obj=$game_player, shape=:triangle)
- x1 = @x
- y1 = @y
- case shape
- when :triangle
- dir = @direction
- if (dir == 2 || dir == 8)
- range = [(obj.y.round-y1).truncate.abs,range].min
- range = 1 if range == 0
- x2 = x1 - range
- x3 = x1 + range
- y2 = y1 + (dir == 2 ? range : -range)
- y3 = y2
- else
- range = [(obj.x.round-x1).truncate.abs,range].min
- range = 1 if range == 0
- y2 = y1 - range
- y3 = y1 + range
- x2 = x1 + (dir == 6 ? range : -range)
- x3 = x2
- end
- rays = [[x1,y1,x2,y2],[x1,y1,x3,y3]]
- area = ray_cast(rays)
- # Check if inside area
- return false if !inside_area(area, obj)
- # Check Events
- shadows = $game_map.events.values.select do |event|
- next if event == self
- next if event.see_through || event.through
- next if event.x.truncate == @x.truncate+range ||
- event.y.truncate == @y.truncate+range
- inside_area(area, event)
- end
- shadows.each do |event|
- return false if inside_area(shadow_cast(event, range), obj)
- end
- # Check regions
- return false if region_inside_area(obj, area, range)
- return true
- end
- false
- end
- #--------------------------------------------------------------------------
- # * Makes area from 2 lines
- #--------------------------------------------------------------------------
- def ray_cast(rays)
- area = []
- rays.each_with_index do |line, i|
- xi = line[0].round; yi = line[1].round
- xf = line[2].round; yf = line[3].round
- xdif = xi - xf
- ydif = yi - yf
- x1 = xi < xf ? xi : xf
- x2 = x1 == xi ? xf : xi
- y1 = yi < yf ? yi : yf
- y2 = y1 == yi ? yf : yi
- slope = ydif.to_f / xdif if xdif != 0
- area[i] = [] if area[i].nil?
- for y in y1..y2
- for x in x1..x2
- next if area[i].include?([x,y])
- if slope == 0
- next unless y == y1
- area[i] << [x,y]
- elsif slope.nil?
- next unless x == x1
- area[i] << [x,y]
- else
- next unless (y-yi).abs.truncate == ((x-xi)*slope).abs.truncate ||
- (x-xi).abs.truncate == ((y-yi)/slope).abs.truncate
- area[i] << [x,y]
- end
- end
- end
- end
- area.each_with_index do |line, i|
- line.reverse! if line[0] != [rays[i][0],rays[i][1]]
- end
- return area
- end
- #--------------------------------------------------------------------------
- # * Gets lines for shadows
- #--------------------------------------------------------------------------
- def shadow_cast(obj, range, reg=false)
- vertices = obj
- vertices = obj.vertices if reg == false
- x = v_center[0]; y = v_center[1]
- angle_tl = Math.angle([x,-y],[vertices[0][0],-vertices[0][1]])
- angle_tr = Math.angle([x,-y],[vertices[1][0],-vertices[1][1]])
- angle_bl = Math.angle([x,-y],[vertices[2][0],-vertices[2][1]])
- angle_br = Math.angle([x,-y],[vertices[3][0],-vertices[3][1]])
- angle_hash = {
- angle_tl => vertices[0], angle_tr => vertices[1],
- angle_bl => vertices[2], angle_br => vertices[3]
- }
- angle1 = angle_hash.select{|k, v| k == angle_hash.keys.max}
- angle1 = angle1.values.flatten
- angle2 = angle_hash.select{|k, v| k == angle_hash.keys.min}
- angle2 = angle2.values.flatten
- slope1 = (y-angle1[1])/(angle1[0]-x) if (angle1[0]-x) != 0
- slope2 = (y-angle2[1])/(angle2[0]-x) if (angle2[0]-x) != 0
- range = (@direction == 2 || @direction == 6) ? range : -range
- if @direction == 2 || @direction == 8
- v1 = v2 = x
- v1 = (((range*32)+y-angle1[1])/slope1) - angle1[0] if slope1 != 0
- v2 = (((range*32)+y-angle2[1])/slope2) - angle2[0] if slope2 != 0
- v1 = x < angle1[0] ? x+range.abs : x-range.abs if slope1 == 0
- v2 = x < angle2[0] ? x+range.abs : x-range.abs if slope2 == 0
- else
- # This formula is sightly incorrect, might works in most cases
- # as long as the event is at the end of the range. if it is
- # it makes a big shadow instead.
- v1 = y < angle1[1] ? y+range.abs : y-range.abs
- v2 = y < angle2[1] ? y+range.abs : y-range.abs
- v1 = (((range*32)+x-angle1[0])*slope1) - angle1[1] if slope1 != nil
- v2 = (((range*32)+x-angle2[0])*slope2) - angle2[1] if slope2 != nil
- v1 = 0 if slope1 == 0
- v2 = 0 if slope2 == 0
- end
- p1 = (v1/32.0).truncate
- p2 = (v2/32.0).truncate
- p3 = p1.abs > p2.abs ? p2.abs : p1.abs
- p4 = p3 == p1.abs ? p2.abs : p1.abs
- if reg == false
- if @direction == 2 || @direction == 8
- rays = [[obj.x, obj.y, p3, @y+range], [obj.x, obj.y, p4, @y+range]]
- else
- rays = [[obj.x, obj.y, @x+range, p3], [obj.x, obj.y, @x+range, p4]]
- end
- else
- if @direction == 2 || @direction == 8
- rays = [[reg[0], reg[1], p3, @y+range], [reg[0], reg[1], p4, @y+range]]
- else
- rays = [[reg[0], reg[1], @x+range, p3], [reg[0], reg[1], @x+range, p4]]
- end
- end
- return ray_cast(rays)
- end
- #--------------------------------------------------------------------------
- # * Checks if obj is inside area
- #--------------------------------------------------------------------------
- def inside_area(area, obj)
- passed1 = false; passed2 = false
- if (@direction == 2 || @direction == 8)
- area[0].each do |left|
- next unless obj.x.round >= left[0] && obj.y.round == left[1]
- passed1 = true
- end
- area[1].each do |right|
- next unless obj.x.round<= right[0] && obj.y.round == right[1]
- passed2 = true
- end
- else
- area[0].each do |top|
- next unless obj.y.round >= top[1] && obj.x.round == top[0]
- passed1 = true
- end
- area[1].each do |bot|
- next unless obj.y.round <= bot[1] && obj.x.round == bot[0]
- passed2 = true
- end
- end
- return passed1 && passed2
- end
- #--------------------------------------------------------------------------
- # * Checks regions inside area
- #--------------------------------------------------------------------------
- def region_inside_area(obj,area,range)
- field = []
- regions = []
- rbox = Quasi::Movement::REGIONBOXES.keys
- for i in 0..range
- field << [area[0][i][0]..area[1][i][0],area[0][i][1]..area[1][i][1]]
- end
- field.each do |f|
- for y in f[1]
- for x in f[0]
- next unless rbox.include?($game_map.region_id(x,y))
- next if Quasi::Sight::SEEREGIONS.include?($game_map.region_id(x,y))
- next if x == @x.truncate+range || y == @y.truncate+range
- next if x == @x.truncate-range || y == @y.truncate-range
- regions << [x,y]
- end
- end
- end
- regions.each do |reg|
- rb = regbox(reg[0],reg[1])
- if rb[0].is_a?(Array)
- rb.each do |box|
- tl = [box[0].first,box[1].first]
- tr = [box[0].last,box[1].first]
- bl = [box[0].first,box[1].last]
- br = [box[0].last,box[1].last]
- return true if inside_area(shadow_cast([tl, tr, bl, br], range, reg), obj)
- end
- else
- tl = [rb[0].first,rb[1].first]
- tr = [rb[0].last,rb[1].first]
- bl = [rb[0].first,rb[1].last]
- br = [rb[0].last,rb[1].last]
- return true if inside_area(shadow_cast([tl, tr, bl, br], range, reg), obj)
- end
- end
- return false
- end
- #--------------------------------------------------------------------------
- # * See Through
- #--------------------------------------------------------------------------
- def see_through
- grab_comment(/(?i:<seethrough>)/)
- end
- end
- else
- msgbox(sprintf("[Quasi Sight] Requires Quasi module + Quasi Movement to run."))
- end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement