diff --git a/Games/Debris_Dodge/Assets/debris dodge.png b/Games/Debris_Dodge/Assets/debris dodge.png new file mode 100644 index 0000000000..4084447392 Binary files /dev/null and b/Games/Debris_Dodge/Assets/debris dodge.png differ diff --git a/Games/Debris_Dodge/Assets/debriss.png b/Games/Debris_Dodge/Assets/debriss.png new file mode 100644 index 0000000000..f15054948b Binary files /dev/null and b/Games/Debris_Dodge/Assets/debriss.png differ diff --git a/Games/Debris_Dodge/Gemfile b/Games/Debris_Dodge/Gemfile new file mode 100644 index 0000000000..27243f1b8e --- /dev/null +++ b/Games/Debris_Dodge/Gemfile @@ -0,0 +1,4 @@ +source 'https://rubygems.org' + +# Specify your gem's dependencies in tank_island.gemspec +gemspec diff --git a/Games/Debris_Dodge/README.md b/Games/Debris_Dodge/README.md new file mode 100644 index 0000000000..1250c52958 --- /dev/null +++ b/Games/Debris_Dodge/README.md @@ -0,0 +1,79 @@ +# **Debris Dodge** + +--- + +
+Give you best Hit! + +## **Description 📃** +Tank Island is an open source 2D top down shooter game that was created with Ruby using +[Gosu](http://www.libgosu.org) game development library while writing +[this book](https://leanpub.com/developing-games-with-ruby/). + + +## **functionalities 🎮** + +Top down 2D shooter game that involves blowing up tanks + +
+ +## **How to play? 🕹️** + +- `W` `A` `S` `D` moves your tank. +- Mouse `left click` shoots. +- `ESC` goes into menu and away from it. +- `R` respawns your tank. +- `T` spawns an enemy tank under mouse cursor. +- `F1` enters debug mode. +- `F2` toggles profiling + + +
+ +## **Screenshots 📸** + +
Image Description +
+Image Description +
+ + + + + +
+ +## Installation + +Before installing, make sure you have: + +- Ruby installed, preferably through [rbenv](https://github.com/sstephenson/rbenv), not rvm. +- ImageMagick (`gem install rmagick` should work). +- Gosu prerequisites for [Mac](https://github.com/jlnr/gosu/wiki/Getting-Started-on-OS-X), + [Linux](https://github.com/jlnr/gosu/wiki/Getting-Started-on-Linux) or + [Windows](https://github.com/jlnr/gosu/wiki/Getting-Started-on-Windows) + +To install it, run + + $ gem install Debris_Dodge + +## Starting the game + +There are several ways to start the game. + +### Running in 800x600 window mode + + $ Debris_Dodge + +### Running with custom resolution + + $ w=1600 h=1200 Debris_Dodge + +### Running full screen with custom resolution + + $ fs=1 w=1200 h=800 Debris_Dodge + + + + + diff --git a/Games/Debris_Dodge/Rakefile b/Games/Debris_Dodge/Rakefile new file mode 100644 index 0000000000..809eb5616a --- /dev/null +++ b/Games/Debris_Dodge/Rakefile @@ -0,0 +1,2 @@ +require "bundler/gem_tasks" + diff --git a/Games/Debris_Dodge/bin/tank_island b/Games/Debris_Dodge/bin/tank_island new file mode 100644 index 0000000000..1352ca07a9 --- /dev/null +++ b/Games/Debris_Dodge/bin/tank_island @@ -0,0 +1,82 @@ +#!/usr/bin/env ruby + +require 'gosu_texture_packer' +require 'perlin_noise' +require 'gosu' + +root_dir = File.expand_path(File.join( + File.dirname(File.dirname(__FILE__)), 'lib')) + +%w( + game_states/game_state.rb + game_states/play_state.rb + entities/components/component.rb + entities/components/ai/tank_motion_state.rb + entities/game_object.rb + entities/powerups/powerup.rb + entities/box.rb + entities/bullet.rb + entities/camera.rb + entities/components/ai/gun.rb + entities/components/ai/tank_chasing_state.rb + entities/components/ai/tank_fighting_state.rb + entities/components/ai/tank_fleeing_state.rb + entities/components/ai/tank_motion_fsm.rb + entities/components/ai/tank_motion_state.rb + entities/components/ai/tank_navigating_state.rb + entities/components/ai/tank_roaming_state.rb + entities/components/ai/tank_stuck_state.rb + entities/components/ai/vision.rb + entities/components/ai_input.rb + entities/components/box_graphics.rb + entities/components/bullet_graphics.rb + entities/components/bullet_physics.rb + entities/components/bullet_sounds.rb + entities/components/component.rb + entities/components/damage_graphics.rb + entities/components/explosion_graphics.rb + entities/components/explosion_sounds.rb + entities/components/health.rb + entities/components/player_input.rb + entities/components/player_sounds.rb + entities/components/powerup_graphics.rb + entities/components/powerup_sounds.rb + entities/components/tank_graphics.rb + entities/components/tank_health.rb + entities/components/tank_physics.rb + entities/components/tank_sounds.rb + entities/components/tree_graphics.rb + entities/damage.rb + entities/explosion.rb + entities/game_object.rb + entities/hud.rb + entities/map.rb + entities/object_pool.rb + entities/powerups/fire_rate_powerup.rb + entities/powerups/health_powerup.rb + entities/powerups/powerup.rb + entities/powerups/powerup_respawn_queue.rb + entities/powerups/repair_powerup.rb + entities/powerups/tank_speed_powerup.rb + entities/radar.rb + entities/score_display.rb + entities/tank.rb + entities/tree.rb + game_states/demo_state.rb + game_states/menu_state.rb + game_states/pause_state.rb + misc/axis_aligned_bounding_box.rb + misc/game_window.rb + misc/names.rb + misc/quad_tree.rb + misc/stats.rb + misc/stereo_sample.rb + misc/utils.rb +).each do |f| + require File.join(root_dir, f) +end + +$debug = false +$window = GameWindow.new +GameState.switch(MenuState.instance) +$window.show diff --git a/Games/Debris_Dodge/lib/entities/box.rb b/Games/Debris_Dodge/lib/entities/box.rb new file mode 100644 index 0000000000..bf70c3db35 --- /dev/null +++ b/Games/Debris_Dodge/lib/entities/box.rb @@ -0,0 +1,28 @@ +class Box < GameObject + attr_reader :health, :graphics, :angle + + def initialize(object_pool, x, y) + super + @graphics = BoxGraphics.new(self) + @health = Health.new(self, object_pool, 10, true) + @angle = rand(-15..15) + end + + def on_collision(object) + return unless object.physics.speed > 1.0 + move(*Utils.point_at_distance(@x, @y, object.direction, 2)) + @box = nil + end + + def box + return @box if @box + w = @graphics.width / 2 + h = @graphics.height / 2 + # Bounding box adjusted to trim shadows + @box = [x - w + 4, y - h + 8, + x + w , y - h + 8, + x + w , y + h, + x - w + 4, y + h] + @box = Utils.rotate(@angle, @x, @y, *@box) + end +end diff --git a/Games/Debris_Dodge/lib/entities/bullet.rb b/Games/Debris_Dodge/lib/entities/bullet.rb new file mode 100644 index 0000000000..93fb0df835 --- /dev/null +++ b/Games/Debris_Dodge/lib/entities/bullet.rb @@ -0,0 +1,26 @@ +class Bullet < GameObject + attr_accessor :target_x, :target_y, :source, :speed, :fired_at + + def initialize(object_pool, source_x, source_y, target_x, target_y) + super(object_pool, source_x, source_y) + @target_x, @target_y = target_x, target_y + BulletPhysics.new(self, object_pool) + BulletGraphics.new(self) + BulletSounds.play(self, object_pool.camera) + end + + def box + [@x, @y] + end + + def explode + Explosion.new(object_pool, @x, @y, @source) + mark_for_removal + end + + def fire(source, speed) + @source = source + @speed = speed + @fired_at = Gosu.milliseconds + end +end diff --git a/Games/Debris_Dodge/lib/entities/camera.rb b/Games/Debris_Dodge/lib/entities/camera.rb new file mode 100644 index 0000000000..06ea2ead0f --- /dev/null +++ b/Games/Debris_Dodge/lib/entities/camera.rb @@ -0,0 +1,113 @@ +class Camera + attr_accessor :x, :y, :zoom + attr_reader :target + + def target=(target) + @target = target + @x, @y = target.x, target.y + @zoom = 1 + end + + def desired_spot + if @target.physics.moving? + Utils.point_at_distance( + @target.x, @target.y, + @target.direction, + @target.physics.speed.ceil * 25) + else + [@target.x, @target.y] + end + end + + def mouse_coords + x, y = target_delta_on_screen + mouse_x_on_map = @target.x + + (x + $window.mouse_x - ($window.width / 2)) / @zoom + mouse_y_on_map = @target.y + + (y + $window.mouse_y - ($window.height / 2)) / @zoom + [mouse_x_on_map, mouse_y_on_map].map(&:round) + end + + def update + des_x, des_y = desired_spot + shift = Utils.adjust_speed( + @target.physics.speed).floor * + @target.speed_modifier + 1 + if @x < des_x + if des_x - @x < shift + @x = des_x + else + @x += shift + end + elsif @x > des_x + if @x - des_x < shift + @x = des_x + else + @x -= shift + end + end + if @y < des_y + if des_y - @y < shift + @y = des_y + else + @y += shift + end + elsif @y > des_y + if @y - des_y < shift + @y = des_y + else + @y -= shift + end + end + + zoom_delta = @zoom > 0 ? 0.01 : 1.0 + zoom_delta = Utils.adjust_speed(zoom_delta) + if $window.button_down?(Gosu::KbUp) + @zoom -= zoom_delta unless @zoom < 0.7 + elsif $window.button_down?(Gosu::KbDown) + @zoom += zoom_delta unless @zoom > 10 + else + target_zoom = @target.physics.speed > 1.1 ? 0.75 : 1.0 + if @zoom <= (target_zoom - 0.01) + @zoom += zoom_delta / 3 + elsif @zoom > (target_zoom + 0.01) + @zoom -= zoom_delta / 3 + end + end + end + + def to_s + "FPS: #{Gosu.fps}. " << + "#{@x}:#{@y} @ #{'%.2f' % @zoom}. " << + 'WASD to move, arrows to zoom.' + end + + def target_delta_on_screen + [(@x - @target.x) * @zoom, (@y - @target.y) * @zoom] + end + + def draw_crosshair + factor = 0.5 + x = $window.mouse_x + y = $window.mouse_y + c = crosshair + c.draw(x - c.width * factor / 2, + y - c.height * factor / 2, + 1000, factor, factor) + end + + def viewport + x0 = @x - ($window.width / 2) / @zoom + x1 = @x + ($window.width / 2) / @zoom + y0 = @y - ($window.height / 2) / @zoom + y1 = @y + ($window.height / 2) / @zoom + [x0, x1, y0, y1] + end + + private + + def crosshair + @crosshair ||= Gosu::Image.new( + Utils.media_path('c_dot.png'), false) + end +end diff --git a/Games/Debris_Dodge/lib/entities/components/ai/gun.rb b/Games/Debris_Dodge/lib/entities/components/ai/gun.rb new file mode 100644 index 0000000000..8dec7a30c2 --- /dev/null +++ b/Games/Debris_Dodge/lib/entities/components/ai/gun.rb @@ -0,0 +1,114 @@ +class AiGun + DECISION_DELAY = 300 + attr_reader :target, :desired_gun_angle + + def initialize(object, vision) + @object = object + @vision = vision + @desired_gun_angle = rand(0..360) + @retarget_speed = rand(1..5) + @accuracy = rand(0..10) + @aggressiveness = rand(1..5) + end + + def adjust_angle + adjust_desired_angle + adjust_gun_angle + end + + def update + if @vision.in_sight.any? + if @vision.closest_tank != @target + change_target(@vision.closest_tank) + end + else + @target = nil + end + + if @target + if (0..30 - rand(0..@accuracy)).include?( + (@desired_gun_angle - @object.gun_angle).abs.round) + distance = distance_to_target + if distance - 50 <= BulletPhysics::MAX_DIST + target_x, target_y = Utils.point_at_distance( + @object.x, @object.y, @object.gun_angle, + distance + 10 - rand(0..@accuracy)) + if can_make_new_decision? && @object.can_shoot? && + should_shoot? + @object.shoot(target_x, target_y) + end + end + end + end + end + + def draw(viewport) + if $debug + color = Gosu::Color::BLUE + x, y = @object.x, @object.y + t_x, t_y = Utils.point_at_distance(x, y, @desired_gun_angle, + BulletPhysics::MAX_DIST) + $window.draw_line(x, y, color, t_x, t_y, color, 1001) + color = Gosu::Color::RED + t_x, t_y = Utils.point_at_distance(x, y, @object.gun_angle, + BulletPhysics::MAX_DIST) + $window.draw_line(x, y, color, t_x, t_y, color, 1000) + end + end + + def distance_to_target + Utils.distance_between( + @object.x, @object.y, @target.x, @target.y) + end + + + def should_shoot? + rand * @aggressiveness > 0.3 + end + + def can_make_new_decision? + now = Gosu.milliseconds + if now - (@last_decision ||= 0) > DECISION_DELAY + @last_decision = now + true + end + end + + def adjust_desired_angle + @desired_gun_angle = if @target + Utils.angle_between( + @object.x, @object.y, @target.x, @target.y) + else + @object.direction + end + end + + def change_target(new_target) + @target = new_target + adjust_desired_angle + end + + def adjust_gun_angle + actual = @object.gun_angle + desired = @desired_gun_angle + if actual > desired + if actual - desired > 180 # 0 -> 360 fix + @object.gun_angle = (actual + @retarget_speed) % 360 + if @object.gun_angle < desired + @object.gun_angle = desired # damp + end + else + @object.gun_angle = [actual - @retarget_speed, desired].max + end + elsif actual < desired + if desired - actual > 180 # 360 -> 0 fix + @object.gun_angle = (360 + actual - @retarget_speed) % 360 + if @object.gun_angle > desired + @object.gun_angle = desired # damp + end + else + @object.gun_angle = [actual + @retarget_speed, desired].min + end + end + end +end diff --git a/Games/Debris_Dodge/lib/entities/components/ai/tank_chasing_state.rb b/Games/Debris_Dodge/lib/entities/components/ai/tank_chasing_state.rb new file mode 100644 index 0000000000..36137754b5 --- /dev/null +++ b/Games/Debris_Dodge/lib/entities/components/ai/tank_chasing_state.rb @@ -0,0 +1,30 @@ +class TankChasingState < TankMotionState + def initialize(object, vision, gun) + super(object, vision) + @object = object + @vision = vision + @gun = gun + end + + def update + change_direction if should_change_direction? + drive + end + + def change_direction + @object.physics.change_direction( + @gun.desired_gun_angle - + @gun.desired_gun_angle % 45) + + @changed_direction_at = Gosu.milliseconds + @will_keep_direction_for = turn_time + end + + def drive_time + 10000 + end + + def turn_time + rand(300..600) + end +end diff --git a/Games/Debris_Dodge/lib/entities/components/ai/tank_fighting_state.rb b/Games/Debris_Dodge/lib/entities/components/ai/tank_fighting_state.rb new file mode 100644 index 0000000000..f7f9dbb121 --- /dev/null +++ b/Games/Debris_Dodge/lib/entities/components/ai/tank_fighting_state.rb @@ -0,0 +1,47 @@ +class TankFightingState < TankMotionState + def initialize(object, vision) + super + @object = object + @vision = vision + end + + def update + change_direction if should_change_direction? + if substate_expired? + rand > 0.1 ? drive : wait + end + end + + def change_direction + change = case rand(0..100) + when 0..20 + -45 + when 20..40 + 45 + when 40..60 + 90 + when 60..80 + -90 + when 80..90 + 135 + when 90..100 + -135 + end + @object.physics.change_direction( + @object.direction + change) + @changed_direction_at = Gosu.milliseconds + @will_keep_direction_for = turn_time + end + + def wait_time + rand(50..300) + end + + def drive_time + rand(5000..10000) + end + + def turn_time + rand(300..3000) + end +end diff --git a/Games/Debris_Dodge/lib/entities/components/ai/tank_fleeing_state.rb b/Games/Debris_Dodge/lib/entities/components/ai/tank_fleeing_state.rb new file mode 100644 index 0000000000..4dbe5eab0b --- /dev/null +++ b/Games/Debris_Dodge/lib/entities/components/ai/tank_fleeing_state.rb @@ -0,0 +1,50 @@ +class TankFleeingState < TankMotionState + MAX_FLEE_TIME = 15 * 1000 # 15 seconds + + def initialize(object, vision, gun) + super(object, vision) + @object = object + @vision = vision + @gun = gun + end + + def can_flee? + return true unless @started_fleeing + Gosu.milliseconds - @started_fleeing < MAX_FLEE_TIME + end + + def enter + @started_fleeing ||= Gosu.milliseconds + end + + def update + change_direction if should_change_direction? + drive + end + + def change_direction + closest_powerup = @vision.closest_powerup( + RepairPowerup, HealthPowerup) + if closest_powerup + angle = Utils.angle_between( + @object.x, @object.y, + closest_powerup.x, closest_powerup.y) + @object.physics.change_direction( + angle - angle % 45) + else + @object.physics.change_direction( + 180 + @gun.desired_gun_angle - + @gun.desired_gun_angle % 45) + end + @changed_direction_at = Gosu.milliseconds + @will_keep_direction_for = turn_time + end + + def drive_time + 10000 + end + + def turn_time + rand(300..600) + end +end diff --git a/Games/Debris_Dodge/lib/entities/components/ai/tank_motion_fsm.rb b/Games/Debris_Dodge/lib/entities/components/ai/tank_motion_fsm.rb new file mode 100644 index 0000000000..08fdbfc3ff --- /dev/null +++ b/Games/Debris_Dodge/lib/entities/components/ai/tank_motion_fsm.rb @@ -0,0 +1,102 @@ +class TankMotionFSM + STATE_CHANGE_DELAY = 500 + LOCATION_CHECK_DELAY = 5000 + + def initialize(object, vision, gun) + @object = object + @vision = vision + @gun = gun + @roaming_state = TankRoamingState.new(object, vision) + @fighting_state = TankFightingState.new(object, vision) + @fleeing_state = TankFleeingState.new(object, vision, gun) + @chasing_state = TankChasingState.new(object, vision, gun) + @stuck_state = TankStuckState.new(object, vision, gun) + @navigating_state = TankNavigatingState.new(object, vision) + set_state(@roaming_state) + end + + def on_collision(with) + @current_state.on_collision(with) + end + + def on_damage(amount) + if @current_state == @roaming_state + set_state(@fighting_state) + end + end + + def draw(viewport) + if $debug + @image && @image.draw( + @object.x - @image.width / 2, + @object.y + @object.graphics.height / 2 - + @image.height, 100) + end + end + + def update + choose_state + @current_state.update + end + + def set_state(state) + return unless state + return if state == @current_state + @last_state_change = Gosu.milliseconds + @current_state = state + state.enter + if $debug + @image = Gosu::Image.from_text( + $window, state.class.to_s, + Gosu.default_font_name, 18) + end + end + + def choose_state + unless @vision.can_go_forward? + unless @current_state == @stuck_state + set_state(@navigating_state) + end + end + # Keep unstucking itself for a while + change_delay = STATE_CHANGE_DELAY + if @current_state == @stuck_state + change_delay *= 5 + end + now = Gosu.milliseconds + return unless now - @last_state_change > change_delay + if @last_location_update.nil? + @last_location_update = now + @last_location = @object.location + end + if now - @last_location_update > LOCATION_CHECK_DELAY + unless @last_location.nil? || @current_state.waiting? + if Utils.distance_between(*@last_location, *@object.location) < 20 + set_state(@stuck_state) + @stuck_state.stuck_at = @object.location + return + end + end + @last_location_update = now + @last_location = @object.location + end + if @gun.target + if @object.health.health > 40 + if @gun.distance_to_target > BulletPhysics::MAX_DIST + new_state = @chasing_state + else + new_state = @fighting_state + end + else + if @fleeing_state.can_flee? + new_state = @fleeing_state + else + new_state = @fighting_state + end + end + else + new_state = @roaming_state + end + set_state(new_state) + end +end diff --git a/Games/Debris_Dodge/lib/entities/components/ai/tank_motion_state.rb b/Games/Debris_Dodge/lib/entities/components/ai/tank_motion_state.rb new file mode 100644 index 0000000000..e1e65cbeb1 --- /dev/null +++ b/Games/Debris_Dodge/lib/entities/components/ai/tank_motion_state.rb @@ -0,0 +1,84 @@ +class TankMotionState + def initialize(object, vision) + @object = object + @vision = vision + end + + def enter + # Override if necessary + end + + def change_direction + # Override + end + + def wait_time + # Override and return a number + end + + def drive_time + # Override and return a number + end + + def turn_time + # Override and return a number + end + + def update + # Override + end + + def wait + @sub_state = :waiting + @started_waiting = Gosu.milliseconds + @will_wait_for = wait_time + @object.throttle_down = false + end + + def waiting? + @sub_state == :waiting + end + + def drive + @sub_state = :driving + @started_driving = Gosu.milliseconds + @will_drive_for = drive_time + @object.throttle_down = true + end + + def should_change_direction? + return true unless @vision.can_go_forward? + return true unless @changed_direction_at + Gosu.milliseconds - @changed_direction_at > + @will_keep_direction_for + end + + def substate_expired? + now = Gosu.milliseconds + case @sub_state + when :waiting + true if now - @started_waiting > @will_wait_for + when :driving + true if now - @started_driving > @will_drive_for + else + true + end + end + + def on_collision(with) + change = case rand(0..100) + when 0..30 + -90 + when 30..60 + 90 + when 60..70 + 135 + when 80..90 + -135 + else + 180 + end + @object.physics.change_direction( + @object.direction + change) + end +end diff --git a/Games/Debris_Dodge/lib/entities/components/ai/tank_navigating_state.rb b/Games/Debris_Dodge/lib/entities/components/ai/tank_navigating_state.rb new file mode 100644 index 0000000000..8e888747e7 --- /dev/null +++ b/Games/Debris_Dodge/lib/entities/components/ai/tank_navigating_state.rb @@ -0,0 +1,34 @@ +class TankNavigatingState < TankMotionState + def initialize(object, vision) + @object = object + @vision = vision + end + + def update + change_direction if should_change_direction? + drive + end + + def change_direction + closest_free_path = @vision.closest_free_path + if closest_free_path + @object.physics.change_direction( + Utils.angle_between( + @object.x, @object.y, *closest_free_path)) + end + @changed_direction_at = Gosu.milliseconds + @will_keep_direction_for = turn_time + end + + def wait_time + rand(10..100) + end + + def drive_time + rand(1000..2000) + end + + def turn_time + rand(300..1000) + end +end diff --git a/Games/Debris_Dodge/lib/entities/components/ai/tank_roaming_state.rb b/Games/Debris_Dodge/lib/entities/components/ai/tank_roaming_state.rb new file mode 100644 index 0000000000..1942f809f9 --- /dev/null +++ b/Games/Debris_Dodge/lib/entities/components/ai/tank_roaming_state.rb @@ -0,0 +1,83 @@ +class TankRoamingState < TankMotionState + def initialize(object, vision) + super + @object = object + @vision = vision + end + + def update + change_direction if should_change_direction? + if substate_expired? + rand > 0.2 ? drive : wait + end + end + + def required_powerups + required = [] + health = @object.health.health + if @object.fire_rate_modifier < 2 && health > 50 + required << FireRatePowerup + end + if @object.speed_modifier < 1.5 && health > 50 + required << TankSpeedPowerup + end + if health < 100 + required << RepairPowerup + end + if health < 190 + required << HealthPowerup + end + required + end + + def change_direction + closest_powerup = @vision.closest_powerup( + *required_powerups) + if closest_powerup + @seeking_powerup = true + angle = Utils.angle_between( + @object.x, @object.y, + closest_powerup.x, closest_powerup.y) + @object.physics.change_direction( + angle - angle % 45) + # Go away from inaccessable powerup + unless @vision.can_go_forward? + @seeking_powerup = false + @object.physics.change_direction( + @object.direction + 180) + end + else + @seeking_powerup = false + change = case rand(0..100) + when 0..30 + -45 + when 30..60 + 45 + when 60..80 + 90 + when 80..100 + -90 + end + @object.physics.change_direction( + @object.direction + change) + end + @changed_direction_at = Gosu.milliseconds + @will_keep_direction_for = turn_time + end + + def wait_time + rand(50..400) + end + + def drive_time + rand(1000..3000) + end + + def turn_time + if @seeking_powerup + rand(100..300) + else + rand(1000..3000) + end + end +end diff --git a/Games/Debris_Dodge/lib/entities/components/ai/tank_stuck_state.rb b/Games/Debris_Dodge/lib/entities/components/ai/tank_stuck_state.rb new file mode 100644 index 0000000000..58c4ccfc15 --- /dev/null +++ b/Games/Debris_Dodge/lib/entities/components/ai/tank_stuck_state.rb @@ -0,0 +1,45 @@ +class TankStuckState < TankMotionState + attr_accessor :stuck_at + def initialize(object, vision, gun) + super(object, vision) + @object = object + @vision = vision + @gun = gun + end + + def update + change_direction if should_change_direction? + drive + end + + def change_direction + closest_free_path = @vision.closest_free_path_away_from( + @stuck_at) + if closest_free_path + @object.physics.change_direction( + Utils.angle_between( + @object.x, @object.y, *closest_free_path)) + else + if @object.health.health > 50 && rand > 0.9 + @object.shoot(*Utils.point_at_distance( + *@object.location, + @object.gun_angle, + 150)) + end + end + @changed_direction_at = Gosu.milliseconds + @will_keep_direction_for = turn_time + end + + def wait_time + rand(10..100) + end + + def drive_time + rand(1000..2000) + end + + def turn_time + rand(1000..2000) + end +end diff --git a/Games/Debris_Dodge/lib/entities/components/ai/vision.rb b/Games/Debris_Dodge/lib/entities/components/ai/vision.rb new file mode 100644 index 0000000000..cd6b9a535a --- /dev/null +++ b/Games/Debris_Dodge/lib/entities/components/ai/vision.rb @@ -0,0 +1,109 @@ +class AiVision + CACHE_TIMEOUT = 500 + POWERUP_CACHE_TIMEOUT = 50 + attr_reader :in_sight + + def initialize(viewer, object_pool, distance) + @viewer = viewer + @object_pool = object_pool + @distance = distance + end + + def can_go_forward? + in_front = Utils.point_at_distance( + *@viewer.location, @viewer.direction, 40) + @object_pool.map.can_move_to?(*in_front) && + @object_pool.nearby_point(*in_front, 40, @viewer) + .reject { |o| o.is_a? Powerup }.empty? + end + + def update + @in_sight = @object_pool.nearby(@viewer, @distance) + end + + def closest_free_path(away_from = nil) + paths = [] + 5.times do |i| + if paths.any? + return farthest_from(paths, away_from) + end + radius = 55 - i * 5 + range_x = range_y = [-radius, 0, radius] + range_x.shuffle.each do |x| + range_y.shuffle.each do |y| + x = @viewer.x + x + y = @viewer.y + y + if @object_pool.map.can_move_to?(x, y) && + @object_pool.nearby_point(x, y, radius, @viewer) + .reject { |o| o.is_a? Powerup }.empty? + if away_from + paths << [x, y] + else + return [x, y] + end + end + end + end + end + false + end + + alias :closest_free_path_away_from :closest_free_path + + def closest_tank + now = Gosu.milliseconds + @closest_tank = nil + if now - (@cache_updated_at ||= 0) > CACHE_TIMEOUT + @closest_tank = nil + @cache_updated_at = now + end + @closest_tank ||= find_closest_tank + end + + def closest_powerup(*suitable) + now = Gosu.milliseconds + @closest_powerup = nil + if now - (@powerup_cache_updated_at ||= 0) > POWERUP_CACHE_TIMEOUT + @closest_powerup = nil + @powerup_cache_updated_at = now + end + @closest_powerup ||= find_closest_powerup(*suitable) + end + + private + + def farthest_from(paths, away_from) + paths.sort do |p1, p2| + Utils.distance_between(*p1, *away_from) <=> + Utils.distance_between(*p2, *away_from) + end.first + end + + def find_closest_powerup(*suitable) + if suitable.empty? + suitable = [FireRatePowerup, + HealthPowerup, + RepairPowerup, + TankSpeedPowerup] + end + @in_sight.select do |o| + suitable.include?(o.class) + end.sort do |a, b| + x, y = @viewer.x, @viewer.y + d1 = Utils.distance_between(x, y, a.x, a.y) + d2 = Utils.distance_between(x, y, b.x, b.y) + d1 <=> d2 + end.first + end + + def find_closest_tank + @in_sight.select do |o| + o.class == Tank && !o.health.dead? + end.sort do |a, b| + x, y = @viewer.x, @viewer.y + d1 = Utils.distance_between(x, y, a.x, a.y) + d2 = Utils.distance_between(x, y, b.x, b.y) + d1 <=> d2 + end.first + end +end diff --git a/Games/Debris_Dodge/lib/entities/components/ai_input.rb b/Games/Debris_Dodge/lib/entities/components/ai_input.rb new file mode 100644 index 0000000000..86671b7885 --- /dev/null +++ b/Games/Debris_Dodge/lib/entities/components/ai_input.rb @@ -0,0 +1,70 @@ +class AiInput < Component + # Dark red + NAME_COLOR = Gosu::Color.argb(0xeeb10000) + UPDATE_RATE = 10 # ms + attr_reader :name + attr_reader :stats + + def initialize(name, object_pool) + super(nil) + @object_pool = object_pool + @stats = Stats.new(name) + @name = name + @last_update = Gosu.milliseconds + end + + def control(obj) + self.object = obj + object.components << self + @vision = AiVision.new(obj, @object_pool, + rand(700..1200)) + @gun = AiGun.new(obj, @vision) + @motion = TankMotionFSM.new(obj, @vision, @gun) + end + + def on_collision(with) + return if object.health.dead? + @motion.on_collision(with) + end + + def on_damage(amount) + @motion.on_damage(amount) + @stats.add_damage(amount) + end + + def update + return respawn if object.health.dead? + @gun.adjust_angle + now = Gosu.milliseconds + return if now - @last_update < UPDATE_RATE + @last_update = now + @vision.update + @gun.update + @motion.update + end + + def draw(viewport) + @motion.draw(viewport) + @gun.draw(viewport) + @name_image ||= Gosu::Image.from_text( + @name, 20, font: Gosu.default_font_name) + @name_image.draw( + x - @name_image.width / 2 - 1, + y + object.graphics.height / 2, 100, + 1, 1, Gosu::Color::WHITE) + @name_image.draw( + x - @name_image.width / 2, + y + object.graphics.height / 2, 100, + 1, 1, NAME_COLOR) + end + + private + + def respawn + if object.health.should_respawn? + object.health.restore + object.move(*@object_pool.map.spawn_point) + PlayerSounds.respawn(object, @object_pool.camera) + end + end +end diff --git a/Games/Debris_Dodge/lib/entities/components/box_graphics.rb b/Games/Debris_Dodge/lib/entities/components/box_graphics.rb new file mode 100644 index 0000000000..e14a2eef79 --- /dev/null +++ b/Games/Debris_Dodge/lib/entities/components/box_graphics.rb @@ -0,0 +1,39 @@ +class BoxGraphics < Component + def initialize(object) + super(object) + load_sprite + end + + def draw(viewport) + @box.draw_rot(x, y, 0, object.angle) + Utils.mark_corners(object.box) if $debug + end + + def height + @box.height + end + + def width + @box.width + end + + private + + def load_sprite + frame = boxes.frame_list.sample + @box = boxes.frame(frame) + end + + def center_x + @center_x ||= x - width / 2 + end + + def center_y + @center_y ||= y - height / 2 + end + + def boxes + @@boxes ||= Gosu::TexturePacker.load_json( + Utils.media_path('boxes_barrels.json')) + end +end diff --git a/Games/Debris_Dodge/lib/entities/components/bullet_graphics.rb b/Games/Debris_Dodge/lib/entities/components/bullet_graphics.rb new file mode 100644 index 0000000000..1a0d2cc54d --- /dev/null +++ b/Games/Debris_Dodge/lib/entities/components/bullet_graphics.rb @@ -0,0 +1,13 @@ +class BulletGraphics < Component + def draw(viewport) + image.draw(x - 8, y - 8, 1) + Utils.mark_corners(object.box) if $debug + end + + private + + def image + @@bullet ||= Gosu::Image.new( + Utils.media_path('bullet.png'), false) + end +end diff --git a/Games/Debris_Dodge/lib/entities/components/bullet_physics.rb b/Games/Debris_Dodge/lib/entities/components/bullet_physics.rb new file mode 100644 index 0000000000..71d399bfff --- /dev/null +++ b/Games/Debris_Dodge/lib/entities/components/bullet_physics.rb @@ -0,0 +1,65 @@ +class BulletPhysics < Component + START_DIST = 20 + MAX_DIST = 500 + + def initialize(game_object, object_pool) + super(game_object) + x, y = point_at_distance(START_DIST) + object.move(x, y) + @object_pool = object_pool + if trajectory_length > MAX_DIST + object.target_x, object.target_y = point_at_distance(MAX_DIST) + end + end + + def update + fly_speed = Utils.adjust_speed(object.speed) + now = Gosu.milliseconds + @last_update ||= object.fired_at + fly_distance = (now - @last_update) * 0.001 * fly_speed + object.move(*point_at_distance(fly_distance)) + @last_update = now + check_hit + object.explode if arrived? + end + + def trajectory_length + Utils.distance_between(object.target_x, object.target_y, x, y) + end + + def point_at_distance(distance) + if distance > trajectory_length + return [object.target_x, object.target_y] + end + distance_factor = distance.to_f / trajectory_length + p_x = x + (object.target_x - x) * distance_factor + p_y = y + (object.target_y - y) * distance_factor + [p_x, p_y] + end + + private + + def check_hit + @object_pool.nearby(object, 50).each do |obj| + next if obj == object.source # Don't hit source tank + if obj.class == Tree + if Utils.distance_between(x, y, obj.x, obj.y) < 10 + return do_hit(obj) if obj.respond_to?(:health) + end + elsif Utils.point_in_poly(x, y, *obj.box) + # Direct hit - extra damage + return do_hit(obj) if obj.respond_to?(:health) + end + end + end + + def do_hit(obj) + obj.health.inflict_damage(20, object.source) + object.target_x = x + object.target_y = y + end + + def arrived? + x == object.target_x && y == object.target_y + end +end diff --git a/Games/Debris_Dodge/lib/entities/components/bullet_sounds.rb b/Games/Debris_Dodge/lib/entities/components/bullet_sounds.rb new file mode 100644 index 0000000000..a79ea40f00 --- /dev/null +++ b/Games/Debris_Dodge/lib/entities/components/bullet_sounds.rb @@ -0,0 +1,15 @@ +class BulletSounds + class << self + def play(object, camera) + volume, pan = Utils.volume_and_pan(object, camera) + sound.play(object.object_id, pan, volume) + end + + private + + def sound + @@sound ||= StereoSample.new( + $window, Utils.media_path('fire.ogg')) + end + end +end diff --git a/Games/Debris_Dodge/lib/entities/components/component.rb b/Games/Debris_Dodge/lib/entities/components/component.rb new file mode 100644 index 0000000000..83e20e8833 --- /dev/null +++ b/Games/Debris_Dodge/lib/entities/components/component.rb @@ -0,0 +1,32 @@ +class Component + attr_reader :object # better performance + + def initialize(game_object = nil) + self.object = game_object + end + + def update + # override + end + + def draw(viewport) + # override + end + + protected + + def object=(obj) + if obj + @object = obj + obj.components << self + end + end + + def x + @object.x + end + + def y + @object.y + end +end diff --git a/Games/Debris_Dodge/lib/entities/components/damage_graphics.rb b/Games/Debris_Dodge/lib/entities/components/damage_graphics.rb new file mode 100644 index 0000000000..1c9ca84f91 --- /dev/null +++ b/Games/Debris_Dodge/lib/entities/components/damage_graphics.rb @@ -0,0 +1,21 @@ +class DamageGraphics < Component + def initialize(object_pool) + super + @image = images.sample + @angle = rand(0..360) + end + + def draw(viewport) + @image.draw_rot(x, y, 0, @angle) + end + + private + + def images + @@images ||= (1..4).map do |i| + Gosu::Image.new( + Utils.media_path("damage#{i}.png"), false + ) + end + end +end diff --git a/Games/Debris_Dodge/lib/entities/components/explosion_graphics.rb b/Games/Debris_Dodge/lib/entities/components/explosion_graphics.rb new file mode 100644 index 0000000000..efbff0cfc6 --- /dev/null +++ b/Games/Debris_Dodge/lib/entities/components/explosion_graphics.rb @@ -0,0 +1,43 @@ +class ExplosionGraphics < Component + FRAME_DELAY = 16.66 # ms + + def initialize(game_object) + super + @current_frame = 0 + end + + def draw(viewport) + image = current_frame + image.draw( + x - image.width / 2 + 3, + y - image.height / 2 - 35, + 20) + end + + def update + now = Gosu.milliseconds + delta = now - (@last_frame ||= now) + if delta > FRAME_DELAY + @last_frame = now + end + @current_frame += (delta / FRAME_DELAY).floor + object.mark_for_removal if done? + end + + private + + def current_frame + animation[@current_frame % animation.size] + end + + def done? + @done ||= @current_frame >= animation.size + end + + def animation + @@animation ||= + Gosu::Image.load_tiles( + $window, Utils.media_path('explosion.png'), + 128, 128, false) + end +end diff --git a/Games/Debris_Dodge/lib/entities/components/explosion_sounds.rb b/Games/Debris_Dodge/lib/entities/components/explosion_sounds.rb new file mode 100644 index 0000000000..871fa58b2c --- /dev/null +++ b/Games/Debris_Dodge/lib/entities/components/explosion_sounds.rb @@ -0,0 +1,16 @@ +class ExplosionSounds + class << self + def play(object, camera) + volume, pan = Utils.volume_and_pan(object, camera) + sound.play(object.object_id, pan, volume) + end + + private + + def sound + @@sound ||= StereoSample.new( + $window, Utils.media_path('explosion.ogg')) + end + end +end + diff --git a/Games/Debris_Dodge/lib/entities/components/health.rb b/Games/Debris_Dodge/lib/entities/components/health.rb new file mode 100644 index 0000000000..a116742b2e --- /dev/null +++ b/Games/Debris_Dodge/lib/entities/components/health.rb @@ -0,0 +1,87 @@ +class Health < Component + attr_accessor :health + + def initialize(object, object_pool, health, explodes) + super(object) + @explodes = explodes + @object_pool = object_pool + @initial_health = @health = health + @health_updated = true + end + + def restore + @health = @initial_health + @health_updated = true + end + + def increase(amount) + @health = [@health + 25, @initial_health * 2].min + @health_updated = true + end + + def damaged? + @health < @initial_health + end + + def dead? + @health < 1 + end + + def update + update_image + end + + def inflict_damage(amount, cause) + if @health > 0 + @health_updated = true + if object.respond_to?(:input) + object.input.stats.add_damage(amount) + # Don't count damage to trees and boxes + if cause.respond_to?(:input) && cause != object + cause.input.stats.add_damage_dealt(amount) + end + end + @health = [@health - amount.to_i, 0].max + after_death(cause) if dead? + end + end + + def draw(viewport) + return unless draw? + @image && @image.draw( + x - @image.width / 2, + y - object.graphics.height / 2 - + @image.height, 100) + end + + protected + + def draw? + $debug + end + + def update_image + return unless draw? + if @health_updated + text = @health.to_s + font_size = 18 + @image = Gosu::Image.from_text( + text, + font_size, font: Gosu.default_font_name) + @health_updated = false + end + end + + def after_death(cause) + if @explodes + Thread.new do + sleep(rand(0.1..0.3)) + Explosion.new(@object_pool, x, y, cause) + sleep 0.3 + object.mark_for_removal + end + else + object.mark_for_removal + end + end +end diff --git a/Games/Debris_Dodge/lib/entities/components/player_input.rb b/Games/Debris_Dodge/lib/entities/components/player_input.rb new file mode 100644 index 0000000000..471838da1f --- /dev/null +++ b/Games/Debris_Dodge/lib/entities/components/player_input.rb @@ -0,0 +1,100 @@ +class PlayerInput < Component + # Dark green + NAME_COLOR = Gosu::Color.argb(0xee084408) + attr_reader :stats + + def initialize(name, camera, object_pool) + super(nil) + @name = name + @stats = Stats.new(name) + @camera = camera + @object_pool = object_pool + end + + def control(obj) + self.object = obj + obj.components << self + end + + def on_collision(with) + end + + def on_damage(amount) + @stats.add_damage(amount) + end + + def update + return respawn if object.health.dead? + d_x, d_y = @camera.target_delta_on_screen + atan = Math.atan2(($window.width / 2) - d_x - $window.mouse_x, + ($window.height / 2) - d_y - $window.mouse_y) + object.gun_angle = -atan * 180 / Math::PI + motion_buttons = [Gosu::KbW, Gosu::KbS, Gosu::KbA, Gosu::KbD] + + if any_button_down?(*motion_buttons) + object.throttle_down = true + object.physics.change_direction( + change_angle(object.direction, *motion_buttons)) + else + object.throttle_down = false + end + + if Utils.button_down?(Gosu::MsLeft) + object.shoot(*@camera.mouse_coords) + end + end + + def draw(viewport) + @name_image ||= Gosu::Image.from_text( + @name, 20, font: Gosu.default_font_name) + @name_image.draw( + x - @name_image.width / 2 - 1, + y + object.graphics.height / 2, 100, + 1, 1, Gosu::Color::WHITE) + @name_image.draw( + x - @name_image.width / 2, + y + object.graphics.height / 2, 100, + 1, 1, NAME_COLOR) + end + + private + + def respawn + if object.health.should_respawn? + object.health.restore + object.move(*@object_pool.map.spawn_point) + @camera.x, @camera.y = x, y + PlayerSounds.respawn(object, @camera) + end + end + + def any_button_down?(*buttons) + buttons.each do |b| + return true if Utils.button_down?(b) + end + false + end + + def change_angle(previous_angle, up, down, right, left) + if Utils.button_down?(up) + angle = 0.0 + angle += 45.0 if Utils.button_down?(left) + angle -= 45.0 if Utils.button_down?(right) + elsif Utils.button_down?(down) + angle = 180.0 + angle -= 45.0 if Utils.button_down?(left) + angle += 45.0 if Utils.button_down?(right) + elsif Utils.button_down?(left) + angle = 90.0 + angle += 45.0 if Utils.button_down?(up) + angle -= 45.0 if Utils.button_down?(down) + elsif Utils.button_down?(right) + angle = 270.0 + angle -= 45.0 if Utils.button_down?(up) + angle += 45.0 if Utils.button_down?(down) + end + angle = (angle + 360) % 360 if angle && angle < 0 + (angle || previous_angle) + end + +end diff --git a/Games/Debris_Dodge/lib/entities/components/player_sounds.rb b/Games/Debris_Dodge/lib/entities/components/player_sounds.rb new file mode 100644 index 0000000000..3c5d17bd3b --- /dev/null +++ b/Games/Debris_Dodge/lib/entities/components/player_sounds.rb @@ -0,0 +1,16 @@ +class PlayerSounds + class << self + def respawn(object, camera) + volume, pan = Utils.volume_and_pan(object, camera) + respawn_sound.play(object.object_id, pan, volume * 0.5) + end + + private + + def respawn_sound + @@respawn ||= StereoSample.new( + $window, Utils.media_path('respawn.wav')) + end + end +end + diff --git a/Games/Debris_Dodge/lib/entities/components/powerup_graphics.rb b/Games/Debris_Dodge/lib/entities/components/powerup_graphics.rb new file mode 100644 index 0000000000..808a2262ca --- /dev/null +++ b/Games/Debris_Dodge/lib/entities/components/powerup_graphics.rb @@ -0,0 +1,22 @@ +class PowerupGraphics < Component + def initialize(object, type) + super(object) + @type = type + end + + def draw(viewport) + image.draw(x - 12, y - 12, 1) + Utils.mark_corners(object.box) if $debug + end + + private + + def image + @image ||= images.frame("#{@type}.png") + end + + def images + @@images ||= Gosu::TexturePacker.load_json( + Utils.media_path('pickups.json')) + end +end diff --git a/Games/Debris_Dodge/lib/entities/components/powerup_sounds.rb b/Games/Debris_Dodge/lib/entities/components/powerup_sounds.rb new file mode 100644 index 0000000000..509272247a --- /dev/null +++ b/Games/Debris_Dodge/lib/entities/components/powerup_sounds.rb @@ -0,0 +1,15 @@ +class PowerupSounds + class << self + def play(object, camera) + volume, pan = Utils.volume_and_pan(object, camera) + sound.play(object.object_id, pan, volume) + end + + private + + def sound + @@sound ||= StereoSample.new( + $window, Utils.media_path('powerup.ogg')) + end + end +end diff --git a/Games/Debris_Dodge/lib/entities/components/tank_graphics.rb b/Games/Debris_Dodge/lib/entities/components/tank_graphics.rb new file mode 100644 index 0000000000..09ed2ceacf --- /dev/null +++ b/Games/Debris_Dodge/lib/entities/components/tank_graphics.rb @@ -0,0 +1,46 @@ +class TankGraphics < Component + def initialize(game_object) + super(game_object) + @body_normal = units.frame('tank1_body.png') + @shadow_normal = units.frame('tank1_body_shadow.png') + @gun_normal = units.frame('tank1_dualgun.png') + @body_dead = units.frame('tank1_body_destroyed.png') + @shadow_dead = units.frame('tank1_body_destroyed_shadow.png') + @gun_dead = nil + update + end + + def update + if object && object.health.dead? + @body = @body_dead + @gun = @gun_dead + @shadow = @shadow_dead + else + @body = @body_normal + @gun = @gun_normal + @shadow = @shadow_normal + end + end + + def draw(viewport) + @shadow.draw_rot(x - 1, y - 1, 0, object.direction) + @body.draw_rot(x, y, 1, object.direction) + @gun.draw_rot(x, y, 2, object.gun_angle) if @gun + Utils.mark_corners(object.box) if $debug + end + + def width + @body.width + end + + def height + @body.height + end + + private + + def units + @@units = Gosu::TexturePacker.load_json( + Utils.media_path('ground_units.json'), :precise) + end +end diff --git a/Games/Debris_Dodge/lib/entities/components/tank_health.rb b/Games/Debris_Dodge/lib/entities/components/tank_health.rb new file mode 100644 index 0000000000..4da7fa8e46 --- /dev/null +++ b/Games/Debris_Dodge/lib/entities/components/tank_health.rb @@ -0,0 +1,32 @@ +class TankHealth < Health + RESPAWN_DELAY = 5000 + attr_accessor :health + + def initialize(object, object_pool) + super(object, object_pool, 100, true) + end + + def should_respawn? + if @death_time + Gosu.milliseconds - @death_time > RESPAWN_DELAY + end + end + + protected + + def draw? + true + end + + def after_death(cause) + @death_time = Gosu.milliseconds + object.reset_modifiers + object.input.stats.add_death + kill = object != cause ? 1 : -1 + cause.input.stats.add_kill(kill) + Thread.new do + sleep(rand(0.1..0.3)) + Explosion.new(@object_pool, x, y, cause) + end + end +end diff --git a/Games/Debris_Dodge/lib/entities/components/tank_physics.rb b/Games/Debris_Dodge/lib/entities/components/tank_physics.rb new file mode 100644 index 0000000000..072a790585 --- /dev/null +++ b/Games/Debris_Dodge/lib/entities/components/tank_physics.rb @@ -0,0 +1,179 @@ +class TankPhysics < Component + attr_accessor :speed, :in_collision, :collides_with + + def initialize(game_object, object_pool) + super(game_object) + @object_pool = object_pool + @map = object_pool.map + @speed = 0.0 + end + + def can_move_to?(x, y) + old_x, old_y = object.x, object.y + object.move(x, y) + return false unless @map.can_move_to?(x, y) + @object_pool.nearby(object, 100).each do |obj| + next if obj.class == Bullet && obj.source == object + if collides_with_poly?(obj.box) + if obj.is_a? Powerup + obj.on_collision(object) + else + @collides_with = obj + # Allow to get unstuck + old_distance = Utils.distance_between( + obj.x, obj.y, old_x, old_y) + new_distance = Utils.distance_between( + obj.x, obj.y, x, y) + return false if new_distance < old_distance + end + else + @collides_with = nil + end + end + true + ensure + object.move(old_x, old_y) + end + + def change_direction(new_direction) + change = (new_direction - object.direction + 360) % 360 + change = 360 - change if change > 180 + if change > 90 + @speed = 0 + elsif change > 45 + @speed *= 0.33 + elsif change > 0 + @speed *= 0.66 + end + object.direction = new_direction % 360 + end + + def moving? + @speed > 0 + end + + def box_height + @box_height ||= object.graphics.height + end + + def box_width + @box_width ||= object.graphics.width + end + + # Tank box looks like H. Vertices: + # 1 2 5 6 + # 3 4 + # + # 10 9 + # 12 11 8 7 + def box + w = box_width / 2 - 1 + h = box_height / 2 - 1 + tw = 8 # track width + fd = 8 # front depth + rd = 6 # rear depth + Utils.rotate(object.direction, x, y, + x + w, y + h, #1 + x + w - tw, y + h, #2 + x + w - tw, y + h - fd, #3 + + x - w + tw, y + h - fd, #4 + x - w + tw, y + h, #5 + x - w, y + h, #6 + + x - w, y - h, #7 + x - w + tw, y - h, #8 + x - w + tw, y - h + rd, #9 + + x + w - tw, y - h + rd, #10 + x + w - tw, y - h, #11 + x + w, y - h, #12 + ) + end + + def update + if object.throttle_down && !object.health.dead? + accelerate + else + decelerate + end + if @speed > 0 + new_x, new_y = x, y + speed = apply_movement_penalty(@speed) + shift = Utils.adjust_speed(speed) * object.speed_modifier + case @object.direction.to_i + when 0 + new_y -= shift + when 45 + new_x += shift + new_y -= shift + when 90 + new_x += shift + when 135 + new_x += shift + new_y += shift + when 180 + new_y += shift + when 225 + new_y += shift + new_x -= shift + when 270 + new_x -= shift + when 315 + new_x -= shift + new_y -= shift + end + if can_move_to?(new_x, new_y) + object.move(new_x, new_y) + @in_collision = false + else + object.on_collision(@collides_with) + @speed = 0.0 + @in_collision = true + end + end + end + + private + + def apply_movement_penalty(speed) + speed * (1.0 - @map.movement_penalty(x, y)) + end + + def accelerate + @speed += 0.08 if @speed < 5 + end + + def decelerate + if @speed > 0 + @speed = [@speed - 0.5, 0].max + elsif @speed < 0 + @speed = [@speed + 0.5, 0].min + end + damp_speed + end + + def damp_speed + @speed = 0 if @speed < 0.01 + end + + def collides_with_poly?(poly) + if poly + if poly.size == 2 + px, py = poly + return Utils.point_in_poly(px, py, *box) + end + poly.each_slice(2) do |x, y| + return true if Utils.point_in_poly(x, y, *box) + end + box.each_slice(2) do |x, y| + return true if Utils.point_in_poly(x, y, *poly) + end + end + false + end + + def collides_with_point?(x, y) + Utils.point_in_poly(x, y, box) + end +end diff --git a/Games/Debris_Dodge/lib/entities/components/tank_sounds.rb b/Games/Debris_Dodge/lib/entities/components/tank_sounds.rb new file mode 100644 index 0000000000..dfeb6a7978 --- /dev/null +++ b/Games/Debris_Dodge/lib/entities/components/tank_sounds.rb @@ -0,0 +1,43 @@ +class TankSounds < Component + def initialize(object, object_pool) + super(object) + @object_pool = object_pool + end + + def update + id = object.object_id + if object.physics.moving? + move_volume = Utils.volume( + object, @object_pool.camera) + pan = Utils.pan(object, @object_pool.camera) + if driving_sound.paused?(id) + driving_sound.resume(id) + elsif driving_sound.stopped?(id) + driving_sound.play(id, pan, 0.5, 1, true) + end + driving_sound.volume_and_pan(id, move_volume * 0.5, pan) + else + if driving_sound.playing?(id) + driving_sound.pause(id) + end + end + end + + def collide + vol, pan = Utils.volume_and_pan( + object, @object_pool.camera) + crash_sound.play(self.object_id, pan, vol, 1, false) + end + + private + + def driving_sound + @@driving_sound ||= StereoSample.new( + $window, Utils.media_path('tank_driving.ogg')) + end + + def crash_sound + @@crash_sound ||= StereoSample.new( + $window, Utils.media_path('metal_interaction2.wav')) + end +end diff --git a/Games/Debris_Dodge/lib/entities/components/tree_graphics.rb b/Games/Debris_Dodge/lib/entities/components/tree_graphics.rb new file mode 100644 index 0000000000..9be245255a --- /dev/null +++ b/Games/Debris_Dodge/lib/entities/components/tree_graphics.rb @@ -0,0 +1,69 @@ +class TreeGraphics < Component + SHAKE_TIME = 100 + SHAKE_COOLDOWN = 200 + SHAKE_DISTANCE = [2, 1, 0, -1, -2, -1, 0, 1, 0, -1, 0] + def initialize(object, seed) + super(object) + load_sprite(seed) + end + + def shake(direction) + now = Gosu.milliseconds + return if @shake_start && + now - @shake_start < SHAKE_TIME + SHAKE_COOLDOWN + @shake_start = now + @shake_direction = direction + @shaking = true + end + + def adjust_shake(x, y, shaking_for) + elapsed = [shaking_for, SHAKE_TIME].min / SHAKE_TIME.to_f + frame = ((SHAKE_DISTANCE.length - 1) * elapsed).floor + distance = SHAKE_DISTANCE[frame] + Utils.point_at_distance(x, y, @shake_direction, distance) + end + + def draw(viewport) + if @shaking + shaking_for = Gosu.milliseconds - @shake_start + shaking_x, shaking_y = adjust_shake( + center_x, center_y, shaking_for) + @tree.draw(shaking_x, shaking_y, 5) + if shaking_for >= SHAKE_TIME + @shaking = false + end + else + @tree.draw(center_x, center_y, 5) + end + Utils.mark_corners(object.box) if $debug + end + + def height + @tree.height + end + + def width + @tree.width + end + + private + + def load_sprite(seed) + frame_list = trees.frame_list + frame = frame_list[(frame_list.size * seed).round] + @tree = trees.frame(frame) + end + + def center_x + @center_x ||= x - @tree.width / 2 + end + + def center_y + @center_y ||= y - @tree.height / 2 + end + + def trees + @@trees ||= Gosu::TexturePacker.load_json( + Utils.media_path('trees_packed.json')) + end +end diff --git a/Games/Debris_Dodge/lib/entities/damage.rb b/Games/Debris_Dodge/lib/entities/damage.rb new file mode 100644 index 0000000000..a501ae6ae7 --- /dev/null +++ b/Games/Debris_Dodge/lib/entities/damage.rb @@ -0,0 +1,26 @@ +class Damage < GameObject + MAX_INSTANCES = 300 + @@instances = [] + + def initialize(object_pool, x, y) + super + DamageGraphics.new(self) + track(self) + end + + def effect? + true + end + + private + + def track(instance) + if @@instances.size < MAX_INSTANCES + @@instances << instance + else + out = @@instances.shift + out.mark_for_removal + @@instances << instance + end + end +end diff --git a/Games/Debris_Dodge/lib/entities/explosion.rb b/Games/Debris_Dodge/lib/entities/explosion.rb new file mode 100644 index 0000000000..772c38351e --- /dev/null +++ b/Games/Debris_Dodge/lib/entities/explosion.rb @@ -0,0 +1,34 @@ +class Explosion < GameObject + + def initialize(object_pool, x, y, source) + super(object_pool, x, y) + @source = source + @object_pool = object_pool + if @object_pool.map.can_move_to?(x, y) + Damage.new(@object_pool, x, y) + end + ExplosionGraphics.new(self) + ExplosionSounds.play(self, object_pool.camera) + inflict_damage + end + + def effect? + true + end + + def mark_for_removal + super + end + + private + + def inflict_damage + object_pool.nearby(self, 100).each do |obj| + if obj.respond_to?(:health) + obj.health.inflict_damage( + Math.sqrt(3 * 100 - Utils.distance_between( + obj.x, obj.y, @x, @y)), @source) + end + end + end +end diff --git a/Games/Debris_Dodge/lib/entities/game_object.rb b/Games/Debris_Dodge/lib/entities/game_object.rb new file mode 100644 index 0000000000..05fa774bab --- /dev/null +++ b/Games/Debris_Dodge/lib/entities/game_object.rb @@ -0,0 +1,54 @@ +class GameObject + attr_reader :x, :y, :location, :components + def initialize(object_pool, x, y) + @x, @y = x, y + @location = [x, y] + @components = [] + @object_pool = object_pool + @object_pool.add(self) + end + + def move(new_x, new_y) + return if new_x == @x && new_y == @y + @object_pool.tree_remove(self) + @x = new_x + @y = new_y + @location = [new_x, new_y] + @object_pool.tree_insert(self) + end + + def update + @components.map(&:update) + end + + def draw(viewport) + @components.each { |c| c.draw(viewport) } + end + + def removable? + @removable + end + + def mark_for_removal + @removable = true + end + + def on_collision(object) + end + + def effect? + false + end + + def box + end + + def collide + end + + protected + + def object_pool + @object_pool + end +end diff --git a/Games/Debris_Dodge/lib/entities/hud.rb b/Games/Debris_Dodge/lib/entities/hud.rb new file mode 100644 index 0000000000..6f3f1965f2 --- /dev/null +++ b/Games/Debris_Dodge/lib/entities/hud.rb @@ -0,0 +1,79 @@ +class HUD + attr_accessor :active + def initialize(object_pool, tank) + @object_pool = object_pool + @tank = tank + @radar = Radar.new(@object_pool, tank) + end + + def player=(tank) + @tank = tank + @radar.target = tank + end + + def update + @radar.update + end + + def health_image + if @health.nil? || @tank.health.health != @health + @health = @tank.health.health + @health_image = Gosu::Image.from_text( + "Health: #{@health}", 20, font: Utils.main_font) + end + @health_image + end + + def stats_image + stats = @tank.input.stats + if @stats_image.nil? || stats.changed_at <= Gosu.milliseconds + @stats_image = Gosu::Image.from_text( + "Kills: #{stats.kills}", 20, font: Utils.main_font) + end + @stats_image + end + + def fire_rate_image + if @tank.fire_rate_modifier > 1 + if @fire_rate != @tank.fire_rate_modifier + @fire_rate = @tank.fire_rate_modifier + @fire_rate_image = Gosu::Image.from_text( + "Fire rate: #{@fire_rate.round(2)}X", + 20, font: Utils.main_font) + end + else + @fire_rate_image = nil + end + @fire_rate_image + end + + def speed_image + if @tank.speed_modifier > 1 + if @speed != @tank.speed_modifier + @speed = @tank.speed_modifier + @speed_image = Gosu::Image.from_text( + "Speed: #{@speed.round(2)}X", + 20, font: Utils.main_font) + end + else + @speed_image = nil + end + @speed_image + end + + def draw + if @active + @object_pool.camera.draw_crosshair + end + @radar.draw + offset = 20 + health_image.draw(20, offset, 1000) + stats_image.draw(20, offset += 30, 1000) + if fire_rate_image + fire_rate_image.draw(20, offset += 30, 1000) + end + if speed_image + speed_image.draw(20, offset += 30, 1000) + end + end +end diff --git a/Games/Debris_Dodge/lib/entities/map.rb b/Games/Debris_Dodge/lib/entities/map.rb new file mode 100644 index 0000000000..4a55676cbe --- /dev/null +++ b/Games/Debris_Dodge/lib/entities/map.rb @@ -0,0 +1,183 @@ +class Map + MAP_WIDTH = 30 + MAP_HEIGHT = 30 + TILE_SIZE = 128 + + def self.bounding_box + center = [MAP_WIDTH * TILE_SIZE / 2, + MAP_HEIGHT * TILE_SIZE / 2] + half_dimension = [MAP_WIDTH * TILE_SIZE, + MAP_HEIGHT * TILE_SIZE] + AxisAlignedBoundingBox.new(center, half_dimension) + end + + def initialize(object_pool) + load_tiles + @object_pool = object_pool + object_pool.map = self + @map = generate_map + generate_trees + generate_boxes + generate_powerups + end + + def spawn_points(max) + @spawn_points = (0..max).map do + find_spawn_point + end + @spawn_points_pointer = 0 + end + + def spawn_point + @spawn_points[(@spawn_points_pointer += 1) % @spawn_points.size] + end + + def can_move_to?(x, y) + tile = tile_at(x, y) + tile && tile != @water + end + + def movement_penalty(x, y) + tile = tile_at(x, y) + case tile + when @sand + 0.33 + else + 0 + end + end + + def draw(viewport) + viewport = viewport.map { |p| p / TILE_SIZE } + x0, x1, y0, y1 = viewport.map(&:to_i) + (x0-1..x1).each do |x| + (y0-1..y1).each do |y| + row = @map[x] + map_x = x * TILE_SIZE + map_y = y * TILE_SIZE + if row + tile = @map[x][y] + if tile + tile.draw(map_x, map_y, 0) + else + @water.draw(map_x, map_y, 0) + end + else + @water.draw(map_x, map_y, 0) + end + end + end + end + + private + + def tile_at(x, y) + t_x = ((x / TILE_SIZE) % TILE_SIZE).floor + t_y = ((y / TILE_SIZE) % TILE_SIZE).floor + row = @map[t_x] + row ? row[t_y] : @water + end + + def load_tiles + tiles = Gosu::Image.load_tiles( + $window, Utils.media_path('ground.png'), + 128, 128, true) + @sand = tiles[0] + @grass = tiles[8] + @water = Gosu::Image.new( + Utils.media_path('water.png'), tileable: true) + end + + def generate_map + noises = Perlin::Noise.new(2) + contrast = Perlin::Curve.contrast( + Perlin::Curve::CUBIC, 2) + map = {} + MAP_WIDTH.times do |x| + map[x] = {} + MAP_HEIGHT.times do |y| + n = noises[x * 0.1, y * 0.1] + n = contrast.call(n) + map[x][y] = choose_tile(n) + end + end + map + end + + def generate_trees + noises = Perlin::Noise.new(2) + contrast = Perlin::Curve.contrast( + Perlin::Curve::CUBIC, 2) + trees = 0 + target_trees = rand(1500..1500) + while trees < target_trees do + x = rand(0..MAP_WIDTH * TILE_SIZE) + y = rand(0..MAP_HEIGHT * TILE_SIZE) + n = noises[x * 0.001, y * 0.001] + n = contrast.call(n) + if tile_at(x, y) == @grass && n > 0.5 + Tree.new(@object_pool, x, y, n * 2 - 1) + trees += 1 + end + end + end + + def generate_boxes + boxes = 0 + target_boxes = rand(50..200) + while boxes < target_boxes do + x = rand(0..MAP_WIDTH * TILE_SIZE) + y = rand(0..MAP_HEIGHT * TILE_SIZE) + if tile_at(x, y) != @water + Box.new(@object_pool, x, y) + boxes += 1 + end + end + end + + def generate_powerups + pups = 0 + target_pups = rand(20..30) + while pups < target_pups do + x = rand(0..MAP_WIDTH * TILE_SIZE) + y = rand(0..MAP_HEIGHT * TILE_SIZE) + if tile_at(x, y) != @water && + @object_pool.nearby_point(x, y, 150).empty? + random_powerup.new(@object_pool, x, y) + pups += 1 + end + end + end + + def random_powerup + [HealthPowerup, + RepairPowerup, + FireRatePowerup, + TankSpeedPowerup].sample + end + + def choose_tile(val) + case val + when 0.0..0.3 # 30% chance + @water + when 0.3..0.5 # 20% chance, water edges + @sand + else # 50% chance + @grass + end + end + + private + + def find_spawn_point + while true + x = rand(0..MAP_WIDTH * TILE_SIZE) + y = rand(0..MAP_HEIGHT * TILE_SIZE) + if can_move_to?(x, y) && + @object_pool.nearby_point(x, y, 150).empty? + return [x, y] + end + end + end + +end diff --git a/Games/Debris_Dodge/lib/entities/object_pool.rb b/Games/Debris_Dodge/lib/entities/object_pool.rb new file mode 100644 index 0000000000..016a7db96b --- /dev/null +++ b/Games/Debris_Dodge/lib/entities/object_pool.rb @@ -0,0 +1,59 @@ +class ObjectPool + attr_accessor :map, :camera, :objects, :powerup_respawn_queue + + def size + @objects.size + end + + def initialize(box) + @tree = QuadTree.new(box) + @powerup_respawn_queue = PowerupRespawnQueue.new + @objects = [] + end + + def add(object) + @objects << object + @tree.insert(object) + end + + def tree_remove(object) + @tree.remove(object) + end + + def tree_insert(object) + @tree.insert(object) + end + + def update_all + @objects.each(&:update) + @objects.reject! do |o| + if o.removable? + @tree.remove(o) + true + end + end + @powerup_respawn_queue.respawn(self) + end + + def nearby_point(cx, cy, max_distance, object = nil) + hx, hy = cx + max_distance, cy + max_distance + # Fast, rough results + results = @tree.query_range( + AxisAlignedBoundingBox.new([cx, cy], [hx, hy])) + # Sift through to select fine-grained results + results.select do |o| + o != object && + Utils.distance_between( + o.x, o.y, cx, cy) <= max_distance + end + end + + def nearby(object, max_distance) + cx, cy = object.location + nearby_point(cx, cy, max_distance, object) + end + + def query_range(box) + @tree.query_range(box) + end +end diff --git a/Games/Debris_Dodge/lib/entities/powerups/fire_rate_powerup.rb b/Games/Debris_Dodge/lib/entities/powerups/fire_rate_powerup.rb new file mode 100644 index 0000000000..76cadb4d50 --- /dev/null +++ b/Games/Debris_Dodge/lib/entities/powerups/fire_rate_powerup.rb @@ -0,0 +1,14 @@ +class FireRatePowerup < Powerup + def pickup(object) + if object.class == Tank + if object.fire_rate_modifier < 2 + object.fire_rate_modifier += 0.25 + end + true + end + end + + def graphics + :straight_gun + end +end diff --git a/Games/Debris_Dodge/lib/entities/powerups/health_powerup.rb b/Games/Debris_Dodge/lib/entities/powerups/health_powerup.rb new file mode 100644 index 0000000000..c73cdbe9c3 --- /dev/null +++ b/Games/Debris_Dodge/lib/entities/powerups/health_powerup.rb @@ -0,0 +1,12 @@ +class HealthPowerup < Powerup + def pickup(object) + if object.class == Tank + object.health.increase(25) + true + end + end + + def graphics + :life_up + end +end diff --git a/Games/Debris_Dodge/lib/entities/powerups/powerup.rb b/Games/Debris_Dodge/lib/entities/powerups/powerup.rb new file mode 100644 index 0000000000..edd2305ff7 --- /dev/null +++ b/Games/Debris_Dodge/lib/entities/powerups/powerup.rb @@ -0,0 +1,35 @@ +class Powerup < GameObject + def initialize(object_pool, x, y) + super + PowerupGraphics.new(self, graphics) + end + + def box + [x - 8, y - 8, + x + 8, y - 8, + x + 8, y + 8, + x - 8, y + 8] + end + + def on_collision(object) + if pickup(object) + PowerupSounds.play(object, object_pool.camera) + remove + end + end + + def pickup(object) + # override and implement application + end + + def remove + object_pool.powerup_respawn_queue.enqueue( + respawn_delay, + self.class, x, y) + mark_for_removal + end + + def respawn_delay + 30 + end +end diff --git a/Games/Debris_Dodge/lib/entities/powerups/powerup_respawn_queue.rb b/Games/Debris_Dodge/lib/entities/powerups/powerup_respawn_queue.rb new file mode 100644 index 0000000000..b8f89d6691 --- /dev/null +++ b/Games/Debris_Dodge/lib/entities/powerups/powerup_respawn_queue.rb @@ -0,0 +1,23 @@ +class PowerupRespawnQueue + RESPAWN_DELAY = 1000 + def initialize + @respawn_queue = {} + @last_respawn = Gosu.milliseconds + end + + def enqueue(delay_seconds, type, x, y) + respawn_at = Gosu.milliseconds + delay_seconds * 1000 + @respawn_queue[respawn_at.to_i] = [type, x, y] + end + + def respawn(object_pool) + now = Gosu.milliseconds + return if now - @last_respawn < RESPAWN_DELAY + @respawn_queue.keys.each do |k| + next if k > now # not yet + type, x, y = @respawn_queue.delete(k) + type.new(object_pool, x, y) + end + @last_respawn = now + end +end diff --git a/Games/Debris_Dodge/lib/entities/powerups/repair_powerup.rb b/Games/Debris_Dodge/lib/entities/powerups/repair_powerup.rb new file mode 100644 index 0000000000..fc3136d8f7 --- /dev/null +++ b/Games/Debris_Dodge/lib/entities/powerups/repair_powerup.rb @@ -0,0 +1,14 @@ +class RepairPowerup < Powerup + def pickup(object) + if object.class == Tank + if object.health.health < 100 + object.health.restore + end + true + end + end + + def graphics + :repair + end +end diff --git a/Games/Debris_Dodge/lib/entities/powerups/tank_speed_powerup.rb b/Games/Debris_Dodge/lib/entities/powerups/tank_speed_powerup.rb new file mode 100644 index 0000000000..c3e2f917f6 --- /dev/null +++ b/Games/Debris_Dodge/lib/entities/powerups/tank_speed_powerup.rb @@ -0,0 +1,14 @@ +class TankSpeedPowerup < Powerup + def pickup(object) + if object.class == Tank + if object.speed_modifier < 1.5 + object.speed_modifier += 0.10 + end + true + end + end + + def graphics + :wingman + end +end diff --git a/Games/Debris_Dodge/lib/entities/radar.rb b/Games/Debris_Dodge/lib/entities/radar.rb new file mode 100644 index 0000000000..96d7018a10 --- /dev/null +++ b/Games/Debris_Dodge/lib/entities/radar.rb @@ -0,0 +1,62 @@ +class Radar + UPDATE_FREQUENCY = 1000 + WIDTH = 150 + HEIGHT = 100 + PADDING = 10 + # Black with 33% transparency + BACKGROUND = Gosu::Color.new(255 * 0.33, 0, 0, 0) + attr_accessor :target + + def initialize(object_pool, target) + @object_pool = object_pool + @target = target + @last_update = 0 + end + + def update + if Gosu.milliseconds - @last_update > UPDATE_FREQUENCY + @nearby = nil + end + @nearby ||= @object_pool.nearby(@target, 2000).select do |o| + o.class == Tank && !o.health.dead? + end + end + + def draw + x1, x2, y1, y2 = radar_coords + $window.draw_quad( + x1, y1, BACKGROUND, + x2, y1, BACKGROUND, + x2, y2, BACKGROUND, + x1, y2, BACKGROUND, + 200) + draw_tank(@target, Gosu::Color::GREEN) + @nearby && @nearby.each do |t| + draw_tank(t, Gosu::Color::RED) + end + end + + private + + def draw_tank(tank, color) + x1, x2, y1, y2 = radar_coords + tx = x1 + WIDTH / 2 + (tank.x - @target.x) / 20 + ty = y1 + HEIGHT / 2 + (tank.y - @target.y) / 20 + if (x1..x2).include?(tx) && (y1..y2).include?(ty) + $window.draw_quad( + tx - 2, ty - 2, color, + tx + 2, ty - 2, color, + tx + 2, ty + 2, color, + tx - 2, ty + 2, color, + 300) + end + end + + def radar_coords + x1 = $window.width - WIDTH - PADDING + x2 = $window.width - PADDING + y1 = $window.height - HEIGHT - PADDING + y2 = $window.height - PADDING + [x1, x2, y1, y2] + end +end diff --git a/Games/Debris_Dodge/lib/entities/score_display.rb b/Games/Debris_Dodge/lib/entities/score_display.rb new file mode 100644 index 0000000000..cca560d0f6 --- /dev/null +++ b/Games/Debris_Dodge/lib/entities/score_display.rb @@ -0,0 +1,35 @@ +class ScoreDisplay + def initialize(object_pool, font_size=30) + @font_size = font_size + tanks = object_pool.objects.select do |o| + o.class == Tank + end + stats = tanks.map(&:input).map(&:stats) + stats.sort! do |stat1, stat2| + stat2.kills <=> stat1.kills + end + create_stats_image(stats) + end + + def create_stats_image(stats) + text = stats.map do |stat| + "#{stat.kills}: #{stat.name} " + end.join("\n") + @stats_image = Gosu::Image.from_text( + $window, text, Utils.main_font, @font_size) + end + + def draw + @stats_image.draw( + $window.width / 2 - @stats_image.width / 2, + $window.height / 4 + 30, + 1000) + end + + def draw_top_right + @stats_image.draw( + $window.width - @stats_image.width - 20, + 20, + 1000) + end +end diff --git a/Games/Debris_Dodge/lib/entities/tank.rb b/Games/Debris_Dodge/lib/entities/tank.rb new file mode 100644 index 0000000000..3e0fbf685b --- /dev/null +++ b/Games/Debris_Dodge/lib/entities/tank.rb @@ -0,0 +1,64 @@ +class Tank < GameObject + SHOOT_DELAY = 500 + attr_accessor :throttle_down, :direction, + :gun_angle, :sounds, :physics, :graphics, :health, :input, + :fire_rate_modifier, :speed_modifier + + def initialize(object_pool, input) + x, y = object_pool.map.spawn_point + super(object_pool, x, y) + @input = input + @input.control(self) + @physics = TankPhysics.new(self, object_pool) + @sounds = TankSounds.new(self, object_pool) + @health = TankHealth.new(self, object_pool) + @graphics = TankGraphics.new(self) + @direction = rand(0..7) * 45 + @gun_angle = rand(0..360) + reset_modifiers + end + + def box + @physics.box + end + + def on_collision(object) + return unless object + # Avoid recursion + if object.class == Tank + # Inform AI about hit + object.input.on_collision(object) + else + # Call only on non-tanks to avoid recursion + object.on_collision(self) + end + # Bullets should not slow Tanks down + if object.class != Bullet + @sounds.collide if @physics.speed > 1 + end + end + + def shoot(target_x, target_y) + if can_shoot? + @last_shot = Gosu.milliseconds + Bullet.new(object_pool, @x, @y, target_x, target_y).fire( + self, 1500) + input.stats.add_shot + end + end + + def can_shoot? + Gosu.milliseconds - (@last_shot || 0) > + (SHOOT_DELAY / @fire_rate_modifier) + end + + def reset_modifiers + @fire_rate_modifier = 1 + @speed_modifier = 1 + end + + def to_s + "Tank [#{@health.health}@#{@x}:#{@y}@#{@physics.speed.round(2)}px/tick]#{@input.stats}" + end + +end diff --git a/Games/Debris_Dodge/lib/entities/tree.rb b/Games/Debris_Dodge/lib/entities/tree.rb new file mode 100644 index 0000000000..07635300d1 --- /dev/null +++ b/Games/Debris_Dodge/lib/entities/tree.rb @@ -0,0 +1,18 @@ +class Tree < GameObject + attr_reader :health, :graphics + + def initialize(object_pool, x, y, seed) + super(object_pool, x, y) + @graphics = TreeGraphics.new(self, seed) + @health = Health.new(self, object_pool, 30, false) + @angle = rand(-15..15) + end + + def on_collision(object) + @graphics.shake(object.direction) + end + + def box + [@x, @y] + end +end diff --git a/Games/Debris_Dodge/lib/game_states/demo_state.rb b/Games/Debris_Dodge/lib/game_states/demo_state.rb new file mode 100644 index 0000000000..13b9587661 --- /dev/null +++ b/Games/Debris_Dodge/lib/game_states/demo_state.rb @@ -0,0 +1,49 @@ +class DemoState < PlayState + attr_accessor :tank + + def enter + # Prevent reactivating HUD + end + + def update + super + @score_display = ScoreDisplay.new( + object_pool, 20) + end + + def draw + super + @score_display.draw_top_right + end + + def button_down(id) + super + if id == Gosu::KbSpace + target_tank = @tanks.reject do |t| + t == @camera.target + end.sample + switch_to_tank(target_tank) + end + end + + private + + def create_tanks(amount) + @map.spawn_points(amount * 3) + @tanks = [] + amount.times do |i| + @tanks << Tank.new(@object_pool, AiInput.new( + @names.random, @object_pool)) + end + target_tank = @tanks.sample + @hud = HUD.new(@object_pool, target_tank) + @hud.active = false + switch_to_tank(target_tank) + end + + def switch_to_tank(tank) + @camera.target = tank + @hud.player = tank + self.tank = tank + end +end diff --git a/Games/Debris_Dodge/lib/game_states/game_state.rb b/Games/Debris_Dodge/lib/game_states/game_state.rb new file mode 100644 index 0000000000..bb6f83eee0 --- /dev/null +++ b/Games/Debris_Dodge/lib/game_states/game_state.rb @@ -0,0 +1,27 @@ +class GameState + + def self.switch(new_state) + $window.state && $window.state.leave + $window.state = new_state + new_state.enter + end + + def enter + end + + def leave + end + + def draw + end + + def update + end + + def needs_redraw? + true + end + + def button_down(id) + end +end diff --git a/Games/Debris_Dodge/lib/game_states/menu_state.rb b/Games/Debris_Dodge/lib/game_states/menu_state.rb new file mode 100644 index 0000000000..294e7d4c06 --- /dev/null +++ b/Games/Debris_Dodge/lib/game_states/menu_state.rb @@ -0,0 +1,62 @@ +require 'singleton' +class MenuState < GameState + include Singleton + attr_accessor :play_state + + def initialize + @message = Gosu::Image.from_text( + "Tank Island", + 60, + font: Utils.title_font + ) + end + + def enter + music.play(true) + music.volume = 1 + end + + def leave + music.volume = 0 + music.stop + end + + def music + @@music ||= Gosu::Song.new( + Utils.media_path('menu_music.ogg')) + end + + def update + text = "Q: Quit\nN: New Game\nD: Demo" + text << "\nC: Continue" if @play_state + @info = Gosu::Image.from_text( + text, + 30, options = {font: Utils.main_font}) + end + + def draw + @message.draw( + $window.width / 2 - @message.width / 2, + $window.height / 2 - @message.height / 2, + 10) + @info.draw( + $window.width / 2 - @info.width / 2, + $window.height / 2 - @info.height / 2 + 100, + 10) + end + + def button_down(id) + $window.close if id == Gosu::KbQ + if id == Gosu::KbC && @play_state + GameState.switch(@play_state) + end + if id == Gosu::KbN + @play_state = PlayState.new + GameState.switch(@play_state) + end + if id == Gosu::KbD + @play_state = DemoState.new + GameState.switch(@play_state) + end + end +end diff --git a/Games/Debris_Dodge/lib/game_states/pause_state.rb b/Games/Debris_Dodge/lib/game_states/pause_state.rb new file mode 100644 index 0000000000..8a8078792d --- /dev/null +++ b/Games/Debris_Dodge/lib/game_states/pause_state.rb @@ -0,0 +1,61 @@ +require 'singleton' +class PauseState < GameState + include Singleton + attr_accessor :play_state + + def initialize + @message = Gosu::Image.from_text( + $window, "Game Paused", + Utils.title_font, 60) + end + + def enter + music.play(true) + music.volume = 1 + @score_display = ScoreDisplay.new(@play_state.object_pool) + @mouse_coords = [$window.mouse_x, $window.mouse_y] + end + + def leave + music.volume = 0 + music.stop + $window.mouse_x, $window.mouse_y = @mouse_coords + end + + def music + @@music ||= Gosu::Song.new( + $window, Utils.media_path('menu_music.ogg')) + end + + def draw + @play_state.draw + @message.draw( + $window.width / 2 - @message.width / 2, + $window.height / 4 - @message.height - 50, + 1000) + info.draw( + $window.width / 2 - info.width / 2, + $window.height / 4 - info.height, + 1000) + @score_display.draw + end + + def info + @info ||= Gosu::Image.from_text( + $window, 'Q: Quit to Main Menu', + Utils.main_font, 30) + end + + def button_down(id) + if id == Gosu::KbQ + MenuState.instance.play_state = @play_state + GameState.switch(MenuState.instance) + end + if id == Gosu::KbC && @play_state + GameState.switch(@play_state) + end + if id == Gosu::KbEscape + GameState.switch(@play_state) + end + end +end diff --git a/Games/Debris_Dodge/lib/game_states/play_state.rb b/Games/Debris_Dodge/lib/game_states/play_state.rb new file mode 100644 index 0000000000..89100befe5 --- /dev/null +++ b/Games/Debris_Dodge/lib/game_states/play_state.rb @@ -0,0 +1,119 @@ +class PlayState < GameState + attr_accessor :update_interval, :object_pool, :tank + + def initialize + # http://www.paulandstorm.com/wha/clown-names/ + @names = Names.new( + Utils.media_path('names.txt')) + @object_pool = ObjectPool.new(Map.bounding_box) + @map = Map.new(@object_pool) + @camera = Camera.new + @object_pool.camera = @camera + create_tanks(7) + end + + def update + StereoSample.cleanup + @object_pool.update_all + @camera.update + @hud.update + update_caption + end + + def draw + cam_x = @camera.x + cam_y = @camera.y + off_x = $window.width / 2 - cam_x + off_y = $window.height / 2 - cam_y + viewport = @camera.viewport + x1, x2, y1, y2 = viewport + box = AxisAlignedBoundingBox.new( + [x1 + (x2 - x1) / 2, y1 + (y2 - y1) / 2], + [x1 - Map::TILE_SIZE, y1 - Map::TILE_SIZE]) + $window.translate(off_x, off_y) do + zoom = @camera.zoom + $window.scale(zoom, zoom, cam_x, cam_y) do + @map.draw(viewport) + @object_pool.query_range(box).map do |o| + o.draw(viewport) + end + end + end + @hud.draw + end + + def button_down(id) + if id == Gosu::KbEscape + pause = PauseState.instance + pause.play_state = self + GameState.switch(pause) + end + if id == Gosu::KbT + t = Tank.new(@object_pool, + AiInput.new(@names.random, @object_pool)) + t.move(*@camera.mouse_coords) + end + if id == Gosu::KbF1 + $debug = !$debug + end + if id == Gosu::KbF2 + toggle_profiling + end + if id == Gosu::KbR + @tank.mark_for_removal + @tank = Tank.new(@object_pool, + PlayerInput.new('Player', @camera, @object_pool)) + @camera.target = @tank + @hud.player = @tank + end + end + + def leave + StereoSample.stop_all + if @profiling_now + toggle_profiling + end + @hud.active = false + end + + def enter + @hud.active = true + end + + private + + def create_tanks(amount) + @map.spawn_points(amount * 3) + @tank = Tank.new(@object_pool, + PlayerInput.new('Player', @camera, @object_pool)) + amount.times do |i| + Tank.new(@object_pool, AiInput.new( + @names.random, @object_pool)) + end + @camera.target = @tank + @hud = HUD.new(@object_pool, @tank) + end + + def toggle_profiling + require 'ruby-prof' unless defined?(RubyProf) + if @profiling_now + result = RubyProf.stop + printer = RubyProf::FlatPrinter.new(result) + printer.print(STDOUT, min_percent: 0.01) + @profiling_now = false + else + RubyProf.start + @profiling_now = true + end + end + + def update_caption + now = Gosu.milliseconds + if now - (@caption_updated_at || 0) > 1000 + $window.caption = 'Tank Island. ' << + "[FPS: #{Gosu.fps}. " << + "Tank @ #{@tank.x.round}:#{@tank.y.round}]" + @caption_updated_at = now + end + end +end diff --git a/Games/Debris_Dodge/lib/misc/axis_aligned_bounding_box.rb b/Games/Debris_Dodge/lib/misc/axis_aligned_bounding_box.rb new file mode 100644 index 0000000000..70bc9e30d1 --- /dev/null +++ b/Games/Debris_Dodge/lib/misc/axis_aligned_bounding_box.rb @@ -0,0 +1,33 @@ +class AxisAlignedBoundingBox + attr_reader :center, :half_dimension + def initialize(center, half_dimension) + @center = center + @half_dimension = half_dimension + @dhx = (@half_dimension[0] - @center[0]).abs + @dhy = (@half_dimension[1] - @center[1]).abs + end + + def contains?(point) + return false unless (@center[0] + @dhx) >= point[0] + return false unless (@center[0] - @dhx) <= point[0] + return false unless (@center[1] + @dhy) >= point[1] + return false unless (@center[1] - @dhy) <= point[1] + true + end + + def intersects?(other) + ocx, ocy = other.center + ohx, ohy = other.half_dimension + odhx = (ohx - ocx).abs + return false unless (@center[0] + @dhx) >= (ocx - odhx) + return false unless (@center[0] - @dhx) <= (ocx + odhx) + odhy = (ohy - ocy).abs + return false unless (@center[1] + @dhy) >= (ocy - odhy) + return false unless (@center[1] - @dhy) <= (ocy + odhy) + true + end + + def to_s + "c: #{@center}, h: #{@half_dimension}" + end +end diff --git a/Games/Debris_Dodge/lib/misc/game_window.rb b/Games/Debris_Dodge/lib/misc/game_window.rb new file mode 100644 index 0000000000..504061cf4a --- /dev/null +++ b/Games/Debris_Dodge/lib/misc/game_window.rb @@ -0,0 +1,30 @@ +class GameWindow < Gosu::Window + attr_accessor :state + + def initialize + super((ENV['w'] || 800).to_i, + (ENV['h'] || 600).to_i, + (ENV['fs'] ? true : false)) + end + + def update + Utils.track_update_interval + @state.update + end + + def draw + @state.draw + end + + def needs_redraw? + @state.needs_redraw? + end + + def needs_cursor? + Utils.update_interval > 200 + end + + def button_down(id) + @state.button_down(id) + end +end diff --git a/Games/Debris_Dodge/lib/misc/names.rb b/Games/Debris_Dodge/lib/misc/names.rb new file mode 100644 index 0000000000..09d2825521 --- /dev/null +++ b/Games/Debris_Dodge/lib/misc/names.rb @@ -0,0 +1,13 @@ +class Names + def initialize(file) + @names = File.read(file).split("\n").reject do |n| + n.size > 12 + end + end + + def random + name = @names.sample + @names.delete(name) + name + end +end diff --git a/Games/Debris_Dodge/lib/misc/quad_tree.rb b/Games/Debris_Dodge/lib/misc/quad_tree.rb new file mode 100644 index 0000000000..6a119aee01 --- /dev/null +++ b/Games/Debris_Dodge/lib/misc/quad_tree.rb @@ -0,0 +1,91 @@ +class QuadTree + NODE_CAPACITY = 12 + attr_accessor :ne, :nw, :se, :sw, :objects + + def initialize(boundary) + @boundary = boundary + @objects = [] + end + + def insert(game_object) + return false unless @boundary.contains?( + game_object.location) + + if @objects.size < NODE_CAPACITY + @objects << game_object + return true + end + + subdivide unless @nw + + return true if @nw.insert(game_object) + return true if @ne.insert(game_object) + return true if @sw.insert(game_object) + return true if @se.insert(game_object) + + # should never happen + raise "Failed to insert #{game_object}" + end + + def remove(game_object) + return false unless @boundary.contains?( + game_object.location) + if @objects.delete(game_object) + return true + end + return false unless @nw + return true if @nw.remove(game_object) + return true if @ne.remove(game_object) + return true if @sw.remove(game_object) + return true if @se.remove(game_object) + false + end + + def query_range(range) + result = [] + unless @boundary.intersects?(range) + return result + end + + @objects.each do |o| + if range.contains?(o.location) + result << o + end + end + + # Not subdivided + return result unless @ne + + result += @nw.query_range(range) + result += @ne.query_range(range) + result += @sw.query_range(range) + result += @se.query_range(range) + + result + end + + private + + def subdivide + cx, cy = @boundary.center + hx, hy = @boundary.half_dimension + hhx = (cx - hx).abs / 2.0 + hhy = (cy - hy).abs / 2.0 + @nw = QuadTree.new( + AxisAlignedBoundingBox.new( + [cx - hhx, cy - hhy], + [cx, cy])) + @ne = QuadTree.new( + AxisAlignedBoundingBox.new( + [cx + hhx, cy - hhy], + [cx, cy])) + @sw = QuadTree.new( + AxisAlignedBoundingBox.new( + [cx - hhx, cy + hhy], + [cx, cy])) + @se = QuadTree.new( + AxisAlignedBoundingBox.new( + [cx + hhx, cy + hhy], + [cx, cy])) + end +end diff --git a/Games/Debris_Dodge/lib/misc/stats.rb b/Games/Debris_Dodge/lib/misc/stats.rb new file mode 100644 index 0000000000..394b584991 --- /dev/null +++ b/Games/Debris_Dodge/lib/misc/stats.rb @@ -0,0 +1,55 @@ +class Stats + attr_reader :name, :kills, :deaths, :shots, :changed_at + def initialize(name) + @name = name + @kills = @deaths = @shots = @damage = @damage_dealt = 0 + changed + end + + def add_kill(amount = 1) + @kills += amount + changed + end + + def add_death + @deaths += 1 + changed + end + + def add_shot + @shots += 1 + changed + end + + def add_damage(amount) + @damage += amount + changed + end + + def damage + @damage.round + end + + def add_damage_dealt(amount) + @damage_dealt += amount + changed + end + + def damage_dealt + @damage_dealt.round + end + + def to_s + "[kills: #{@kills}, " \ + "deaths: #{@deaths}, " \ + "shots: #{@shots}, " \ + "damage: #{damage}, " \ + "damage_dealt: #{damage_dealt}]" + end + + private + + def changed + @changed_at = Gosu.milliseconds + end +end diff --git a/Games/Debris_Dodge/lib/misc/stereo_sample.rb b/Games/Debris_Dodge/lib/misc/stereo_sample.rb new file mode 100644 index 0000000000..211f6ca2f0 --- /dev/null +++ b/Games/Debris_Dodge/lib/misc/stereo_sample.rb @@ -0,0 +1,96 @@ +class StereoSample + MAX_POLIPHONY = 16 + @@all_instances = [] + + def self.register_instances(instances) + @@all_instances << instances + end + + def self.cleanup + @@all_instances.each do |instances| + instances.each do |key, instance| + unless instance.playing? || instance.paused? + instances.delete(key) + end + end + end + end + + def self.stop_all + @@all_instances.each do |instances| + instances.each do |key, instance| + if instance.playing? + instance.stop + end + end + end + end + + def initialize(window, sound_l, sound_r = sound_l) + @sound_l = Gosu::Sample.new(sound_l) + # Use same sample in mono -> stereo + if sound_l == sound_r + @sound_r = @sound_l + else + @sound_r = Gosu::Sample.new(sound_r) + end + @instances = {} + self.class.register_instances(@instances) + end + + def paused?(id = :default) + i = @instances["#{id}_l"] + i && i.paused? + end + + def playing?(id = :default) + i = @instances["#{id}_l"] + i && i.playing? + end + + def stopped?(id = :default) + @instances["#{id}_l"].nil? + end + + def play(id = :default, pan = 0, + volume = 1, speed = 1, looping = false) + if @instances.size > MAX_POLIPHONY + return + end + @instances["#{id}_l"] = @sound_l.play_pan( + -0.2, 0, speed, looping) + @instances["#{id}_r"] = @sound_r.play_pan( + 0.2, 0, speed, looping) + volume_and_pan(id, volume, pan) + end + + def pause(id = :default) + @instances["#{id}_l"].pause + @instances["#{id}_r"].pause + end + + def resume(id = :default) + @instances["#{id}_l"].resume + @instances["#{id}_r"].resume + end + + def stop + @instances.delete("#{id}_l").stop + @instances.delete("#{id}_r").stop + end + + def volume_and_pan(id, volume, pan) + return unless @instances["#{id}_l"] + if pan > 0 + pan_l = 1 - pan * 2 + pan_r = 1 + else + pan_l = 1 + pan_r = 1 + pan * 2 + end + pan_l *= volume + pan_r *= volume + @instances["#{id}_l"].volume = [pan_l, 0.05].max + @instances["#{id}_r"].volume = [pan_r, 0.05].max + end +end diff --git a/Games/Debris_Dodge/lib/misc/utils.rb b/Games/Debris_Dodge/lib/misc/utils.rb new file mode 100644 index 0000000000..88800da504 --- /dev/null +++ b/Games/Debris_Dodge/lib/misc/utils.rb @@ -0,0 +1,145 @@ +module Utils + HEARING_DISTANCE = 1000.0 + DEBUG_COLORS = [ + Gosu::Color::RED, + Gosu::Color::BLUE, + Gosu::Color::YELLOW, + Gosu::Color::WHITE + ] + def self.media_path(file) + File.join(File.dirname(File.dirname(File.dirname( + __FILE__))), 'media', file) + end + + def self.track_update_interval + now = Gosu.milliseconds + @update_interval = (now - (@last_update ||= 0)).to_f + @last_update = now + end + + def self.title_font + media_path('top_secret.ttf') + end + + def self.main_font + media_path('armalite_rifle.ttf') + end + + def self.update_interval + @update_interval ||= $window.update_interval + end + + def self.adjust_speed(speed) + speed * update_interval / 33.33 + end + + def self.button_down?(button) + @buttons ||= {} + now = Gosu.milliseconds + now = now - (now % 150) + if $window.button_down?(button) + @buttons[button] = now + true + elsif @buttons[button] + if now == @buttons[button] + true + else + @buttons.delete(button) + false + end + end + end + + def self.rotate(angle, around_x, around_y, *points) + result = [] + angle = angle * Math::PI / 180.0 + points.each_slice(2) do |x, y| + r_x = Math.cos(angle) * (around_x - x) - + Math.sin(angle) * (around_y - y) + around_x + r_y = Math.sin(angle) * (around_x - x) + + Math.cos(angle) * (around_y - y) + around_y + result << r_x + result << r_y + end + result + end + + # http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html + def self.point_in_poly(testx, testy, *poly) + nvert = poly.size / 2 # Number of vertices in poly + vertx = [] + verty = [] + poly.each_slice(2) do |x, y| + vertx << x + verty << y + end + inside = false + j = nvert - 1 + (0..nvert - 1).each do |i| + if (((verty[i] > testy) != (verty[j] > testy)) && + (testx < (vertx[j] - vertx[i]) * (testy - verty[i]) / + (verty[j] - verty[i]) + vertx[i])) + inside = !inside + end + j = i + end + inside + end + + def self.distance_between(x1, y1, x2, y2) + dx = x1 - x2 + dy = y1 - y2 + Math.sqrt(dx * dx + dy * dy) + end + + def self.angle_between(x, y, target_x, target_y) + dx = target_x - x + dy = target_y - y + (180 - Math.atan2(dx, dy) * 180 / Math::PI) + 360 % 360 + end + + def self.point_at_distance(source_x, source_y, angle, distance) + angle = (90 - angle) * Math::PI / 180 + x = source_x + Math.cos(angle) * distance + y = source_y - Math.sin(angle) * distance + [x, y] + end + + def self.mark_corners(box) + i = 0 + box.each_slice(2) do |x, y| + color = DEBUG_COLORS[i] + $window.draw_triangle( + x - 3, y - 3, color, + x, y, color, + x + 3, y - 3, color, + 100) + i = (i + 1) % 4 + end + end + + def self.volume(object, camera) + return 1 if object == camera.target + distance = Utils.distance_between( + camera.target.x, camera.target.y, + object.x, object.y) + distance = [(HEARING_DISTANCE - distance), 0].max + distance / HEARING_DISTANCE + end + + def self.pan(object, camera) + return 0 if object == camera.target + pan = object.x - camera.target.x + sig = pan > 0 ? 1 : -1 + pan = (pan % HEARING_DISTANCE) / HEARING_DISTANCE + if sig > 0 + pan + else + -1 + pan + end + end + + def self.volume_and_pan(object, camera) + [volume(object, camera), pan(object, camera)] + end +end diff --git a/Games/Debris_Dodge/media/armalite_rifle.ttf b/Games/Debris_Dodge/media/armalite_rifle.ttf new file mode 100644 index 0000000000..06619a3aef Binary files /dev/null and b/Games/Debris_Dodge/media/armalite_rifle.ttf differ diff --git a/Games/Debris_Dodge/media/boxes_barrels.json b/Games/Debris_Dodge/media/boxes_barrels.json new file mode 100644 index 0000000000..f74563a202 --- /dev/null +++ b/Games/Debris_Dodge/media/boxes_barrels.json @@ -0,0 +1,60 @@ +{"frames": { + +"barrel_side.png": +{ + "frame": {"x":2,"y":2,"w":30,"h":36}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":30,"h":36}, + "sourceSize": {"w":30,"h":36} +}, +"barrel_top.png": +{ + "frame": {"x":34,"y":2,"w":30,"h":32}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":30,"h":32}, + "sourceSize": {"w":30,"h":32} +}, +"box.png": +{ + "frame": {"x":42,"y":40,"w":50,"h":50}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":50,"h":50}, + "sourceSize": {"w":50,"h":50} +}, +"box_2x1.png": +{ + "frame": {"x":2,"y":176,"w":80,"h":53}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":80,"h":53}, + "sourceSize": {"w":80,"h":53} +}, +"box_2x2.png": +{ + "frame": {"x":2,"y":92,"w":80,"h":82}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":80,"h":82}, + "sourceSize": {"w":80,"h":82} +}, +"box_small.png": +{ + "frame": {"x":2,"y":40,"w":38,"h":40}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":38,"h":40}, + "sourceSize": {"w":38,"h":40} +}}, +"meta": { + "app": "http://www.codeandweb.com/texturepacker ", + "version": "1.0", + "image": "boxes_barrels.png", + "format": "RGBA8888", + "size": {"w":94,"h":231}, + "scale": "1", + "smartupdate": "$TexturePacker:SmartUpdate:e1f8dd3e75d56379964832e4e1fe08fd:ca59b503f7b878a09d84d41cbeb53a15:d01cf1bf6125b2a1524959777ff4451f$" +} +} diff --git a/Games/Debris_Dodge/media/boxes_barrels.png b/Games/Debris_Dodge/media/boxes_barrels.png new file mode 100644 index 0000000000..89a94f1286 Binary files /dev/null and b/Games/Debris_Dodge/media/boxes_barrels.png differ diff --git a/Games/Debris_Dodge/media/bullet.png b/Games/Debris_Dodge/media/bullet.png new file mode 100644 index 0000000000..a8016083e9 Binary files /dev/null and b/Games/Debris_Dodge/media/bullet.png differ diff --git a/Games/Debris_Dodge/media/c_dot.png b/Games/Debris_Dodge/media/c_dot.png new file mode 100644 index 0000000000..c848f78c53 Binary files /dev/null and b/Games/Debris_Dodge/media/c_dot.png differ diff --git a/Games/Debris_Dodge/media/country_field.png b/Games/Debris_Dodge/media/country_field.png new file mode 100644 index 0000000000..4a2dffdb18 Binary files /dev/null and b/Games/Debris_Dodge/media/country_field.png differ diff --git a/Games/Debris_Dodge/media/crash.ogg b/Games/Debris_Dodge/media/crash.ogg new file mode 100644 index 0000000000..8a9bd8cd39 Binary files /dev/null and b/Games/Debris_Dodge/media/crash.ogg differ diff --git a/Games/Debris_Dodge/media/damage1.png b/Games/Debris_Dodge/media/damage1.png new file mode 100644 index 0000000000..371c304e66 Binary files /dev/null and b/Games/Debris_Dodge/media/damage1.png differ diff --git a/Games/Debris_Dodge/media/damage2.png b/Games/Debris_Dodge/media/damage2.png new file mode 100644 index 0000000000..5ca6de4f34 Binary files /dev/null and b/Games/Debris_Dodge/media/damage2.png differ diff --git a/Games/Debris_Dodge/media/damage3.png b/Games/Debris_Dodge/media/damage3.png new file mode 100644 index 0000000000..b676c0df70 Binary files /dev/null and b/Games/Debris_Dodge/media/damage3.png differ diff --git a/Games/Debris_Dodge/media/damage4.png b/Games/Debris_Dodge/media/damage4.png new file mode 100644 index 0000000000..b748883b92 Binary files /dev/null and b/Games/Debris_Dodge/media/damage4.png differ diff --git a/Games/Debris_Dodge/media/decor.json b/Games/Debris_Dodge/media/decor.json new file mode 100644 index 0000000000..e5a59aaee4 --- /dev/null +++ b/Games/Debris_Dodge/media/decor.json @@ -0,0 +1,516 @@ +{"frames": { + +"aircraft_1d_destroyed.png": +{ + "frame": {"x":451,"y":102,"w":57,"h":42}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":57,"h":42}, + "sourceSize": {"w":57,"h":42} +}, +"aircraft_2d_destroyed.png": +{ + "frame": {"x":2,"y":680,"w":63,"h":47}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":63,"h":47}, + "sourceSize": {"w":63,"h":47} +}, +"aircraft_3d_destroyed.png": +{ + "frame": {"x":368,"y":125,"w":81,"h":55}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":81,"h":55}, + "sourceSize": {"w":81,"h":55} +}, +"aircraft_3e_destroyed.png": +{ + "frame": {"x":368,"y":68,"w":81,"h":55}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":81,"h":55}, + "sourceSize": {"w":81,"h":55} +}, +"barrels_1.png": +{ + "frame": {"x":430,"y":738,"w":64,"h":64}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":64,"h":64}, + "sourceSize": {"w":64,"h":64} +}, +"barrels_2.png": +{ + "frame": {"x":364,"y":680,"w":64,"h":64}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":64,"h":64}, + "sourceSize": {"w":64,"h":64} +}, +"bush_1.png": +{ + "frame": {"x":102,"y":820,"w":64,"h":64}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":64,"h":64}, + "sourceSize": {"w":64,"h":64} +}, +"bush_big.png": +{ + "frame": {"x":368,"y":182,"w":128,"h":128}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":128,"h":128}, + "sourceSize": {"w":128,"h":128} +}, +"crates_1.png": +{ + "frame": {"x":168,"y":794,"w":64,"h":64}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":64,"h":64}, + "sourceSize": {"w":64,"h":64} +}, +"crates_2.png": +{ + "frame": {"x":102,"y":754,"w":64,"h":64}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":64,"h":64}, + "sourceSize": {"w":64,"h":64} +}, +"crates_3.png": +{ + "frame": {"x":331,"y":812,"w":64,"h":64}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":64,"h":64}, + "sourceSize": {"w":64,"h":64} +}, +"crates_4.png": +{ + "frame": {"x":265,"y":760,"w":64,"h":64}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":64,"h":64}, + "sourceSize": {"w":64,"h":64} +}, +"dirt_001.png": +{ + "frame": {"x":2,"y":480,"w":88,"h":68}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":88,"h":68}, + "sourceSize": {"w":88,"h":68} +}, +"dirt_002.png": +{ + "frame": {"x":2,"y":550,"w":88,"h":64}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":88,"h":64}, + "sourceSize": {"w":88,"h":64} +}, +"dirt_grass_hor_01.png": +{ + "frame": {"x":2,"y":272,"w":128,"h":104}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":128,"h":104}, + "sourceSize": {"w":128,"h":104} +}, +"dirt_grass_hor_02.png": +{ + "frame": {"x":2,"y":166,"w":128,"h":104}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":128,"h":104}, + "sourceSize": {"w":128,"h":104} +}, +"dirt_grass_vert.png": +{ + "frame": {"x":132,"y":36,"w":104,"h":128}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":104,"h":128}, + "sourceSize": {"w":104,"h":128} +}, +"dirt_road_hor.png": +{ + "frame": {"x":2,"y":2,"w":256,"h":32}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":256,"h":32}, + "sourceSize": {"w":256,"h":32} +}, +"dirt_road_vert.png": +{ + "frame": {"x":2,"y":738,"w":32,"h":256}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":32,"h":256}, + "sourceSize": {"w":32,"h":256} +}, +"grass_01.png": +{ + "frame": {"x":238,"y":68,"w":128,"h":128}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":128,"h":128}, + "sourceSize": {"w":128,"h":128} +}, +"grass_02.png": +{ + "frame": {"x":2,"y":36,"w":128,"h":128}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":128,"h":128}, + "sourceSize": {"w":128,"h":128} +}, +"road_1.png": +{ + "frame": {"x":234,"y":532,"w":64,"h":128}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":64,"h":128}, + "sourceSize": {"w":64,"h":128} +}, +"road_2.png": +{ + "frame": {"x":430,"y":608,"w":64,"h":128}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":64,"h":128}, + "sourceSize": {"w":64,"h":128} +}, +"road_3.png": +{ + "frame": {"x":364,"y":486,"w":64,"h":192}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":64,"h":192}, + "sourceSize": {"w":64,"h":192} +}, +"road_4.png": +{ + "frame": {"x":432,"y":414,"w":64,"h":192}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":64,"h":192}, + "sourceSize": {"w":64,"h":192} +}, +"road_5.png": +{ + "frame": {"x":260,"y":2,"w":192,"h":64}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":192,"h":64}, + "sourceSize": {"w":192,"h":64} +}, +"road_asphalt_clean_hor.png": +{ + "frame": {"x":364,"y":312,"w":128,"h":100}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":128,"h":100}, + "sourceSize": {"w":128,"h":100} +}, +"road_asphalt_clean_to_damaged_hor.png": +{ + "frame": {"x":234,"y":300,"w":128,"h":100}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":128,"h":100}, + "sourceSize": {"w":128,"h":100} +}, +"road_asphalt_clean_to_damaged_vert.png": +{ + "frame": {"x":132,"y":426,"w":100,"h":128}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":100,"h":128}, + "sourceSize": {"w":100,"h":128} +}, +"road_asphalt_clean_vert.png": +{ + "frame": {"x":234,"y":402,"w":100,"h":128}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":100,"h":128}, + "sourceSize": {"w":100,"h":128} +}, +"road_asphalt_damaged_hor.png": +{ + "frame": {"x":2,"y":378,"w":128,"h":100}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":128,"h":100}, + "sourceSize": {"w":128,"h":100} +}, +"road_asphalt_damaged_to_clean_hor.png": +{ + "frame": {"x":234,"y":198,"w":128,"h":100}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":128,"h":100}, + "sourceSize": {"w":128,"h":100} +}, +"road_asphalt_damaged_to_clean_vert.png": +{ + "frame": {"x":132,"y":296,"w":100,"h":128}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":100,"h":128}, + "sourceSize": {"w":100,"h":128} +}, +"road_asphalt_damaged_vert.png": +{ + "frame": {"x":132,"y":166,"w":100,"h":128}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":100,"h":128}, + "sourceSize": {"w":100,"h":128} +}, +"road_corner_1.png": +{ + "frame": {"x":199,"y":728,"w":64,"h":64}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":64,"h":64}, + "sourceSize": {"w":64,"h":64} +}, +"road_corner_2.png": +{ + "frame": {"x":133,"y":688,"w":64,"h":64}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":64,"h":64}, + "sourceSize": {"w":64,"h":64} +}, +"road_corner_3.png": +{ + "frame": {"x":67,"y":688,"w":64,"h":64}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":64,"h":64}, + "sourceSize": {"w":64,"h":64} +}, +"road_corner_4.png": +{ + "frame": {"x":36,"y":760,"w":64,"h":64}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":64,"h":64}, + "sourceSize": {"w":64,"h":64} +}, +"rock_010.png": +{ + "frame": {"x":364,"y":414,"w":66,"h":70}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":66,"h":70}, + "sourceSize": {"w":66,"h":70} +}, +"rock_1.png": +{ + "frame": {"x":36,"y":936,"w":64,"h":64}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":64,"h":64}, + "sourceSize": {"w":64,"h":64} +}, +"rock_2.png": +{ + "frame": {"x":36,"y":870,"w":64,"h":64}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":64,"h":64}, + "sourceSize": {"w":64,"h":64} +}, +"rock_3.png": +{ + "frame": {"x":428,"y":804,"w":64,"h":64}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":64,"h":64}, + "sourceSize": {"w":64,"h":64} +}, +"rock_4.png": +{ + "frame": {"x":362,"y":746,"w":64,"h":64}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":64,"h":64}, + "sourceSize": {"w":64,"h":64} +}, +"rock_5.png": +{ + "frame": {"x":296,"y":694,"w":64,"h":64}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":64,"h":64}, + "sourceSize": {"w":64,"h":64} +}, +"rock_6.png": +{ + "frame": {"x":230,"y":662,"w":64,"h":64}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":64,"h":64}, + "sourceSize": {"w":64,"h":64} +}, +"rock_7.png": +{ + "frame": {"x":164,"y":622,"w":64,"h":64}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":64,"h":64}, + "sourceSize": {"w":64,"h":64} +}, +"rock_8.png": +{ + "frame": {"x":98,"y":622,"w":64,"h":64}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":64,"h":64}, + "sourceSize": {"w":64,"h":64} +}, +"rock_9.png": +{ + "frame": {"x":128,"y":556,"w":64,"h":64}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":64,"h":64}, + "sourceSize": {"w":64,"h":64} +}, +"tank1_body_destroyed.png": +{ + "frame": {"x":92,"y":480,"w":34,"h":48}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":34,"h":48}, + "sourceSize": {"w":34,"h":48} +}, +"tank1b_body_destroyed.png": +{ + "frame": {"x":92,"y":530,"w":34,"h":48}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":34,"h":48}, + "sourceSize": {"w":34,"h":48} +}, +"tank2_body_destroyed.png": +{ + "frame": {"x":454,"y":2,"w":42,"h":48}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":42,"h":48}, + "sourceSize": {"w":42,"h":48} +}, +"tank2b_body_destroyed.png": +{ + "frame": {"x":454,"y":52,"w":42,"h":48}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":42,"h":48}, + "sourceSize": {"w":42,"h":48} +}, +"tank3_body_destroyed.png": +{ + "frame": {"x":336,"y":525,"w":26,"h":39}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":26,"h":39}, + "sourceSize": {"w":26,"h":39} +}, +"tank3b_body_destroyed.png": +{ + "frame": {"x":336,"y":484,"w":26,"h":39}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":26,"h":39}, + "sourceSize": {"w":26,"h":39} +}, +"tank3c_body_destroyed.png": +{ + "frame": {"x":336,"y":443,"w":26,"h":39}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":26,"h":39}, + "sourceSize": {"w":26,"h":39} +}, +"tank3d_body_destroyed.png": +{ + "frame": {"x":336,"y":402,"w":26,"h":39}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":26,"h":39}, + "sourceSize": {"w":26,"h":39} +}, +"truck1_destroyed.png": +{ + "frame": {"x":2,"y":616,"w":30,"h":62}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":30,"h":62}, + "sourceSize": {"w":30,"h":62} +}, +"truck1b_destroyed.png": +{ + "frame": {"x":332,"y":630,"w":30,"h":62}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":30,"h":62}, + "sourceSize": {"w":30,"h":62} +}, +"truck1c_destroyed.png": +{ + "frame": {"x":300,"y":596,"w":30,"h":62}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":30,"h":62}, + "sourceSize": {"w":30,"h":62} +}, +"truck2_destroyed.png": +{ + "frame": {"x":332,"y":566,"w":30,"h":62}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":30,"h":62}, + "sourceSize": {"w":30,"h":62} +}, +"truck2b_destroyed.png": +{ + "frame": {"x":300,"y":532,"w":30,"h":62}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":30,"h":62}, + "sourceSize": {"w":30,"h":62} +}, +"truck2c_destroyed.png": +{ + "frame": {"x":66,"y":616,"w":30,"h":62}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":30,"h":62}, + "sourceSize": {"w":30,"h":62} +}, +"truck3_destroyed.png": +{ + "frame": {"x":34,"y":616,"w":30,"h":62}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":30,"h":62}, + "sourceSize": {"w":30,"h":62} +}}, +"meta": { + "app": "http://www.texturepacker.com", + "version": "1.0", + "image": "decor.png", + "format": "RGBA8888", + "size": {"w":512,"h":1024}, + "scale": "1", + "smartupdate": "$TexturePacker:SmartUpdate:2e6b6964f24c7abfaa85a804e2dc1b05$" +} +} diff --git a/Games/Debris_Dodge/media/decor.png b/Games/Debris_Dodge/media/decor.png new file mode 100644 index 0000000000..9c385f8870 Binary files /dev/null and b/Games/Debris_Dodge/media/decor.png differ diff --git a/Games/Debris_Dodge/media/decor.psd b/Games/Debris_Dodge/media/decor.psd new file mode 100644 index 0000000000..ba2766e4d6 Binary files /dev/null and b/Games/Debris_Dodge/media/decor.psd differ diff --git a/Games/Debris_Dodge/media/explosion.ogg b/Games/Debris_Dodge/media/explosion.ogg new file mode 100644 index 0000000000..04d6799b97 Binary files /dev/null and b/Games/Debris_Dodge/media/explosion.ogg differ diff --git a/Games/Debris_Dodge/media/explosion.png b/Games/Debris_Dodge/media/explosion.png new file mode 100644 index 0000000000..42fa4425f9 Binary files /dev/null and b/Games/Debris_Dodge/media/explosion.png differ diff --git a/Games/Debris_Dodge/media/fire.ogg b/Games/Debris_Dodge/media/fire.ogg new file mode 100644 index 0000000000..0c82c760df Binary files /dev/null and b/Games/Debris_Dodge/media/fire.ogg differ diff --git a/Games/Debris_Dodge/media/ground.json b/Games/Debris_Dodge/media/ground.json new file mode 100644 index 0000000000..1193be2e7a --- /dev/null +++ b/Games/Debris_Dodge/media/ground.json @@ -0,0 +1,492 @@ +{"frames": { + +"beach_bl.png": +{ + "frame": {"x":896,"y":640,"w":128,"h":128}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":128,"h":128}, + "sourceSize": {"w":128,"h":128} +}, +"beach_bl_grass.png": +{ + "frame": {"x":768,"y":640,"w":128,"h":128}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":128,"h":128}, + "sourceSize": {"w":128,"h":128} +}, +"beach_bm_01.png": +{ + "frame": {"x":640,"y":896,"w":128,"h":128}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":128,"h":128}, + "sourceSize": {"w":128,"h":128} +}, +"beach_bm_01_grass.png": +{ + "frame": {"x":640,"y":768,"w":128,"h":128}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":128,"h":128}, + "sourceSize": {"w":128,"h":128} +}, +"beach_bm_02.png": +{ + "frame": {"x":640,"y":640,"w":128,"h":128}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":128,"h":128}, + "sourceSize": {"w":128,"h":128} +}, +"beach_bm_02_grass.png": +{ + "frame": {"x":896,"y":512,"w":128,"h":128}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":128,"h":128}, + "sourceSize": {"w":128,"h":128} +}, +"beach_bm_03.png": +{ + "frame": {"x":768,"y":512,"w":128,"h":128}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":128,"h":128}, + "sourceSize": {"w":128,"h":128} +}, +"beach_bm_03_grass.png": +{ + "frame": {"x":640,"y":512,"w":128,"h":128}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":128,"h":128}, + "sourceSize": {"w":128,"h":128} +}, +"beach_bm_04.png": +{ + "frame": {"x":512,"y":896,"w":128,"h":128}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":128,"h":128}, + "sourceSize": {"w":128,"h":128} +}, +"beach_bm_04_grass.png": +{ + "frame": {"x":512,"y":768,"w":128,"h":128}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":128,"h":128}, + "sourceSize": {"w":128,"h":128} +}, +"beach_bm_05.png": +{ + "frame": {"x":512,"y":640,"w":128,"h":128}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":128,"h":128}, + "sourceSize": {"w":128,"h":128} +}, +"beach_bm_05_grass.png": +{ + "frame": {"x":512,"y":512,"w":128,"h":128}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":128,"h":128}, + "sourceSize": {"w":128,"h":128} +}, +"beach_br.png": +{ + "frame": {"x":896,"y":384,"w":128,"h":128}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":128,"h":128}, + "sourceSize": {"w":128,"h":128} +}, +"beach_br_grass.png": +{ + "frame": {"x":768,"y":384,"w":128,"h":128}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":128,"h":128}, + "sourceSize": {"w":128,"h":128} +}, +"beach_l_up_diagonal.png": +{ + "frame": {"x":640,"y":384,"w":128,"h":128}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":128,"h":128}, + "sourceSize": {"w":128,"h":128} +}, +"beach_l_up_diagonal_grass.png": +{ + "frame": {"x":512,"y":384,"w":128,"h":128}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":128,"h":128}, + "sourceSize": {"w":128,"h":128} +}, +"beach_l_up_diagonal_neighbour.png": +{ + "frame": {"x":384,"y":896,"w":128,"h":128}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":128,"h":128}, + "sourceSize": {"w":128,"h":128} +}, +"beach_l_up_diagonal_neighbour_grass.png": +{ + "frame": {"x":384,"y":768,"w":128,"h":128}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":128,"h":128}, + "sourceSize": {"w":128,"h":128} +}, +"beach_lm_01.png": +{ + "frame": {"x":384,"y":640,"w":128,"h":128}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":128,"h":128}, + "sourceSize": {"w":128,"h":128} +}, +"beach_lm_01_grass.png": +{ + "frame": {"x":384,"y":512,"w":128,"h":128}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":128,"h":128}, + "sourceSize": {"w":128,"h":128} +}, +"beach_lm_02.png": +{ + "frame": {"x":384,"y":384,"w":128,"h":128}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":128,"h":128}, + "sourceSize": {"w":128,"h":128} +}, +"beach_lm_02_grass.png": +{ + "frame": {"x":896,"y":256,"w":128,"h":128}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":128,"h":128}, + "sourceSize": {"w":128,"h":128} +}, +"beach_lm_03.png": +{ + "frame": {"x":768,"y":256,"w":128,"h":128}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":128,"h":128}, + "sourceSize": {"w":128,"h":128} +}, +"beach_lm_03_grass.png": +{ + "frame": {"x":640,"y":256,"w":128,"h":128}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":128,"h":128}, + "sourceSize": {"w":128,"h":128} +}, +"beach_lm_04.png": +{ + "frame": {"x":512,"y":256,"w":128,"h":128}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":128,"h":128}, + "sourceSize": {"w":128,"h":128} +}, +"beach_lm_04_grass.png": +{ + "frame": {"x":384,"y":256,"w":128,"h":128}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":128,"h":128}, + "sourceSize": {"w":128,"h":128} +}, +"beach_r_diagonal_neighbour.png": +{ + "frame": {"x":256,"y":896,"w":128,"h":128}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":128,"h":128}, + "sourceSize": {"w":128,"h":128} +}, +"beach_r_diagonal_neighbour_grass.png": +{ + "frame": {"x":256,"y":768,"w":128,"h":128}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":128,"h":128}, + "sourceSize": {"w":128,"h":128} +}, +"beach_r_down_diagonal.png": +{ + "frame": {"x":256,"y":640,"w":128,"h":128}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":128,"h":128}, + "sourceSize": {"w":128,"h":128} +}, +"beach_r_down_diagonal_grass.png": +{ + "frame": {"x":256,"y":512,"w":128,"h":128}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":128,"h":128}, + "sourceSize": {"w":128,"h":128} +}, +"beach_r_down_diagonal_neighbour.png": +{ + "frame": {"x":256,"y":384,"w":128,"h":128}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":128,"h":128}, + "sourceSize": {"w":128,"h":128} +}, +"beach_r_down_diagonal_neighbour_grass.png": +{ + "frame": {"x":256,"y":256,"w":128,"h":128}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":128,"h":128}, + "sourceSize": {"w":128,"h":128} +}, +"beach_r_up_diagonal.png": +{ + "frame": {"x":896,"y":128,"w":128,"h":128}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":128,"h":128}, + "sourceSize": {"w":128,"h":128} +}, +"beach_r_up_diagonal_grass.png": +{ + "frame": {"x":768,"y":128,"w":128,"h":128}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":128,"h":128}, + "sourceSize": {"w":128,"h":128} +}, +"beach_rm_01-22.png": +{ + "frame": {"x":256,"y":128,"w":128,"h":128}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":128,"h":128}, + "sourceSize": {"w":128,"h":128} +}, +"beach_rm_01.png": +{ + "frame": {"x":640,"y":128,"w":128,"h":128}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":128,"h":128}, + "sourceSize": {"w":128,"h":128} +}, +"beach_rm_01_grass-22.png": +{ + "frame": {"x":384,"y":128,"w":128,"h":128}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":128,"h":128}, + "sourceSize": {"w":128,"h":128} +}, +"beach_rm_01_grass.png": +{ + "frame": {"x":512,"y":128,"w":128,"h":128}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":128,"h":128}, + "sourceSize": {"w":128,"h":128} +}, +"beach_rm_02.png": +{ + "frame": {"x":128,"y":896,"w":128,"h":128}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":128,"h":128}, + "sourceSize": {"w":128,"h":128} +}, +"beach_rm_02_grass.png": +{ + "frame": {"x":128,"y":768,"w":128,"h":128}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":128,"h":128}, + "sourceSize": {"w":128,"h":128} +}, +"beach_rm_03.png": +{ + "frame": {"x":128,"y":640,"w":128,"h":128}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":128,"h":128}, + "sourceSize": {"w":128,"h":128} +}, +"beach_rm_03_grass.png": +{ + "frame": {"x":128,"y":512,"w":128,"h":128}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":128,"h":128}, + "sourceSize": {"w":128,"h":128} +}, +"beach_rm_04.png": +{ + "frame": {"x":128,"y":384,"w":128,"h":128}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":128,"h":128}, + "sourceSize": {"w":128,"h":128} +}, +"beach_rm_04_grass.png": +{ + "frame": {"x":128,"y":256,"w":128,"h":128}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":128,"h":128}, + "sourceSize": {"w":128,"h":128} +}, +"beach_rm_05.png": +{ + "frame": {"x":128,"y":128,"w":128,"h":128}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":128,"h":128}, + "sourceSize": {"w":128,"h":128} +}, +"beach_rm_05_grass.png": +{ + "frame": {"x":896,"y":0,"w":128,"h":128}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":128,"h":128}, + "sourceSize": {"w":128,"h":128} +}, +"beach_tl.png": +{ + "frame": {"x":768,"y":0,"w":128,"h":128}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":128,"h":128}, + "sourceSize": {"w":128,"h":128} +}, +"beach_tl_grass.png": +{ + "frame": {"x":640,"y":0,"w":128,"h":128}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":128,"h":128}, + "sourceSize": {"w":128,"h":128} +}, +"beach_tm_01.png": +{ + "frame": {"x":512,"y":0,"w":128,"h":128}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":128,"h":128}, + "sourceSize": {"w":128,"h":128} +}, +"beach_tm_01_grass.png": +{ + "frame": {"x":384,"y":0,"w":128,"h":128}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":128,"h":128}, + "sourceSize": {"w":128,"h":128} +}, +"beach_tm_02.png": +{ + "frame": {"x":256,"y":0,"w":128,"h":128}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":128,"h":128}, + "sourceSize": {"w":128,"h":128} +}, +"beach_tm_02_grass.png": +{ + "frame": {"x":128,"y":0,"w":128,"h":128}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":128,"h":128}, + "sourceSize": {"w":128,"h":128} +}, +"beach_tm_03.png": +{ + "frame": {"x":0,"y":896,"w":128,"h":128}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":128,"h":128}, + "sourceSize": {"w":128,"h":128} +}, +"beach_tm_03_grass.png": +{ + "frame": {"x":0,"y":768,"w":128,"h":128}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":128,"h":128}, + "sourceSize": {"w":128,"h":128} +}, +"beach_tm_04.png": +{ + "frame": {"x":0,"y":640,"w":128,"h":128}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":128,"h":128}, + "sourceSize": {"w":128,"h":128} +}, +"beach_tm_04_grass.png": +{ + "frame": {"x":0,"y":512,"w":128,"h":128}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":128,"h":128}, + "sourceSize": {"w":128,"h":128} +}, +"beach_tr.png": +{ + "frame": {"x":0,"y":384,"w":128,"h":128}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":128,"h":128}, + "sourceSize": {"w":128,"h":128} +}, +"beach_tr_grass.png": +{ + "frame": {"x":0,"y":256,"w":128,"h":128}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":128,"h":128}, + "sourceSize": {"w":128,"h":128} +}, +"grass.png": +{ + "frame": {"x":0,"y":128,"w":128,"h":128}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":128,"h":128}, + "sourceSize": {"w":128,"h":128} +}, +"sand.png": +{ + "frame": {"x":0,"y":0,"w":128,"h":128}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":128,"h":128}, + "sourceSize": {"w":128,"h":128} +}}, +"meta": { + "app": "http://www.texturepacker.com", + "version": "1.0", + "image": "ground.png", + "format": "RGBA8888", + "size": {"w":1024,"h":1024}, + "scale": "1", + "smartupdate": "$TexturePacker:SmartUpdate:a4e7956c80b1dabce22dc97d34f9811b$" +} +} diff --git a/Games/Debris_Dodge/media/ground.png b/Games/Debris_Dodge/media/ground.png new file mode 100644 index 0000000000..536a5ceb08 Binary files /dev/null and b/Games/Debris_Dodge/media/ground.png differ diff --git a/Games/Debris_Dodge/media/ground_units.json b/Games/Debris_Dodge/media/ground_units.json new file mode 100644 index 0000000000..a3bcc73653 --- /dev/null +++ b/Games/Debris_Dodge/media/ground_units.json @@ -0,0 +1,900 @@ +{"frames": { + +"tank1_body.png": +{ + "frame": {"x":278,"y":338,"w":34,"h":48}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":34,"h":48}, + "sourceSize": {"w":34,"h":48} +}, +"tank1_body_1b.png": +{ + "frame": {"x":314,"y":382,"w":34,"h":48}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":34,"h":48}, + "sourceSize": {"w":34,"h":48} +}, +"tank1_body_destroyed.png": +{ + "frame": {"x":322,"y":332,"w":34,"h":48}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":34,"h":48}, + "sourceSize": {"w":34,"h":48} +}, +"tank1_body_destroyed_shadow.png": +{ + "frame": {"x":438,"y":346,"w":34,"h":48}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":34,"h":48}, + "sourceSize": {"w":34,"h":48} +}, +"tank1_body_hit.png": +{ + "frame": {"x":366,"y":302,"w":34,"h":48}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":34,"h":48}, + "sourceSize": {"w":34,"h":48} +}, +"tank1_body_shadow.png": +{ + "frame": {"x":402,"y":302,"w":34,"h":48}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":34,"h":48}, + "sourceSize": {"w":34,"h":48} +}, +"tank1_dualgun.png": +{ + "frame": {"x":336,"y":244,"w":56,"h":56}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":56,"h":56}, + "sourceSize": {"w":56,"h":56} +}, +"tank1_dualgun_hit.png": +{ + "frame": {"x":234,"y":196,"w":56,"h":56}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":56,"h":56}, + "sourceSize": {"w":56,"h":56} +}, +"tank1_gun.png": +{ + "frame": {"x":176,"y":196,"w":56,"h":56}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":56,"h":56}, + "sourceSize": {"w":56,"h":56} +}, +"tank1_gun_destroyed-02.png": +{ + "frame": {"x":60,"y":196,"w":56,"h":56}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":56,"h":56}, + "sourceSize": {"w":56,"h":56} +}, +"tank1_gun_destroyed.png": +{ + "frame": {"x":118,"y":196,"w":56,"h":56}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":56,"h":56}, + "sourceSize": {"w":56,"h":56} +}, +"tank1_gun_hit.png": +{ + "frame": {"x":2,"y":196,"w":56,"h":56}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":56,"h":56}, + "sourceSize": {"w":56,"h":56} +}, +"tank1_track.png": +{ + "frame": {"x":394,"y":352,"w":34,"h":28}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":34,"h":28}, + "sourceSize": {"w":34,"h":28} +}, +"tank1b_body.png": +{ + "frame": {"x":358,"y":352,"w":34,"h":48}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":34,"h":48}, + "sourceSize": {"w":34,"h":48} +}, +"tank1b_body_destroyed.png": +{ + "frame": {"x":474,"y":346,"w":34,"h":48}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":34,"h":48}, + "sourceSize": {"w":34,"h":48} +}, +"tank1b_body_destroyed_shadow.png": +{ + "frame": {"x":438,"y":346,"w":34,"h":48}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":34,"h":48}, + "sourceSize": {"w":34,"h":48} +}, +"tank1b_body_shadow.png": +{ + "frame": {"x":402,"y":302,"w":34,"h":48}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":34,"h":48}, + "sourceSize": {"w":34,"h":48} +}, +"tank1b_dualgun.png": +{ + "frame": {"x":176,"y":254,"w":56,"h":56}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":56,"h":56}, + "sourceSize": {"w":56,"h":56} +}, +"tank1b_dualgun_hit.png": +{ + "frame": {"x":118,"y":254,"w":56,"h":56}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":56,"h":56}, + "sourceSize": {"w":56,"h":56} +}, +"tank1b_gun.png": +{ + "frame": {"x":60,"y":254,"w":56,"h":56}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":56,"h":56}, + "sourceSize": {"w":56,"h":56} +}, +"tank1b_gun_destroyed-02.png": +{ + "frame": {"x":452,"y":288,"w":56,"h":56}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":56,"h":56}, + "sourceSize": {"w":56,"h":56} +}, +"tank1b_gun_destroyed.png": +{ + "frame": {"x":2,"y":254,"w":56,"h":56}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":56,"h":56}, + "sourceSize": {"w":56,"h":56} +}, +"tank1b_gun_hit.png": +{ + "frame": {"x":394,"y":244,"w":56,"h":56}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":56,"h":56}, + "sourceSize": {"w":56,"h":56} +}, +"tank1b_track.png": +{ + "frame": {"x":394,"y":382,"w":34,"h":28}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":34,"h":28}, + "sourceSize": {"w":34,"h":28} +}, +"tank2_body.png": +{ + "frame": {"x":292,"y":138,"w":42,"h":48}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":42,"h":48}, + "sourceSize": {"w":42,"h":48} +}, +"tank2_body_destroyed.png": +{ + "frame": {"x":458,"y":180,"w":42,"h":48}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":42,"h":48}, + "sourceSize": {"w":42,"h":48} +}, +"tank2_body_destroyed_shadow.png": +{ + "frame": {"x":234,"y":254,"w":42,"h":48}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":42,"h":48}, + "sourceSize": {"w":42,"h":48} +}, +"tank2_body_hit.png": +{ + "frame": {"x":458,"y":130,"w":42,"h":48}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":42,"h":48}, + "sourceSize": {"w":42,"h":48} +}, +"tank2_body_shadow.png": +{ + "frame": {"x":292,"y":188,"w":42,"h":48}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":42,"h":48}, + "sourceSize": {"w":42,"h":48} +}, +"tank2_dualgun.png": +{ + "frame": {"x":342,"y":2,"w":66,"h":66}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":66,"h":66}, + "sourceSize": {"w":66,"h":66} +}, +"tank2_dualgun_destroyed.png": +{ + "frame": {"x":274,"y":2,"w":66,"h":66}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":66,"h":66}, + "sourceSize": {"w":66,"h":66} +}, +"tank2_dualgun_hit.png": +{ + "frame": {"x":206,"y":2,"w":66,"h":66}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":66,"h":66}, + "sourceSize": {"w":66,"h":66} +}, +"tank2_gun.png": +{ + "frame": {"x":138,"y":2,"w":66,"h":66}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":66,"h":66}, + "sourceSize": {"w":66,"h":66} +}, +"tank2_gun_destroyed.png": +{ + "frame": {"x":70,"y":2,"w":66,"h":66}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":66,"h":66}, + "sourceSize": {"w":66,"h":66} +}, +"tank2_gun_hit.png": +{ + "frame": {"x":2,"y":2,"w":66,"h":66}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":66,"h":66}, + "sourceSize": {"w":66,"h":66} +}, +"tank2_track.png": +{ + "frame": {"x":322,"y":302,"w":42,"h":28}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":42,"h":28}, + "sourceSize": {"w":42,"h":28} +}, +"tank2b_body.png": +{ + "frame": {"x":234,"y":304,"w":42,"h":48}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":42,"h":48}, + "sourceSize": {"w":42,"h":48} +}, +"tank2b_body_destroyed.png": +{ + "frame": {"x":278,"y":288,"w":42,"h":48}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":42,"h":48}, + "sourceSize": {"w":42,"h":48} +}, +"tank2b_body_destroyed_shadow.png": +{ + "frame": {"x":234,"y":254,"w":42,"h":48}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":42,"h":48}, + "sourceSize": {"w":42,"h":48} +}, +"tank2b_body_hit.png": +{ + "frame": {"x":292,"y":238,"w":42,"h":48}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":42,"h":48}, + "sourceSize": {"w":42,"h":48} +}, +"tank2b_body_shadow.png": +{ + "frame": {"x":292,"y":188,"w":42,"h":48}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":42,"h":48}, + "sourceSize": {"w":42,"h":48} +}, +"tank2b_dualgun.png": +{ + "frame": {"x":274,"y":70,"w":66,"h":66}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":66,"h":66}, + "sourceSize": {"w":66,"h":66} +}, +"tank2b_dualgun_destroyed.png": +{ + "frame": {"x":206,"y":70,"w":66,"h":66}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":66,"h":66}, + "sourceSize": {"w":66,"h":66} +}, +"tank2b_dualgun_hit.png": +{ + "frame": {"x":138,"y":70,"w":66,"h":66}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":66,"h":66}, + "sourceSize": {"w":66,"h":66} +}, +"tank2b_gun.png": +{ + "frame": {"x":70,"y":70,"w":66,"h":66}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":66,"h":66}, + "sourceSize": {"w":66,"h":66} +}, +"tank2b_gun_destroyed.png": +{ + "frame": {"x":2,"y":70,"w":66,"h":66}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":66,"h":66}, + "sourceSize": {"w":66,"h":66} +}, +"tank2b_gun_hit.png": +{ + "frame": {"x":410,"y":2,"w":66,"h":66}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":66,"h":66}, + "sourceSize": {"w":66,"h":66} +}, +"tank3_body.png": +{ + "frame": {"x":58,"y":481,"w":26,"h":39}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":26,"h":39}, + "sourceSize": {"w":26,"h":39} +}, +"tank3_body_destroyed.png": +{ + "frame": {"x":30,"y":481,"w":26,"h":39}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":26,"h":39}, + "sourceSize": {"w":26,"h":39} +}, +"tank3_body_destroyed_shadow.png": +{ + "frame": {"x":2,"y":481,"w":26,"h":39}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":26,"h":39}, + "sourceSize": {"w":26,"h":39} +}, +"tank3_body_hit.png": +{ + "frame": {"x":198,"y":440,"w":26,"h":39}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":26,"h":39}, + "sourceSize": {"w":26,"h":39} +}, +"tank3_body_shadow.png": +{ + "frame": {"x":170,"y":440,"w":26,"h":39}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":26,"h":39}, + "sourceSize": {"w":26,"h":39} +}, +"tank3_gun.png": +{ + "frame": {"x":452,"y":230,"w":56,"h":56}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":56,"h":56}, + "sourceSize": {"w":56,"h":56} +}, +"tank3_gun_destroyed.png": +{ + "frame": {"x":394,"y":186,"w":56,"h":56}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":56,"h":56}, + "sourceSize": {"w":56,"h":56} +}, +"tank3_gun_hit.png": +{ + "frame": {"x":336,"y":186,"w":56,"h":56}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":56,"h":56}, + "sourceSize": {"w":56,"h":56} +}, +"tank3_track.png": +{ + "frame": {"x":290,"y":478,"w":22,"h":28}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":22,"h":28}, + "sourceSize": {"w":22,"h":28} +}, +"tank3b_body.png": +{ + "frame": {"x":142,"y":440,"w":26,"h":39}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":26,"h":39}, + "sourceSize": {"w":26,"h":39} +}, +"tank3b_body_destroyed.png": +{ + "frame": {"x":114,"y":440,"w":26,"h":39}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":26,"h":39}, + "sourceSize": {"w":26,"h":39} +}, +"tank3b_body_hit.png": +{ + "frame": {"x":86,"y":440,"w":26,"h":39}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":26,"h":39}, + "sourceSize": {"w":26,"h":39} +}, +"tank3b_gun.png": +{ + "frame": {"x":234,"y":138,"w":56,"h":56}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":56,"h":56}, + "sourceSize": {"w":56,"h":56} +}, +"tank3b_gun_destroyed.png": +{ + "frame": {"x":176,"y":138,"w":56,"h":56}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":56,"h":56}, + "sourceSize": {"w":56,"h":56} +}, +"tank3b_gun_hit.png": +{ + "frame": {"x":118,"y":138,"w":56,"h":56}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":56,"h":56}, + "sourceSize": {"w":56,"h":56} +}, +"tank3b_track.png": +{ + "frame": {"x":290,"y":448,"w":22,"h":28}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":22,"h":28}, + "sourceSize": {"w":22,"h":28} +}, +"tank3c_body.png": +{ + "frame": {"x":58,"y":440,"w":26,"h":39}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":26,"h":39}, + "sourceSize": {"w":26,"h":39} +}, +"tank3c_body_destroyed.png": +{ + "frame": {"x":30,"y":440,"w":26,"h":39}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":26,"h":39}, + "sourceSize": {"w":26,"h":39} +}, +"tank3c_body_hit.png": +{ + "frame": {"x":2,"y":440,"w":26,"h":39}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":26,"h":39}, + "sourceSize": {"w":26,"h":39} +}, +"tank3c_gun.png": +{ + "frame": {"x":60,"y":138,"w":56,"h":56}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":56,"h":56}, + "sourceSize": {"w":56,"h":56} +}, +"tank3c_gun_destroyed.png": +{ + "frame": {"x":2,"y":138,"w":56,"h":56}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":56,"h":56}, + "sourceSize": {"w":56,"h":56} +}, +"tank3c_gun_hit.png": +{ + "frame": {"x":400,"y":128,"w":56,"h":56}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":56,"h":56}, + "sourceSize": {"w":56,"h":56} +}, +"tank3c_track.png": +{ + "frame": {"x":290,"y":418,"w":22,"h":28}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":22,"h":28}, + "sourceSize": {"w":22,"h":28} +}, +"tank3d_body.png": +{ + "frame": {"x":370,"y":540,"w":26,"h":39}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":26,"h":39}, + "sourceSize": {"w":26,"h":39} +}, +"tank3d_body_destroyed.png": +{ + "frame": {"x":342,"y":530,"w":26,"h":39}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":26,"h":39}, + "sourceSize": {"w":26,"h":39} +}, +"tank3d_body_hit.png": +{ + "frame": {"x":314,"y":496,"w":26,"h":39}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":26,"h":39}, + "sourceSize": {"w":26,"h":39} +}, +"tank3d_gun.png": +{ + "frame": {"x":342,"y":128,"w":56,"h":56}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":56,"h":56}, + "sourceSize": {"w":56,"h":56} +}, +"tank3d_gun_destroyed.png": +{ + "frame": {"x":400,"y":70,"w":56,"h":56}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":56,"h":56}, + "sourceSize": {"w":56,"h":56} +}, +"tank3d_gun_hit.png": +{ + "frame": {"x":342,"y":70,"w":56,"h":56}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":56,"h":56}, + "sourceSize": {"w":56,"h":56} +}, +"tank3d_track.png": +{ + "frame": {"x":290,"y":388,"w":22,"h":28}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":22,"h":28}, + "sourceSize": {"w":22,"h":28} +}, +"truck1_body.png": +{ + "frame": {"x":258,"y":452,"w":30,"h":62}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":30,"h":62}, + "sourceSize": {"w":30,"h":62} +}, +"truck1_body_hit.png": +{ + "frame": {"x":226,"y":418,"w":30,"h":62}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":30,"h":62}, + "sourceSize": {"w":30,"h":62} +}, +"truck1_body_shadow.png": +{ + "frame": {"x":194,"y":376,"w":30,"h":62}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":30,"h":62}, + "sourceSize": {"w":30,"h":62} +}, +"truck1_destroyed.png": +{ + "frame": {"x":162,"y":376,"w":30,"h":62}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":30,"h":62}, + "sourceSize": {"w":30,"h":62} +}, +"truck1_destroyed_shadow.png": +{ + "frame": {"x":130,"y":376,"w":30,"h":62}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":30,"h":62}, + "sourceSize": {"w":30,"h":62} +}, +"truck1b_body.png": +{ + "frame": {"x":98,"y":376,"w":30,"h":62}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":30,"h":62}, + "sourceSize": {"w":30,"h":62} +}, +"truck1b_body_hit.png": +{ + "frame": {"x":66,"y":376,"w":30,"h":62}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":30,"h":62}, + "sourceSize": {"w":30,"h":62} +}, +"truck1b_destroyed.png": +{ + "frame": {"x":34,"y":376,"w":30,"h":62}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":30,"h":62}, + "sourceSize": {"w":30,"h":62} +}, +"truck1c_body.png": +{ + "frame": {"x":2,"y":376,"w":30,"h":62}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":30,"h":62}, + "sourceSize": {"w":30,"h":62} +}, +"truck1c_body_hit.png": +{ + "frame": {"x":474,"y":524,"w":30,"h":62}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":30,"h":62}, + "sourceSize": {"w":30,"h":62} +}, +"truck1c_destroyed.png": +{ + "frame": {"x":442,"y":524,"w":30,"h":62}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":30,"h":62}, + "sourceSize": {"w":30,"h":62} +}, +"truck2_body.png": +{ + "frame": {"x":410,"y":524,"w":30,"h":62}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":30,"h":62}, + "sourceSize": {"w":30,"h":62} +}, +"truck2_body_hit.png": +{ + "frame": {"x":378,"y":476,"w":30,"h":62}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":30,"h":62}, + "sourceSize": {"w":30,"h":62} +}, +"truck2_body_shadow.png": +{ + "frame": {"x":346,"y":466,"w":30,"h":62}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":30,"h":62}, + "sourceSize": {"w":30,"h":62} +}, +"truck2_destroyed.png": +{ + "frame": {"x":314,"y":432,"w":30,"h":62}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":30,"h":62}, + "sourceSize": {"w":30,"h":62} +}, +"truck2_destroyed_shadow.png": +{ + "frame": {"x":258,"y":388,"w":30,"h":62}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":30,"h":62}, + "sourceSize": {"w":30,"h":62} +}, +"truck2b_body.png": +{ + "frame": {"x":226,"y":354,"w":30,"h":62}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":30,"h":62}, + "sourceSize": {"w":30,"h":62} +}, +"truck2b_body_hit.png": +{ + "frame": {"x":194,"y":312,"w":30,"h":62}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":30,"h":62}, + "sourceSize": {"w":30,"h":62} +}, +"truck2b_destroyed.png": +{ + "frame": {"x":162,"y":312,"w":30,"h":62}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":30,"h":62}, + "sourceSize": {"w":30,"h":62} +}, +"truck2c_body.png": +{ + "frame": {"x":130,"y":312,"w":30,"h":62}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":30,"h":62}, + "sourceSize": {"w":30,"h":62} +}, +"truck2c_body_hit.png": +{ + "frame": {"x":98,"y":312,"w":30,"h":62}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":30,"h":62}, + "sourceSize": {"w":30,"h":62} +}, +"truck2c_destroyed.png": +{ + "frame": {"x":66,"y":312,"w":30,"h":62}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":30,"h":62}, + "sourceSize": {"w":30,"h":62} +}, +"truck3_body.png": +{ + "frame": {"x":34,"y":312,"w":30,"h":62}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":30,"h":62}, + "sourceSize": {"w":30,"h":62} +}, +"truck3_body_hit.png": +{ + "frame": {"x":2,"y":312,"w":30,"h":62}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":30,"h":62}, + "sourceSize": {"w":30,"h":62} +}, +"truck3_body_shadow.png": +{ + "frame": {"x":478,"y":460,"w":30,"h":62}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":30,"h":62}, + "sourceSize": {"w":30,"h":62} +}, +"truck3_destroyed.png": +{ + "frame": {"x":446,"y":460,"w":30,"h":62}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":30,"h":62}, + "sourceSize": {"w":30,"h":62} +}, +"truck3_destroyed_shadow.png": +{ + "frame": {"x":414,"y":460,"w":30,"h":62}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":30,"h":62}, + "sourceSize": {"w":30,"h":62} +}, +"truck3b_body.png": +{ + "frame": {"x":462,"y":396,"w":30,"h":62}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":30,"h":62}, + "sourceSize": {"w":30,"h":62} +}, +"truck3b_body_hit.png": +{ + "frame": {"x":382,"y":412,"w":30,"h":62}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":30,"h":62}, + "sourceSize": {"w":30,"h":62} +}, +"truck3b_destroyed.png": +{ + "frame": {"x":430,"y":396,"w":30,"h":62}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":30,"h":62}, + "sourceSize": {"w":30,"h":62} +}, +"truck3c_body.png": +{ + "frame": {"x":350,"y":402,"w":30,"h":62}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":30,"h":62}, + "sourceSize": {"w":30,"h":62} +}, +"truck3c_body_hit.png": +{ + "frame": {"x":478,"y":66,"w":30,"h":62}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":30,"h":62}, + "sourceSize": {"w":30,"h":62} +}, +"truck3c_destroyed.png": +{ + "frame": {"x":478,"y":2,"w":30,"h":62}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":30,"h":62}, + "sourceSize": {"w":30,"h":62} +}, +"truck_track.png": +{ + "frame": {"x":86,"y":481,"w":24,"h":23}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":24,"h":23}, + "sourceSize": {"w":24,"h":23} +}}, +"meta": { + "app": "http://www.texturepacker.com", + "version": "1.0", + "image": "ground_units.png", + "format": "RGBA8888", + "size": {"w":512,"h":1024}, + "scale": "1", + "smartupdate": "$TexturePacker:SmartUpdate:0da088f23b1454869c6ff25aabebeda2$" +} +} diff --git a/Games/Debris_Dodge/media/ground_units.png b/Games/Debris_Dodge/media/ground_units.png new file mode 100644 index 0000000000..c9c32a48a4 Binary files /dev/null and b/Games/Debris_Dodge/media/ground_units.png differ diff --git a/Games/Debris_Dodge/media/menu_music.ogg b/Games/Debris_Dodge/media/menu_music.ogg new file mode 100644 index 0000000000..d3706a6a10 Binary files /dev/null and b/Games/Debris_Dodge/media/menu_music.ogg differ diff --git a/Games/Debris_Dodge/media/metal_interaction2.wav b/Games/Debris_Dodge/media/metal_interaction2.wav new file mode 100644 index 0000000000..8519c81c36 Binary files /dev/null and b/Games/Debris_Dodge/media/metal_interaction2.wav differ diff --git a/Games/Debris_Dodge/media/names.txt b/Games/Debris_Dodge/media/names.txt new file mode 100644 index 0000000000..bae56c1746 --- /dev/null +++ b/Games/Debris_Dodge/media/names.txt @@ -0,0 +1,279 @@ +Strippy +Boffo +Buffo +Drips +Porno +Mentos +Felches +Grout +Oboe +Bumbo +Salvo +Drowny +Viagra +Acetone +Zarathustra +Styptic +Recidivo +Unctuous +Reflux +Maalox +Scurvy +Rickets +Noriega +Polyp +Garbo +Tantric +Phalanx +Bondage +Asbestos +Trenton +Aspic +Marfin +Merkin +Dropsy +Ponzi +Garrotte +Calphalon +Juvie +Schmoey Schmoe-head +Nixon +Droppo +Lesions +Boner +Clowny +Clooney +Frowny +Enfilade +Mojo +Ploop +Contusions +Animus +Pooey Poo-head +Weiner +Bac-o’s +Buckminster Fuller +Domey +Subjunctive Predicate +Pestilence +Fury +Ninja +Platano +Melons +Nutout +Dangles +Tipsy +Steerage +Dunkirk +Antietam +Chins +Genuflection +Kreplach +Pringles +Shingles +Viscera +Viggo +Kielbasa +Sterno +Salieri +Flaubert +Gaspachio +Chagganooga +Nougat +Lumps +Chewie +Wookie +Kotter +Dracula +Han Solo +Jabba +Lando +Alone +Felony +Diaspora +Perspicacity +Tapenade +Detritus +Jaundice +Sbarro +Osmosis +Achtung! +Stabbo +Oleo +Tampopo +Nagano +Synergy +Effluvia +Leg Warmers +Roboto +Prozac +Eukenuba +Retsin +Rogaine +Ethel Merman +Topical Crème +Ointment +Cold Compress +Ace Bandage +Bourbon +Bowels +Brundlefly +Platanos +My People +Mo’ Broccoli +Borracho +Smuts +Nehi +Olestra +Greedo +Coolio +Consiglieri +Dinner Bell +Maligno +Angelos +Parabola +Velcro +Nubbins +Scuppers +Kippers +Flautas +Blintzes +Decoupage +Sprockets +Lupins +Gorditas +Funyuns +Manicles +Drano +Alcoa +Spores +Spleens +Placenta +Melanoma +Pathos +Explosivo +Feces +Epoxy +Ruminant +Calamari +Toffifay +Proletariat +Cop Rock +Tunisia +Cabal +Glasnost +Lanolin +Surfeit +Pillages +Acela +Wads +Bulges +Apshai +Zork +Socratic Method +Stoma +Bulldog +Bilbo +Stephen McNulty +Ball in +Schyler +Santyl +Fungible +Fergie +Verizon +Magma +Clown +Mature Content +Humpy +Flabby +Meniscus +Mellotron +M.C. Escher +Morbidly Obese +Fluffer +Strychnine +Tolstoy +String Theory +Mastication +Corpuscle +Animatronic Abraham Lincoln +Arrears +No Lo Contendere +Top Copy is Yours +Wankel +Peristalsis +Next Stop Friendship Heights +Pompatus +T’aint +Repetitive Motion Disorder +Post-traumatic Stress Disorder +Aphasia +Enlarged Prostate +Irritable Bowel Syndrome +Feline Distemper +Riboflavin +Flintstones Chewable Vitamins +Metamucils +Premature Ejaculation +Erection Lasting More Than 4 Hours +The +Quadratic Equation +Stephen Hawking +Hello Larry +Mildly Amusing +Scary to Children +Harmful If Swallowed +Do Not Take Internally +Courtesy Flush +Chuck Norris +Collect all Four +Buckaroo Bonsai Reference +Your Mom Just Died +Jonathan Coulton +Axis of Evil +Crystal Pepsi +Dr. Bob +FEMA +Broken Levee +Rhyming Couplet +Iambic Pentameter +Reforestation +Eustachian Tube +Trachea +Duodenum +Relapse +Dressing on the Side, Please, +High Fructose Corn Syrup +High Fiber Diet +Load Bearing Wall +Partially Hydrogenated +Reconstituted Meat Slurry +30,000 lbs of Bananas +Open-source Coding +Network Administrator +Subversive Meme +4th Grade Education +Conscientious Objector +Monkeydogs +Irregular Heartbeat +Asystole +Peak Oil +SEPTA IRA +Diversified Stock Portfolio +No-load Funds +0% APR for 12 Months +Zero-Sum Game +Nitrogen-fixing Crop Rotation +Frame-off Restoration +Acid Bath +Knights Templar +Mary Magdalene +Unexpected Plot Twist +Kennesaw Mountain Landis +Unintended Consequences +Odd-lot Purchases +Martyrs +Consenting Adults +Store-brand Taco Seasoning +Penultimate +It’s Not a Balloon It’s an Airship diff --git a/Games/Debris_Dodge/media/pickups.json b/Games/Debris_Dodge/media/pickups.json new file mode 100644 index 0000000000..c3cdd6acba --- /dev/null +++ b/Games/Debris_Dodge/media/pickups.json @@ -0,0 +1,68 @@ +{"frames": { + +"coin.png": +{ + "frame": {"x":2,"y":80,"w":25,"h":24}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":25,"h":24}, + "sourceSize": {"w":25,"h":24} +}, +"diagonal_gun.png": +{ + "frame": {"x":29,"y":54,"w":25,"h":24}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":25,"h":24}, + "sourceSize": {"w":25,"h":24} +}, +"life_up.png": +{ + "frame": {"x":2,"y":54,"w":25,"h":24}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":25,"h":24}, + "sourceSize": {"w":25,"h":24} +}, +"missile.png": +{ + "frame": {"x":29,"y":28,"w":25,"h":24}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":25,"h":24}, + "sourceSize": {"w":25,"h":24} +}, +"repair.png": +{ + "frame": {"x":2,"y":28,"w":25,"h":24}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":25,"h":24}, + "sourceSize": {"w":25,"h":24} +}, +"straight_gun.png": +{ + "frame": {"x":29,"y":2,"w":25,"h":24}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":25,"h":24}, + "sourceSize": {"w":25,"h":24} +}, +"wingman.png": +{ + "frame": {"x":2,"y":2,"w":25,"h":24}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":25,"h":24}, + "sourceSize": {"w":25,"h":24} +}}, +"meta": { + "app": "http://www.codeandweb.com/texturepacker ", + "version": "1.0", + "image": "pickups.png", + "format": "RGBA8888", + "size": {"w":64,"h":128}, + "scale": "0.5", + "smartupdate": "$TexturePacker:SmartUpdate:5bccec5fb5decb53145ba22504d88edd:1/1$" +} +} diff --git a/Games/Debris_Dodge/media/pickups.png b/Games/Debris_Dodge/media/pickups.png new file mode 100644 index 0000000000..4cdd27e732 Binary files /dev/null and b/Games/Debris_Dodge/media/pickups.png differ diff --git a/Games/Debris_Dodge/media/top_secret.ttf b/Games/Debris_Dodge/media/top_secret.ttf new file mode 100644 index 0000000000..fa8644287f Binary files /dev/null and b/Games/Debris_Dodge/media/top_secret.ttf differ diff --git a/Games/Debris_Dodge/media/trees.png b/Games/Debris_Dodge/media/trees.png new file mode 100644 index 0000000000..1d461258f2 Binary files /dev/null and b/Games/Debris_Dodge/media/trees.png differ diff --git a/Games/Debris_Dodge/media/trees_packed.json b/Games/Debris_Dodge/media/trees_packed.json new file mode 100644 index 0000000000..be7906b52e --- /dev/null +++ b/Games/Debris_Dodge/media/trees_packed.json @@ -0,0 +1,388 @@ +{"frames": { + +"tree_01.png": +{ + "frame": {"x":280,"y":183,"w":62,"h":66}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":2,"y":0,"w":62,"h":66}, + "sourceSize": {"w":68,"h":68} +}, +"tree_02.png": +{ + "frame": {"x":125,"y":3,"w":40,"h":38}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":2,"y":2,"w":40,"h":38}, + "sourceSize": {"w":44,"h":42} +}, +"tree_03.png": +{ + "frame": {"x":451,"y":115,"w":66,"h":64}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":0,"y":0,"w":66,"h":64}, + "sourceSize": {"w":68,"h":68} +}, +"tree_04.png": +{ + "frame": {"x":383,"y":115,"w":64,"h":64}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":2,"y":0,"w":64,"h":64}, + "sourceSize": {"w":68,"h":68} +}, +"tree_05.png": +{ + "frame": {"x":217,"y":55,"w":54,"h":52}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":0,"y":0,"w":54,"h":52}, + "sourceSize": {"w":54,"h":54} +}, +"tree_06.png": +{ + "frame": {"x":3,"y":55,"w":46,"h":48}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":46,"h":48}, + "sourceSize": {"w":46,"h":48} +}, +"tree_07.png": +{ + "frame": {"x":443,"y":55,"w":52,"h":56}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":2,"y":0,"w":52,"h":56}, + "sourceSize": {"w":56,"h":58} +}, +"tree_08.png": +{ + "frame": {"x":163,"y":55,"w":50,"h":50}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":0,"y":1,"w":50,"h":50}, + "sourceSize": {"w":50,"h":52} +}, +"tree_09.png": +{ + "frame": {"x":39,"y":3,"w":38,"h":38}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":0,"y":0,"w":38,"h":38}, + "sourceSize": {"w":40,"h":40} +}, +"tree_10.png": +{ + "frame": {"x":3,"y":183,"w":64,"h":64}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":0,"y":0,"w":64,"h":64}, + "sourceSize": {"w":66,"h":66} +}, +"tree_11.png": +{ + "frame": {"x":365,"y":3,"w":47,"h":48}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":0,"y":2,"w":47,"h":48}, + "sourceSize": {"w":47,"h":52} +}, +"tree_12.png": +{ + "frame": {"x":416,"y":3,"w":46,"h":48}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":46,"h":48}, + "sourceSize": {"w":46,"h":48} +}, +"tree_13.png": +{ + "frame": {"x":3,"y":3,"w":32,"h":32}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":32,"h":32}, + "sourceSize": {"w":32,"h":32} +}, +"tree_14.png": +{ + "frame": {"x":215,"y":3,"w":46,"h":44}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":46,"h":44}, + "sourceSize": {"w":46,"h":44} +}, +"tree_15.png": +{ + "frame": {"x":71,"y":183,"w":64,"h":64}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":0,"y":0,"w":64,"h":64}, + "sourceSize": {"w":66,"h":66} +}, +"tree_16.png": +{ + "frame": {"x":169,"y":3,"w":42,"h":42}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":3,"y":1,"w":42,"h":42}, + "sourceSize": {"w":48,"h":46} +}, +"tree_17.png": +{ + "frame": {"x":385,"y":55,"w":54,"h":54}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":0,"y":2,"w":54,"h":54}, + "sourceSize": {"w":54,"h":58} +}, +"tree_18.png": +{ + "frame": {"x":139,"y":183,"w":68,"h":64}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":1,"y":0,"w":68,"h":64}, + "sourceSize": {"w":70,"h":64} +}, +"tree_19.png": +{ + "frame": {"x":67,"y":115,"w":56,"h":58}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":0,"y":0,"w":56,"h":58}, + "sourceSize": {"w":56,"h":60} +}, +"tree_20.png": +{ + "frame": {"x":275,"y":55,"w":48,"h":52}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":1,"y":1,"w":48,"h":52}, + "sourceSize": {"w":52,"h":54} +}, +"tree_21.png": +{ + "frame": {"x":3,"y":115,"w":60,"h":56}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":0,"y":0,"w":60,"h":56}, + "sourceSize": {"w":64,"h":60} +}, +"tree_22.png": +{ + "frame": {"x":327,"y":55,"w":54,"h":54}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":0,"y":2,"w":54,"h":54}, + "sourceSize": {"w":54,"h":60} +}, +"tree_23.png": +{ + "frame": {"x":346,"y":183,"w":62,"h":66}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":0,"y":0,"w":62,"h":66}, + "sourceSize": {"w":64,"h":68} +}, +"tree_24.png": +{ + "frame": {"x":81,"y":3,"w":40,"h":38}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":0,"y":1,"w":40,"h":38}, + "sourceSize": {"w":40,"h":42} +}, +"tree_25.png": +{ + "frame": {"x":255,"y":115,"w":58,"h":62}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":0,"y":0,"w":58,"h":62}, + "sourceSize": {"w":60,"h":62} +}, +"tree_26.png": +{ + "frame": {"x":466,"y":3,"w":48,"h":48}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":0,"y":0,"w":48,"h":48}, + "sourceSize": {"w":50,"h":50} +}, +"tree_27.png": +{ + "frame": {"x":127,"y":115,"w":56,"h":60}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":1,"y":1,"w":56,"h":60}, + "sourceSize": {"w":60,"h":62} +}, +"tree_28.png": +{ + "frame": {"x":3,"y":257,"w":66,"h":70}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":1,"y":0,"w":66,"h":70}, + "sourceSize": {"w":70,"h":70} +}, +"tree_29.png": +{ + "frame": {"x":111,"y":55,"w":48,"h":50}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":2,"y":1,"w":48,"h":50}, + "sourceSize": {"w":52,"h":52} +}, +"tree_30.png": +{ + "frame": {"x":317,"y":115,"w":62,"h":62}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":1,"y":2,"w":62,"h":62}, + "sourceSize": {"w":66,"h":66} +}, +"tree_38.png": +{ + "frame": {"x":407,"y":341,"w":110,"h":114}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":0,"y":3,"w":110,"h":114}, + "sourceSize": {"w":110,"h":120} +}, +"tree_39.png": +{ + "frame": {"x":301,"y":341,"w":102,"h":114}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":0,"y":1,"w":102,"h":114}, + "sourceSize": {"w":106,"h":120} +}, +"tree_40.png": +{ + "frame": {"x":211,"y":183,"w":65,"h":65}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":1,"y":0,"w":65,"h":65}, + "sourceSize": {"w":67,"h":65} +}, +"tree_41.png": +{ + "frame": {"x":151,"y":257,"w":74,"h":72}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":1,"y":0,"w":74,"h":72}, + "sourceSize": {"w":82,"h":76} +}, +"tree_42.png": +{ + "frame": {"x":73,"y":257,"w":74,"h":70}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":2,"y":2,"w":74,"h":70}, + "sourceSize": {"w":78,"h":76} +}, +"tree_43.png": +{ + "frame": {"x":385,"y":257,"w":78,"h":78}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":3,"y":1,"w":78,"h":78}, + "sourceSize": {"w":84,"h":82} +}, +"tree_44.png": +{ + "frame": {"x":195,"y":341,"w":102,"h":108}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":2,"y":2,"w":102,"h":108}, + "sourceSize": {"w":110,"h":112} +}, +"tree_46.png": +{ + "frame": {"x":467,"y":257,"w":70,"h":80}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":1,"y":8,"w":70,"h":80}, + "sourceSize": {"w":76,"h":90} +}, +"tree_47.png": +{ + "frame": {"x":53,"y":55,"w":54,"h":50}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":2,"y":2,"w":54,"h":50}, + "sourceSize": {"w":60,"h":56} +}, +"tree_48.png": +{ + "frame": {"x":265,"y":3,"w":46,"h":46}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":6,"y":3,"w":46,"h":46}, + "sourceSize": {"w":60,"h":56} +}, +"tree_49.png": +{ + "frame": {"x":315,"y":3,"w":46,"h":46}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":6,"y":5,"w":46,"h":46}, + "sourceSize": {"w":60,"h":56} +}, +"tree_50.png": +{ + "frame": {"x":412,"y":183,"w":68,"h":70}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":0,"y":2,"w":68,"h":70}, + "sourceSize": {"w":70,"h":76} +}, +"tree_51.png": +{ + "frame": {"x":229,"y":257,"w":74,"h":74}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":4,"y":1,"w":74,"h":74}, + "sourceSize": {"w":86,"h":78} +}, +"tree_52.png": +{ + "frame": {"x":187,"y":115,"w":64,"h":62}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":1,"y":4,"w":64,"h":62}, + "sourceSize": {"w":68,"h":68} +}, +"tree_53.png": +{ + "frame": {"x":3,"y":341,"w":94,"h":82}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":0,"y":5,"w":94,"h":82}, + "sourceSize": {"w":94,"h":98} +}, +"tree_54.png": +{ + "frame": {"x":101,"y":341,"w":90,"h":90}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":2,"y":0,"w":90,"h":90}, + "sourceSize": {"w":94,"h":90} +}, +"tree_55.png": +{ + "frame": {"x":307,"y":257,"w":74,"h":78}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":0,"y":2,"w":74,"h":78}, + "sourceSize": {"w":76,"h":82} +}}, +"meta": { + "app": "http://www.codeandweb.com/texturepacker ", + "version": "1.0", + "image": "trees_packed.png", + "format": "RGBA8888", + "size": {"w":540,"h":458}, + "scale": "1", + "smartupdate": "$TexturePacker:SmartUpdate:d8b078a9b489ef94c8641390211543b9:adf8ffbc3d0a646442fdb1855a36ac0e:a7653fb3592c74bd7bf4b33200c676f1$" +} +} diff --git a/Games/Debris_Dodge/media/trees_packed.png b/Games/Debris_Dodge/media/trees_packed.png new file mode 100644 index 0000000000..24001c4505 Binary files /dev/null and b/Games/Debris_Dodge/media/trees_packed.png differ diff --git a/Games/Debris_Dodge/media/water.png b/Games/Debris_Dodge/media/water.png new file mode 100644 index 0000000000..7c4934cb0d Binary files /dev/null and b/Games/Debris_Dodge/media/water.png differ diff --git a/Games/Debris_Dodge/spec/misc/aabb_spec.rb b/Games/Debris_Dodge/spec/misc/aabb_spec.rb new file mode 100644 index 0000000000..1ba5e3bcc3 --- /dev/null +++ b/Games/Debris_Dodge/spec/misc/aabb_spec.rb @@ -0,0 +1,85 @@ +require_relative '../../lib/misc/axis_aligned_bounding_box' +describe AxisAlignedBoundingBox do + + let(:center) { [5, 5] } + let(:half_dimension) { [10, 10] } + let(:box) { AxisAlignedBoundingBox.new( + center, half_dimension) } + + let(:point1) { [4, 7] } + let(:point2) { [0, 0] } + let(:point3) { [10, 10] } + let(:point4) { [0, 10] } + let(:point5) { [10, 0] } + + let(:point6) { [-2, 7] } + let(:point7) { [0, 11] } + let(:point8) { [11, 11] } + let(:point9) { [0, 11] } + let(:point10) { [11, 0] } + let(:point11) { [3, 15] } + let(:point12) { [11, 4] } + let(:point13) { [1, -4] } + let(:point14) { [-1, -4] } + + describe '#contains?' do + it 'detects containing point' do + expect(box.contains?(point1)).to be_truthy + expect(box.contains?(point2)).to be_truthy + expect(box.contains?(point3)).to be_truthy + expect(box.contains?(point4)).to be_truthy + expect(box.contains?(point5)).to be_truthy + end + + it 'does not detect points out of bounds' do + expect(box.contains?(point6)).to be_falsy + expect(box.contains?(point8)).to be_falsy + expect(box.contains?(point7)).to be_falsy + expect(box.contains?(point9)).to be_falsy + expect(box.contains?(point10)).to be_falsy + expect(box.contains?(point11)).to be_falsy + expect(box.contains?(point12)).to be_falsy + expect(box.contains?(point13)).to be_falsy + expect(box.contains?(point14)).to be_falsy + end + end + + describe '#intersects?' do + # center within box + let(:box1) { AxisAlignedBoundingBox.new( + [8, 8], [10, 12]) } + # center out of boundaries + let(:box2) { AxisAlignedBoundingBox.new( + [12, 12], [15, 15]) } + let(:box2_1) { AxisAlignedBoundingBox.new( + [-5, -5], [1, 1]) } + # touching corners + let(:box3) { AxisAlignedBoundingBox.new( + [-1, -1], [0, 0]) } + # out of bounds + let(:box4) { AxisAlignedBoundingBox.new( + [15, 15], [17, 17]) } + let(:box5) { AxisAlignedBoundingBox.new( + [-5, -5], [-1, -1]) } + let(:box6) { AxisAlignedBoundingBox.new( + [5, 12], [6, 13]) } + + + it 'intersects with itself' do + expect(box.intersects?(box)).to be_truthy + end + + it 'detects intersecting boxes' do + expect(box.intersects?(box1)).to be_truthy + expect(box.intersects?(box2)).to be_truthy + expect(box.intersects?(box2_1)).to be_truthy + expect(box.intersects?(box3)).to be_truthy + end + + it 'does not detect interesections out of bounds' do + expect(box.intersects?(box4)).to be_falsy + expect(box.intersects?(box5)).to be_falsy + expect(box.intersects?(box6)).to be_falsy + end + end +end diff --git a/Games/Debris_Dodge/spec/misc/quad_tree_spec.rb b/Games/Debris_Dodge/spec/misc/quad_tree_spec.rb new file mode 100644 index 0000000000..d28af31ffc --- /dev/null +++ b/Games/Debris_Dodge/spec/misc/quad_tree_spec.rb @@ -0,0 +1,137 @@ +class GameObject + attr_accessor :x, :y + def initialize(x, y) + @x, @y = x, y + end + + def location + [@x, @y] + end +end + +require_relative '../../lib/misc/axis_aligned_bounding_box' +require_relative '../../lib/misc/quad_tree' + +describe QuadTree do + let(:box) { AxisAlignedBoundingBox.new( + [5, 5], [10, 10]) } + let(:tree) { QuadTree.new(box) } + + let(:location) { [5, 5] } + let(:object) { GameObject.new(*location) } + + describe '#insert' do + subject { tree.insert(object) } + + context 'around zero coordinates' do + let(:box) { AxisAlignedBoundingBox.new( + [0, 0], [10, 10]) } + let(:location) { [0, 0] } + + it 'inserts in the middle' do + expect(subject).to be_truthy + end + end + + context 'object in center' do + it 'gets inserted' do + expect(subject).to be_truthy + end + end + + context 'object in corner' do + let(:location) { [10, 10] } + it 'gets inserted' do + expect(subject).to be_truthy + end + end + + context 'object out of bounds' do + let(:location) { [11, 11] } + it 'does not get inserted' do + expect(subject).to be_falsy + end + end + + context 'several objects' do + subject { tree.query_range(box) } + context 'to different locations' do + before do + 50.times do |i| + tree.insert( + GameObject.new( + rand(0..10), + rand(0..10))) + end + end + it 'inserts all' do + expect(subject.size).to eq 50 + end + end + + context 'to same location' do + before { 5.times { tree.insert(object.dup) } } + + it 'still inserts all' do + expect(subject.size).to eq 5 + end + end + end + end + + describe '#query_range' do + let(:query_params) { [[5, 5], [10, 10]] } + let(:query_box) { AxisAlignedBoundingBox.new(*query_params) } + subject { tree.query_range(query_box) } + + context 'empty tree' do + it 'returns empty array' do + should be_empty + end + end + + context 'single object' do + before { tree.insert(object) } + + context 'is found' do + let(:query_params) do + [object.location, object.location.map { |c| c + 1 }] + end + end + end + end + + describe '#remove' do + context 'single object' do + before do + tree.insert(object) + tree.remove(object) + end + subject { tree.query_range(box) } + + it 'removes it' do + expect(subject.size).to equal(0) + end + end + + context 'all objects' do + before do + 50.times do + tree.insert( + GameObject.new( + rand(0..10), + rand(0..10))) + end + end + subject { tree.query_range(box) } + + it 'removes it' do + expect(subject.size).to equal(50) + subject.each do |ob| + expect(tree.remove(ob)).to be_truthy + end + expect(tree.query_range(box).size).to equal(0) + end + end + end +end diff --git a/Games/Debris_Dodge/tank_island.gemspec b/Games/Debris_Dodge/tank_island.gemspec new file mode 100644 index 0000000000..086617cadd --- /dev/null +++ b/Games/Debris_Dodge/tank_island.gemspec @@ -0,0 +1,30 @@ +# coding: utf-8 +lib = File.expand_path('../lib', __FILE__) +$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) + +Gem::Specification.new do |spec| + spec.name = "tank_island" + spec.version = '1.0.5' + spec.authors = ["Tomas Varaneckas"] + spec.email = ["tomas.varaneckas@gmail.com"] + spec.summary = %q{Top down 2D shooter game that involves blowing up tanks} + spec.description = <<-EOS + This is a game built with Gosu library while writing "Developing Games With Ruby" book. + You can get the book at https://leanpub.com/developing-games-with-ruby + EOS + spec.homepage = "https://leanpub.com/developing-games-with-ruby" + spec.license = "MIT" + + spec.files = `git ls-files -z`.split("\x0") + spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) } + spec.test_files = spec.files.grep(%r{^(test|spec|features)/}) + spec.require_paths = ["lib"] + + spec.add_development_dependency "bundler", "~> 1.6" + spec.add_development_dependency "rake", "~> 10.0" + + spec.add_runtime_dependency 'gosu', "~> 0.15.2" + spec.add_runtime_dependency 'rmagick' + spec.add_runtime_dependency 'gosu_texture_packer' + spec.add_runtime_dependency 'perlin_noise' +end