TileMap parser can now load spawn locations, added construction yard building, added particle emitters, added smoke sprite and svg.

This commit is contained in:
2019-11-20 12:51:24 -06:00
parent 7775ccb3a3
commit a9307733e3
10 changed files with 476 additions and 6 deletions

View File

@@ -0,0 +1,34 @@
IMICRTS::Entity.define_entity(:construction_yard, :building, 2_000, "Provides radar and builds construction workers") do |entity|
entity.radius = 40
entity.max_health = 100.0
entity.body_image = "buildings/construction_yard/construction_yard.png"
entity.shell_image = "buildings/construction_yard/construction_yard_shell.png"
entity.overlay_image = "buildings/construction_yard/construction_yard_overlay.png"
position = entity.position.clone
position.z = IMICRTS::ZOrder::OVERLAY
emitters = []
p1 = position.clone
p1.x -= 25
p1.y -= 8
p2 = p1.clone
p2.y += 25
p3 = position.clone
p3.x += 8
p3.y -= 15
p4 = p3.clone
p4.x += 21
emitters.push(p1, p2, p3, p4)
emitters.each do |pos|
entity.particle_emitters << IMICRTS::SmokeEmitter.new(position: pos)
end
entity.on_tick do
end
end

View File

@@ -18,7 +18,7 @@ class IMICRTS
attr_reader :player, :id, :name, :type, :speed
attr_accessor :position, :angle, :radius, :target, :state,
:movement, :health, :max_health,
:turret, :center
:turret, :center, :particle_emitters
def initialize(name:, player:, id:, position:, angle:, director:)
@player = player
@id = id
@@ -27,10 +27,13 @@ class IMICRTS
@director = director
@speed = 0.5
@radius = 32 / 2
@sight_radius = 5 # tiles
@range_radius = 3 # tiles
@radius = 32 / 2 # pixels
@target = nil
@state = :idle
@center = CyberarmEngine::Vector.new(0.5, 0.5)
@particle_emitters = []
@components = {}
@@ -101,7 +104,7 @@ class IMICRTS
end
def render
@render = Gosu.render(32, 32, retro: true) do
@render = Gosu.render(@shell_image.width, @shell_image.height, retro: true) do
@body_image.draw(0, 0, 0) if @body_image
@shell_image.draw(0, 0, 0, 1, 1, @player.color)
@overlay_image.draw(0, 0, 0) if @overlay_image
@@ -113,6 +116,7 @@ class IMICRTS
@render.draw_rot(@position.x, @position.y, @position.z, @angle, @center.x, @center.y)
component(:turret).draw if component(:turret)
@particle_emitters.each(&:draw)
end
def update
@@ -123,6 +127,11 @@ class IMICRTS
component(:movement).follow_path
end
@particle_emitters.each do |emitter|
@particle_emitters.delete(emitter) if emitter.die?
emitter.update
end
end
def tick(tick_id)

View File

@@ -1,6 +1,6 @@
class IMICRTS
class Map
attr_reader :tile_size, :tiles, :ores, :width, :height
attr_reader :tile_size, :tiles, :ores, :spawnpoints, :width, :height
def initialize(map_file:)
@tiled_map = TiledMap.new(map_file)
@@ -9,6 +9,7 @@ class IMICRTS
@tiles = {}
@ores = {}
@spawnpoints = @tiled_map.spawnpoints.freeze
@tiled_map.layers.each do |layer|
layer.height.times do |y|

93
lib/particle_emitter.rb Normal file
View File

