Added construction complete order, added jeep overlay image to show windscreen, added rotors component for helicopter; more work needed, replaced all build and vehicle assets with ones that are 6x larger to prevent pixelization when zoomed in, misc.

This commit is contained in:
2021-01-08 12:41:04 -06:00
parent 0d449b9375
commit a3c3939f50
45 changed files with 149 additions and 66 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 KiB

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 478 B

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 7.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 613 B

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 344 B

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 764 B

After

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 511 B

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 768 B

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 7.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 KiB

After

Width:  |  Height:  |  Size: 14 KiB

View File

@@ -1,6 +1,4 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
@@ -14,11 +12,11 @@
viewBox="0 0 25.399999 25.400001"
version="1.1"
id="svg1914"
inkscape:version="0.92.4 5da689c313, 2019-01-14"
inkscape:version="1.0.1 (3bc2e813f5, 2020-09-07)"
sodipodi:docname="construction_yard.svg"
inkscape:export-filename="/home/cyberarm/Code/i-mic-rts/assets/buildings/construction_yard/construction_yard_overlay.png"
inkscape:export-xdpi="96"
inkscape:export-ydpi="96">
inkscape:export-filename="/home/cyberarm/Code/i-mic-rts/assets/buildings/construction_yard/construction_yard.png"
inkscape:export-xdpi="576"
inkscape:export-ydpi="576">
<defs
id="defs1908">
<filter
@@ -102,8 +100,8 @@
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="5.730767"
inkscape:cx="23.5431"
inkscape:cy="40.736561"
inkscape:cx="14.700343"
inkscape:cy="47.457411"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
@@ -122,13 +120,14 @@
units="px"
inkscape:showpageshadow="false"
inkscape:window-width="1920"
inkscape:window-height="1006"
inkscape:window-height="1024"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
showguides="true"
inkscape:guide-bbox="true"
inkscape:snap-global="true">
inkscape:snap-global="true"
inkscape:document-rotation="0">
<sodipodi:guide
position="1.5875,14.410343"
orientation="1,0"

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 645 B

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 734 B

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 462 B

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 628 B

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 505 B

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 648 B

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 926 B

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 234 B

After

Width:  |  Height:  |  Size: 570 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 800 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 235 B

After

Width:  |  Height:  |  Size: 684 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 455 B

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 369 B

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 634 B

After

Width:  |  Height:  |  Size: 3.2 KiB

View File

@@ -3,6 +3,8 @@ class IMICRTS
def setup
data.construction_progress ||= 0
data.construction_goal ||= Entity.get(@parent.name).build_steps
data.construction_complete ||= false
data.construction_complete_ordered ||= false
@text = CyberarmEngine::Text.new("", y: @parent.position.y, z: Float::INFINITY, size: 12)
data.state = :construct # deconstruct, building, idle
@@ -32,7 +34,7 @@ class IMICRTS
end
def construction_complete?
data.construction_progress >= data.construction_goal
data.construction_progress >= data.construction_goal && data.construction_complete
end
# WARNING: returns a floating point number, not network safe!
@@ -44,7 +46,14 @@ class IMICRTS
raise TypeError, "Got a non integer value!" unless work.is_a?(Integer)
data.construction_progress += work
data.construction_progress = data.construction_goal if construction_complete?
return unless data.construction_progress > data.construction_goal
data.construction_progress = data.construction_goal
unless data.construction_complete_ordered
@parent.director.schedule_order(IMICRTS::Order::CONSTRUCTION_COMPLETE, @parent.player.id, @parent.id)
data.construction_complete_ordered = true
end
end
def draw_construction

42
lib/components/rotors.rb Normal file
View File

