#! /usr/bin/ruby #========================================================== # galint.rb - Juego de naves usando la biblioteca Gosu #---------------------------------------------------------- # Tomando como base Tutorial.rb, script que forma parte de # los ejemplos que acompañan a la biblioteca Gosu. # Proyecto en: http://code.google.com/p/gosu/ #========================================================== # FJA - neocipres@gmail.com Diciembre de 2010 #========================================================== require 'rubygems' require 'gosu' XMAX = 800 YMAX = 600 DATOS = '/home/paco/prgdgnu/ruby/gosu/galint/rec/' module ZOrder Background, Star, Foton, Player, UI = *0..4 end class Nube attr_reader :x, :y, :t def initialize(window, x, y, vx, vy, t) @imagen = Gosu::Image.new(window, "#{DATOS}nube.png", false) @x, @y = x, y @vx, @vy = vx, vy @t = t end def move @x += @vx @y += @vy @x %= XMAX @y %= YMAX end def draw @imagen.draw_rot(@x, @y, ZOrder::Star, 0) end end class Explosion attr_reader :t def initialize(window, x, y, t) @imagen = Gosu::Image.new(window, "#{DATOS}exp.png", false) @x = x @y = y @t = t end def draw @imagen.draw_rot(@x, @y, ZOrder::Foton, 0) end end class Star attr_reader :x, :y, :vel_x, :vel_y def initialize(animation, vx, vy) @animation = animation @color = Gosu::Color.new(0xff000000) @color.red = rand(255 - 40) + 40 @color.green = rand(255 - 40) + 40 @color.blue = rand(255 - 40) + 40 @x = rand * XMAX @y = rand * YMAX @vel_x, @vel_y = vx, vy end def draw img = @animation[Gosu::milliseconds / 100 % @animation.size] img.draw(@x - img.width / 2.0, @y - img.height / 2.0, ZOrder::Star, 1, 1, @color, :additive) end def move @x += @vel_x @y += @vel_y end def Star.destruir(estrellas) # Método de clase estrellas.reject! {|e| e.x < 0 or e.x > XMAX or e.y < 0 or e.y > YMAX} end def exp_stars(foton) if Gosu::distance(@x, @y, foton.x, foton.y) < 5 then true else false end end end class Foton attr_reader :x, :y def initialize(window, vx, vy) @imagen = Gosu::Image.new(window, "#{DATOS}foton.png", false) @x = @y = @angle = 0.0 @vel_x, @vel_y = vx, vy end def pos(x,y) @x, @y = x, y end def move @x += @vel_x @y += @vel_y end def Foton.destruir(fotones) # Método de clase fotones.reject! {|f| f.x < 0 or f.x > XMAX or f.y < 0 or f.y > YMAX} end def draw @imagen.draw_rot(@x, @y, ZOrder::Foton, @angle) end end class Player attr_reader :score, :vel_x, :vel_y, :x, :y, :angle, :fin, :tf def initialize(window) @imagen = Gosu::Image.new(window, "#{DATOS}nave.bmp", false) @imgexp = Gosu::Image.new(window, "#{DATOS}exp.png", false) @recs = Gosu::Sample.new(window, "#{DATOS}slurp.wav") @x = @y = @vel_x = @vel_y = @angle = 0.0 @score = 0 @fin = 0 end def puntos(p) @score += p end def pos(x, y) @x, @y = x, y end def turn_left @angle -= 2.5 end def turn_right @angle += 2.5 end def accelerate @vel_x += Gosu::offset_x(@angle, 0.3) @vel_y += Gosu::offset_y(@angle, 0.3) end def move(vx,vy) @x += vx @y += vy @x %= XMAX # Permite que la nave no se escape de la ventana @y %= YMAX end def stop @vel_x *= 0.65 @vel_y *= 0.65 end def colector_nubes(nubes) nubes.reject! do |n| if Gosu::distance(@x, @y, n.x, n.y) < 15 then @score += 20 @recs.play true else false end end end def draw @imagen.draw_rot(@x, @y, ZOrder::Player, @angle) end def kill(estrellas) estrellas.each do |e| if Gosu::distance(@x, @y, e.x, e.y) < 15 then @fin = 1 @tf = Time.now @imagen = @imgexp end end end end class GameWindow < Gosu::Window def initialize super(XMAX, YMAX, false) self.caption = "Interceptor Galáctico" # Imágenes y sonidos @imagen_fondo = Gosu::Image.new(self, "#{DATOS}fondo.png", true) @laser = Gosu::Sample.new(self, "#{DATOS}laser.wav") @exps = Gosu::Sample.new(self, "#{DATOS}exp.wav") @ti = Time.now # Contenedores de sprites @fotones = [] @explosiones = [] @nubes = [] @star_anim = Gosu::Image::load_tiles(self, "#{DATOS}star.png", 25, 25, false) @stars = Array.new @n, @nx, @ny, @vx, @vy = 0 @player = Player.new(self) @player.pos(XMAX/2, YMAX/2) @font = Gosu::Font.new(self, Gosu::default_font_name, 20) @ffont = Gosu::Font.new(self, Gosu::default_font_name, 48) end def update if @player.fin == 0 then if button_down? Gosu::KbLeft or button_down? Gosu::GpLeft then @player.turn_left end if button_down? Gosu::KbRight or button_down? Gosu::GpRight then @player.turn_right end if button_down? Gosu::KbUp or button_down? Gosu::GpButton0 then @player.accelerate end end # Movimiento de los sprites @player.move(@player.vel_x,@player.vel_y) if @player.fin == 0 if !@fotones.empty? then @fotones.each {|f| f.move} Foton.destruir(@fotones) end @nubes.each {|n| n.move} if !@nubes.empty? if !@stars.empty? then @stars.each {|s| s.move} Star.destruir(@stars) # Controla la colisión fotón - estrella @fotones.each do |f| @stars.reject! do |s| exp = s.exp_stars(f) if exp then f.pos(-5,-5) t = Time.now @explosion = Explosion.new(self, s.x, s.y, t) @explosiones << @explosion @exps.play @nube = Nube.new(self, s.x, s.y, s.vel_x, s.vel_y, t) @nubes << @nube if s.vel_x == 0 && s.vel_y == 0 then @player.puntos(5) else @player.puntos(10) end end end end end # Controla la recogida de nubes @player.colector_nubes(@nubes) # Controla la duración de la explosión y de la nube @explosiones.reject!{|e| Time.now - e.t > 1} @nubes.reject!{|n| Time.now - n.t > 9} # Controla el número y la velocidad de las estrellas @n = rand(299) @nx = rand(3) @ny = rand(3) case @nx when 0 @vx = 0 when 1 @vx = 1 when 2 @vx = -1 end case @ny when 0 @vy = 0 when 1 @vy = 1 when 2 @vy = -1 end # Controla la dificultad del juego @tiempo = (Time.now - @ti).to_i if @tiempo > 180 then @gd = 10 elsif @tiempo > 60 && @tiempo < 180 then @gd = 7 else @gd = 4 end if @n < @gd and @stars.size < 25 then @stars.push(Star.new(@star_anim, @vx, @vy)) end # Controla el fin del juego @player.kill(@stars) if !@stars.empty? && @player.fin == 0 if @player.fin == 1 then @exps.play if (Time.now - @player.tf) < 2 close if (Time.now - @player.tf) > 9 end end def draw @imagen_fondo.draw(0,0,ZOrder::Background) @player.draw @fotones.each {|f| f.draw} @stars.each {|s| s.draw} @explosiones.each {|e| e.draw} @nubes.each {|n| n.draw} # Información en pantalla @font.draw("Estrellas: #{@stars.size}", 10, 10, ZOrder::UI, 1.0, 1.0, 0xff00ffff) @font.draw("Puntos: #{@player.score}", 120, 10, ZOrder::UI, 1.0, 1.0, 0xff00ffff) @font.draw("Tiempo: #{@tiempo}", XMAX - 150, 10, ZOrder::UI, 1.0, 1.0, 0xff00ffff) if @player.fin == 1 then @ffont.draw("Nave destruida... Game Over !!!", 70, YMAX/2, ZOrder::UI, 1.0, 1.0, 0xffff0000) end end def button_down(id) case id when Gosu::KbEscape close when Gosu::KbDown @player.stop when Gosu::KbSpace if @player.fin == 0 then @foton = Foton.new( self, Gosu::offset_x(@player.angle, 5), Gosu::offset_y(@player.angle, 5)) @foton.pos(@player.x, @player.y) @fotones << @foton @laser.play end end end end window = GameWindow.new window.show