@@ -0,0 +1,93 @@
class IMICRTS
class ParticleEmitter
def initialize(position:, direction: CyberarmEngine::Vector.up, time_to_live: 1000, particle_time_to_live: 500, speed: 10.0, max_particles: 128, frequency: 10.0, images: [], color: Gosu::Color::WHITE.dup, jitter: 10.0)
@position = position
@direction = direction
@time_to_live = time_to_live
@particle_time_to_live = particle_time_to_live
@speed = speed
@max_particles = max_particles
@frequency = frequency
@images = images
@color = color
@jitter = jitter
@born_at = Gosu.milliseconds
@last_emitted_at = 0
@particles = []
@factor = CyberarmEngine::Vector.new(1.0 ,1.0)
setup
end
def setup
end
def emit
dir = @direction.clone
dir.x = rand(-@jitter.to_f..@jitter.to_f) * 1
dir.normalized
@particles << Particle.new(
position: @position, direction: dir,
factor: @factor.clone, angle: rand(360.0),
speed: @speed, time_to_live: @particle_time_to_live, image: @images.sample,
color: @color.dup
)
@last_emitted_at = Gosu.milliseconds
end
def draw
@particles.each(&:draw)
end
def update
if @particles.count < @max_particles && Gosu.milliseconds >= @last_emitted_at + (1000.0 / @frequency)
emit
end
@particles.each do |particle|
@particles.delete(particle) if particle.die?
particle.update
end
end
def die?
Gosu.milliseconds >= @born_at + @time_to_live
end
end
class Particle
attr_accessor :position, :direction, :factor, :angle, :speed, :time_to_live, :image, :color, :born_at
def initialize(position:, direction:, factor:, angle:, speed:, time_to_live:, image:, color:)
@position = position
@direction = direction
@factor = factor
@angle = angle
@speed = speed
@time_to_live = time_to_live
@image = image
@color = color
@born_at = Gosu.milliseconds
end
def draw
@image.draw_rot(*@position.to_a[0..2], @angle, 0.5, 0.5, @factor.x, @factor.y, @color)
end
def update
@position -= (@direction * @speed) * $window.dt
end
def die?
Gosu.milliseconds >= @born_at + @time_to_live
end
end
end
Dir.glob("#{IMICRTS::GAME_ROOT_PATH}/lib/particle_emitters/**/*.rb").each do |emitter|
p emitter
require_relative emitter
end

View File

@@ -0,0 +1,37 @@
class IMICRTS
class SmokeEmitter < ParticleEmitter
def setup
@time_to_live = Float::INFINITY
@particle_time_to_live = 2_500
@frequency = 10.0
@color = Gosu::Color.rgba(255, 255, 255, 255.0 * 0.4)
@direction = CyberarmEngine::Vector.up
@direction.y = 4.5
@jitter = 25.0
@images = Gosu::Image.load_tiles("#{IMICRTS::ASSETS_PATH}/smoke/smoke.png", 32, 32, retro: false)
end
def emit
super
@particles.last.factor = CyberarmEngine::Vector.new(0.1, 0.1)
end
def update
super
@particles.each do |particle|
life_cycle = (Gosu.milliseconds - particle.born_at.to_f) / particle.time_to_live
scale = (2.0 * life_cycle) + 0.25
particle.factor.x = scale
particle.factor.y = scale
particle.color.alpha = ((255.0 * (1.0 - life_cycle)) - 255.0 * 0.4).clamp(0.0, 255.0)
particle.angle += rand(0.1..0.5)
particle.direction.x = Math.cos(Gosu.milliseconds / 1_000.0) * 0.162
end
end
end
end

View File

@@ -65,7 +65,24 @@ class IMICRTS
end
end
100.times { |i| [@c, @h, @t].sample.instance_variable_get("@block").call }
# 100.times { |i| [@c, @h, @t].sample.instance_variable_get("@block").call }
spawnpoint = @director.map.spawnpoints.last
@player.entities << Entity.new(
name: :construction_yard,
director: @director,
player: @player,
id: @player.next_entity_id,
position: CyberarmEngine::Vector.new(spawnpoint.x, spawnpoint.y, ZOrder::BUILDING),
angle: 0
)
@player.entities << Entity.new(
name: :construction_worker,
director: @director,
player: @player,
id: @player.next_entity_id,
position: CyberarmEngine::Vector.new(spawnpoint.x - 64, spawnpoint.y + 64, ZOrder::GROUND_VEHICLE),
angle: 0
)
end
def draw

View File

@@ -1,7 +1,7 @@
class IMICRTS
class TiledMap
attr_reader :width, :height, :tile_size
attr_reader :layers, :tilesets
attr_reader :layers, :tilesets, :spawnpoints
def initialize(map_file)
@xml = Nokogiri::XML(File.read("#{IMICRTS::ASSETS_PATH}/#{map_file}"))
@@ -10,6 +10,7 @@ class IMICRTS
@layers = []
@tilesets = []
@spawnpoints = []
@tiles = []
@@ -33,6 +34,15 @@ class IMICRTS
@xml.search("//layer").each do |layer|
@layers << Layer.new(layer)
end
@xml.search("//objectgroup").each do |objectgroup|
if objectgroup.attr("name") == "spawns"
objectgroup.children.each do |object|
next unless object.attr("name") && object.attr("name").downcase.strip == "spawn"
@spawnpoints << SpawnPoint.new(object)
end
end
end
end
def get_tile(tile_id)
@@ -121,5 +131,14 @@ class IMICRTS
end
end
end
class SpawnPoint
attr_reader :x, :y
def initialize(xml_object)
@x, @y = Integer(xml_object.attr("x")), Integer(xml_object.attr("y"))
end
end
end
end