@@ -0,0 +1,42 @@
class IMICRTS
class Rotors < Component
attr_accessor :angle, :speed, :center
def setup
@angle = 0
@speed = 1
@center = CyberarmEngine::Vector.new(0.5, 0.5)
end
def body_image=(image)
@body_image = get_image("#{IMICRTS::ASSETS_PATH}/#{image}", retro: true)
end
def shell_image=(image)
@shell_image = get_image("#{IMICRTS::ASSETS_PATH}/#{image}", retro: true)
end
def overlay_image=(image)
@overlay_image = get_image("#{IMICRTS::ASSETS_PATH}/#{image}", retro: true)
end
def render
image = @shell_image || @body_image || @overlay_image
@render = Gosu.render(image.width, image.height, retro: true) do
@body_image&.draw(0, 0, 0)
@shell_image&.draw_rot(0, 0, 0, 0, 0, 0, 1, 1, @parent.player.color)
@overlay_image&.draw(0, 0, 0)
end
end
def draw
render unless @render
@render.draw_rot(@parent.position.x, @parent.position.y, @parent.position.z, @angle, @center.x, @center.y, @parent.scale.x, @parent.scale.y)
end
def update
@angle += @speed
end
end
end

View File

@@ -1,6 +1,7 @@
class IMICRTS
class Turret < Component
attr_accessor :angle, :center
def setup
@angle = 0
@center = CyberarmEngine::Vector.new(0.5, 0.5)
@@ -19,16 +20,18 @@ class IMICRTS
end
def render
@render = Gosu.render(32, 32, retro: true) do
@body_image.draw(0, 0, 0) if @body_image
@shell_image.draw_rot(0, 0, 0, 0, 0, 0, 1, 1, @parent.player.color) if @shell_image
@overlay_image.draw(0, 0, 0) if @overlay_image
image = @shell_image || @body_image || @overlay_image
@render = Gosu.render(image.width, image.height, retro: true) do
@body_image&.draw(0, 0, 0)
@shell_image&.draw_rot(0, 0, 0, 0, 0, 0, 1, 1, @parent.player.color)
@overlay_image&.draw(0, 0, 0)
end
end
def draw
render unless @render
@render.draw_rot(@parent.position.x, @parent.position.y, @parent.position.z, @angle, @center.x, @center.y)
@render.draw_rot(@parent.position.x, @parent.position.y, @parent.position.z, @angle, @center.x, @center.y, @parent.scale.x, @parent.scale.y)
end
def update

View File

@@ -2,7 +2,7 @@ class IMICRTS
class Director
attr_reader :current_tick, :map, :game, :players
def initialize(game:, map:, players: [], networking_mode:, tick_rate: 10, local_game: true)
def initialize(game:, map:, players: [], networking_mode:, tick_rate: 10, local_game: true, replay: false)
@game = game
@map = map
@players = players
@@ -10,6 +10,7 @@ class IMICRTS
@networking_mode = networking_mode
@tick_rate = tick_rate
@local_game = local_game
@replay = replay
@last_tick_at = Gosu.milliseconds
@tick_time = 1000.0 / @tick_rate
@@ -20,6 +21,10 @@ class IMICRTS
@local_game
end
def replay?
@replay
end
def add_player(player)
@players << player
end
@@ -40,22 +45,21 @@ class IMICRTS
player.tick(@current_tick)
# Records where player is looking at tick
# record_order(Order::CAMERA_MOVE, player.id, *player.camera.to_a)# if player.camera_moved?
schedule_order(Order::CAMERA_MOVE, player.id, *player.camera.to_a) if player.camera_moved?
player.orders.sort_by {|order| order.tick_id }.each do |order|
player.orders.sort_by(&:tick_id).each do |order|
raise DesyncError, "Have orders from an already processed tick! (#{order.tick_id} < #{current_tick})" if order.tick_id < @current_tick
next if order.tick_id > @current_tick
raise UndefinedOrderError unless (o = Order.get(Integer(order.serialized_order.unpack1("C"))))
if _order = Order.get(Integer(order.serialized_order.unpack("C").first))
# Chop off Order ID
_order_data = order.serialized_order
_order_args = _order.deserialize(_order_data[1.._order_data.length - 1], self)
order_data = order.serialized_order
order_args = o.deserialize(order_data[1..order_data.length - 1], self)
execute_order(_order.id, *_order_args)
execute_order(o.id, *order_args)
player.orders.delete(order)
else
raise UndefinedOrderError
end
break if order.tick_id > @current_tick
end
@@ -77,38 +81,22 @@ class IMICRTS
klass.new(director: self, entity: entity, goal: goal, travels_along: travels_along, allow_diagonal: allow_diagonal)
end
def record_order(order_id, *args)
if order = Order.get(order_id)
struct = order.struct(args)
scheduled_order = Player::ScheduledOrder.new( order_id, @current_tick + 1, order.serialize(struct, self) )
@connection.add_order(scheduled_order)
player(struct.player_id).orders.push(scheduled_order)
else
raise "Undefined order: #{Order.order_name(order_id)}"
end
end
def schedule_order(order_id, *args)
if order = Order.get(order_id)
raise UndefinedOrderError, "Undefined order: #{Order.order_name(order_id)}" unless (order = Order.get(order_id))
struct = order.struct(args)
pp Order.order_name(order_id)
puts "Issued order: #{Order.order_name(order_id).inspect} [tick: #{@current_tick}]" if Setting.enabled?(:debug_mode)
scheduled_order = Player::ScheduledOrder.new(order_id, @current_tick + 2, order.serialize(struct, self))
@connection.add_order(scheduled_order)
player(struct.player_id).orders.push(scheduled_order)
else
raise "Undefined order: #{Order.order_name(order_id)}"
end
end
def execute_order(order_id, *args)
if order = Order.get(order_id)
raise UndefinedOrderError, "Undefined order: #{Order.order_name(order_id)}" unless (order = Order.get(order_id))
order.execute(self, *args)
else
raise "Undefined order: #{Order.order_name(order_id)}"
end
end
def each_tile(vector, entity, &block)

