166 lines
4 KiB
Ruby
166 lines
4 KiB
Ruby
|
###########
|
||
|
# utility, math, and misc methods
|
||
|
|
||
|
# returns random val between min & max, inclusive
|
||
|
# needs integers, use rand if you don't need min/max and don't care much
|
||
|
def random(min, max)
|
||
|
min = Integer(min)
|
||
|
max = Integer(max)
|
||
|
rand((max + 1) - min) + min
|
||
|
end
|
||
|
|
||
|
# returns true the passed in % of the time
|
||
|
# ex: `percent_chance?(25)` -- 1/4 chance of returning true
|
||
|
def percent_chance?(percent)
|
||
|
error("percent param (#{percent}) can't be above 100!") if percent > 100.0
|
||
|
return false if percent == 0.0
|
||
|
return true if percent == 100.0
|
||
|
rand() < (percent / 100.0)
|
||
|
end
|
||
|
|
||
|
# strips away the junk added by GTK::OpenEntity
|
||
|
def open_entity_to_hash(open_entity)
|
||
|
open_entity.as_hash.except(:entity_id, :entity_name, :entity_keys_by_ref, :__thrash_count__)
|
||
|
end
|
||
|
|
||
|
# Executes the block for each intersection of the collections. Doesn't check
|
||
|
# intersections within a parameter
|
||
|
#
|
||
|
# Block arguments are an instance of each collection, ordered by the parameter
|
||
|
# order.
|
||
|
#
|
||
|
# ex:
|
||
|
# collide(tiles, enemies) do |tile, enemy|
|
||
|
# # do stuff!
|
||
|
# end
|
||
|
#
|
||
|
# collide(player, enemies) do |player, enemy|
|
||
|
# player.health -= enemy.power
|
||
|
# end
|
||
|
def collide(col1, col2, &block)
|
||
|
col1 = [col1] unless col1.is_a?(Array)
|
||
|
col2 = [col2] unless col2.is_a?(Array)
|
||
|
|
||
|
col1.each do |i|
|
||
|
col2.each do |j|
|
||
|
if i.intersect_rect?(j)
|
||
|
block.call(i, j)
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
# +angle+ is expected to be in degrees with 0 being facing right
|
||
|
def vel_from_angle(angle, speed)
|
||
|
[speed * Math.cos(deg_to_rad(angle)), speed * Math.sin(deg_to_rad(angle))]
|
||
|
end
|
||
|
|
||
|
# returns diametrically opposed angle
|
||
|
# uses degrees
|
||
|
def opposite_angle(angle)
|
||
|
add_to_angle(angle, 180)
|
||
|
end
|
||
|
|
||
|
# returns a new angle from the og `angle` one summed with the `diff`
|
||
|
# degrees! of course
|
||
|
def add_to_angle(angle, diff)
|
||
|
((angle + diff) % 360).abs
|
||
|
end
|
||
|
|
||
|
def deg_to_rad(deg)
|
||
|
(deg * Math::PI / 180).round(4)
|
||
|
end
|
||
|
|
||
|
# Returns degrees
|
||
|
def angle_for_dir(dir)
|
||
|
case dir
|
||
|
when DIR_RIGHT
|
||
|
0
|
||
|
when DIR_LEFT
|
||
|
180
|
||
|
when DIR_UP
|
||
|
90
|
||
|
when DIR_DOWN
|
||
|
270
|
||
|
else
|
||
|
error("invalid dir: #{dir}")
|
||
|
end
|
||
|
end
|
||
|
|
||
|
# checks if the passed in `rect` is outside of the `container`
|
||
|
# `container` can be any rectangle-ish data structure
|
||
|
def out_of_bounds?(container, rect)
|
||
|
rect.x > container.right ||
|
||
|
rect.x + rect.w < container.left ||
|
||
|
rect.y > container.top ||
|
||
|
rect.y + rect.h < container.bottom
|
||
|
end
|
||
|
|
||
|
# Raises an exception with the passing in error message
|
||
|
# `msg` - String
|
||
|
def error(msg)
|
||
|
raise StandardError.new(msg)
|
||
|
end
|
||
|
|
||
|
# The version of your game defined in `metadata/game_metadata.txt`
|
||
|
def version
|
||
|
$gtk.args.cvars['game_metadata.version'].value
|
||
|
end
|
||
|
|
||
|
# Name of who make the game
|
||
|
def dev_title
|
||
|
$gtk.args.cvars['game_metadata.devtitle'].value
|
||
|
end
|
||
|
|
||
|
# Title of the game
|
||
|
def title
|
||
|
$gtk.args.cvars['game_metadata.gametitle'].value
|
||
|
end
|
||
|
|
||
|
# debug mode is what's running when you're making the game
|
||
|
# when you build and ship your game, it's in production mode
|
||
|
def debug?
|
||
|
@debug ||= !$gtk.production
|
||
|
end
|
||
|
|
||
|
# whether or not you're on a mobile device (or simulating one)
|
||
|
def mobile?
|
||
|
$gtk.platform?(:mobile) || $gtk.args.state.simulate_mobile
|
||
|
end
|
||
|
|
||
|
# sets the passed in entity's color for the specified number of ticks
|
||
|
def flash(entity, color, tick_count)
|
||
|
entity.flashing = true
|
||
|
entity.flash_ticks_remaining = tick_count
|
||
|
entity.flash_color = color
|
||
|
end
|
||
|
|
||
|
def tick_flasher(entity)
|
||
|
if entity.flashing
|
||
|
entity.flash_ticks_remaining -= 1
|
||
|
entity.merge!(entity.flash_color)
|
||
|
if entity.flash_ticks_remaining <= 0
|
||
|
entity.flashing = false
|
||
|
reset_color(entity)
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
def reset_color(entity)
|
||
|
entity.a = nil
|
||
|
entity.r = nil
|
||
|
entity.g = nil
|
||
|
entity.b = nil
|
||
|
end
|
||
|
|
||
|
# Returns a hash of the x and y position coords of the center of the entity.
|
||
|
# The passed in `entity` must have x, y, h, and w attributes
|
||
|
#
|
||
|
# Ex:
|
||
|
# center_of({ x: 100, y: 100, w: 200, h: 250 })
|
||
|
# # => { x: 200.0, y: 225.0 }
|
||
|
def center_of(entity)
|
||
|
raise StandardError.new("entity does not have needed properties to find center; must have x, y, w, and h properties") unless entity.x && entity.y && entity.h && entity.w
|
||
|
{ x: entity.x + entity.w / 2, y: entity.y + entity.h / 2 }
|
||
|
end
|