View File

@@ -48,7 +48,7 @@ IMICRTS::Entity.define_entity(:construction_yard, :building, 2_000, 310, "Provid
entity.on_tick do
if entity.component(:building).data.state == :idle
if entity.component(:building).construction_complete?
item = entity.component(:build_queue).queue.first
entity.particle_emitters.each_with_index do |emitter, i|

View File

@@ -37,6 +37,7 @@ IMICRTS::Entity.define_entity(:war_factory, :building, 2_000, 310, "Builds and r
entity.particle_emitters << IMICRTS::SmokeEmitter.new(position: p2, emitting: false)
entity.on_tick do
if entity.component(:building).construction_complete?
item = entity.component(:build_queue).queue.first
entity.particle_emitters.each do |pe|
@@ -44,3 +45,4 @@ IMICRTS::Entity.define_entity(:war_factory, :building, 2_000, 310, "Builds and r
end
end
end
end

View File

@@ -1,5 +1,6 @@
IMICRTS::Entity.define_entity(:helicopter, :unit, 400, 40, "Attacks ground targets") do |entity|
entity.has(:movement)
entity.has(:rotors)
entity.speed = 2.5
entity.radius = 14
@@ -10,6 +11,10 @@ IMICRTS::Entity.define_entity(:helicopter, :unit, 400, 40, "Attacks ground targe
entity.shell_image = "vehicles/helicopter/helicopter_shell.png"
entity.overlay_image = "vehicles/helicopter/helicopter_overlay.png"
entity.component(:rotors).body_image = "vehicles/helicopter/helicopter_rotors.png"
entity.component(:rotors).center.y = 0.593
entity.component(:rotors).speed = 500 / 60.0
entity.on_tick do
end
end

View File

@@ -9,9 +9,10 @@ IMICRTS::Entity.define_entity(:jeep, :unit, 400, 40, "Attacks ground targets") d
entity.body_image = "vehicles/jeep/jeep.png"
entity.shell_image = "vehicles/jeep/jeep_shell.png"
entity.overlay_image = "vehicles/jeep/jeep_overlay.png"
entity.component(:turret).shell_image = "vehicles/jeep/jeep_turret_shell.png"
entity.component(:turret).center.y = 0.3125
entity.component(:turret).center.y = 0.5
entity.on_tick do
end

View File

@@ -16,7 +16,7 @@ class IMICRTS
attr_reader :director, :player, :id, :name, :type, :data, :proto_entity
attr_accessor :position, :angle, :radius, :target, :state, :movement, :health, :max_health,
:speed, :turret, :center, :particle_emitters, :color
:speed, :turret, :center, :scale, :particle_emitters, :color
def initialize(name:, player:, id:, position:, angle:, director:, proto_entity: false)
@player = player
@@ -37,6 +37,8 @@ class IMICRTS
@target = nil
@state = :idle
@center = CyberarmEngine::Vector.new(0.5, 0.5)
@scale = CyberarmEngine::Vector.new(1, 1)
@scale *= 1 / 6.0
@particle_emitters = []
@components = {}
@@ -136,7 +138,7 @@ class IMICRTS
def draw
render unless @render
@render.draw_rot(@position.x, @position.y, @position.z, @angle, @center.x, @center.y, 1, 1, @color)
@render.draw_rot(@position.x, @position.y, @position.z, @angle, @center.x, @center.y, @scale.x, @scale.y, @color)
unless @proto_entity
@components.values.each(&:draw)

View File

@@ -1,6 +1,7 @@
class IMICRTS
class DesyncError < Exception
end
class UndefinedOrderError < Exception
end
end

View File

@@ -37,7 +37,7 @@ class IMICRTS
end
def execute(director, *arguments)
pp Order.order_name(id)
puts "Executing order: #{Order.order_name(id).inspect} [tick: #{director.current_tick}]" if Setting.enabled?(:debug_mode)
@handler.call(struct(arguments), director)
end

View File

@@ -10,8 +10,8 @@ IMICRTS::Order.define_handler(IMICRTS::Order::BUILD_UNIT_COMPLETE, arguments: [:
end
IMICRTS::Order.define_serializer(IMICRTS::Order::BUILD_UNIT_COMPLETE) do |order, director|
# Order ID | Player ID
# char | char
# Order ID | Player ID | Entity ID
# char | char | Integer
[IMICRTS::Order::BUILD_UNIT_COMPLETE, order.player_id, order.entity_id].pack("CCN")
end

View File

@@ -1,5 +1,5 @@
IMICRTS::Order.define_handler(IMICRTS::Order::CAMERA_MOVE, arguments: [:player_id, :x, :y, :zoom]) do |order, director|
director.player(order.player_id).camera.move_to(order.x, order.y, order.zoom)
director.player(order.player_id).camera.move_to(order.x, order.y, order.zoom) if director.replay?
end
IMICRTS::Order.define_serializer(IMICRTS::Order::CAMERA_MOVE) do |order, director|

View File

@@ -0,0 +1,20 @@
IMICRTS::Order.define_handler(IMICRTS::Order::CONSTRUCTION_COMPLETE, arguments: [:player_id, :entity_id]) do |order, director|
entity = director.player(order.player_id).entity(order.entity_id)
entity.component(:building).data.construction_complete = true
end
IMICRTS::Order.define_serializer(IMICRTS::Order::CONSTRUCTION_COMPLETE) do |order, director|
# Order ID | Player ID | Entity ID
# char | char | Integer
[IMICRTS::Order::CONSTRUCTION_COMPLETE, order.player_id, order.entity_id].pack("CCN")
end
IMICRTS::Order.define_deserializer(IMICRTS::Order::CONSTRUCTION_COMPLETE) do |string, director|
# String fed into deserializer has Order ID removed
# Player ID | Entity ID
# char | integer
data = string.unpack("CN")
[data[0], data[1]]
end

View File

@@ -12,12 +12,18 @@ class IMICRTS
@entities = []
@orders = []
@camera = Camera.new(viewport: [0, 0, $window.width, $window.height])
@last_camera_position = @camera.position.clone
@camera_moved = true
@camera_move_threshold = 5
@selected_entities = []
@current_entity_id = 0
end
def tick(tick_id)
@camera_moved = (@last_camera_position - @camera.position.clone).sum > @camera_move_threshold
@last_camera_position = @camera.position.clone
@entities.each { |ent| ent.tick(tick_id) }
end
@@ -33,6 +39,10 @@ class IMICRTS
@current_entity_id += 1
end
def camera_moved?
@camera_moved
end
class ScheduledOrder
attr_reader :order_id, :tick_id, :serialized_order
def initialize(order_id, tick_id, serialized_order)

View File

@@ -60,6 +60,7 @@ class IMICRTS
position: CyberarmEngine::Vector.new(player.spawnpoint.x, player.spawnpoint.y, ZOrder::BUILDING)
)
construction_yard.component(:building).data.construction_progress = Entity.get(construction_yard.name).build_steps
construction_yard.component(:building).data.construction_complete = true
@director.each_tile(@director.map.world_to_grid(construction_yard.position), construction_yard.name) do |tile, space_required|
if space_required == true
tile.entity = construction_yard