Como les comentaba en el post anterior, comencé a programar un pequeño juego en mis ratos libres. Para esto utilicé la librería Gosu, que hace que esto sea una tarea bastante sencilla.
Comenzando
Para mi juego dividí la aplicación en 5 clases, una para definir el entorno o sea el juego en sí, otra el mundo donde esta el código encargado de manejar la gravedad y eventualmente las colisiones entre objetos; luego esta la clase actor, donde defino cosas comunes a todos los actores que aparecen en el juego (bloques, personajes, NPCs? ) y dos clases que derivan de esta, player y block. La clase esta comentada explicando que hace cada cosa:
require "gosu" require_relative "./lib/player" require_relative "./lib/block" require_relative "./lib/world" class GameWindow < Gosu::Window def initialize super 800, 600 self.caption = "Game test" @world = World.new() # aquí inicializamos la clase mundo y le asignamos un par de valores @world.viewport_height = self.height @world.viewport_width = self.width #Creamos un jugador y lo añadimos a nuestro mundo @player = Player.new @player.warp(200,@world.horizon ) @world.add_actor(@player) # Creamos un bloque y lo añadimos a nuestro mundo @block = Block.new @block.place(300,@world.horizon + @block.height) @world.add_actor(@block) # seteamos un fondo @background_image = Gosu::Image.new("assets/images/bg.png", :tileable => true) end # El método update se encarga de capturar los distintos eventos de teclado # también llamamos al metodo de mundo gravity, que se encargará de que los objetos caigan # por ultimo el método move de la clase player se encargara de que el jugador se mueva def update if Gosu::button_down? Gosu::KbLeft @player.accelerate :left end if Gosu::button_down? Gosu::KbRight @player.accelerate :right end if Gosu::button_down? Gosu::KbUp if !@player.falling @player.jump end end @world.gravity @player.move end # El método draw se encarga de dibujar todos los actores del mundo así como la imágen de fondo que hemos escogido def draw @world.show @background_image.draw(0, 0, 0) end end #Instanciamos la ventana de juego y mostramos window = GameWindow.new window.show
La clase actor
La clase actor define propiedades comunes de los actores del juego. Por ahora no hace mucho más que proveer un método comun de acceder a las propiedades del ancho y alto de la sprite de cada actor
class Actor attr_accessor :sprite, :x, :y, :angle, :mass, :falling, :mid_air, :height def width @sprite.width end def height @sprite.height end end
La clase player
Nuestra clase player hereda de actor, tiene los métodos necesarios para: posicionar el jugador, iniciar la aceleración cuando el jugador realiza un movimiento
require_relative "./actor" require "pp" class Player < Actor attr_accessor :vel_y, :vel_x, :acc, :x,:y def initialize super @sprite = Gosu::Image.new("assets/images/player.png") @x = @y = @vel_x = @vel_y = 0.0 @acc = 0.5 @mass = 50 end def warp(x,y) @x,@y = x,y end # este metodo se encarga de acelerar el jugador, dado que queremos disminuir la velocidad de aceleracion cuando estamos en el aire # el flag @midair determina si estamos en el aire o no def accelerate(angle) acc = @mid_air ? 0.2 : @acc case angle when :right @vel_x += Gosu::offset_x(90, acc) when :left @vel_x += Gosu::offset_x(-90, acc) end end # Movemos el actor a las coordenadas deseadas def move @x += @vel_x @y += @vel_y @vel_x *= 0.95 @vel_y *= 0.95 end # Al saltar, definimos que estamos en el aire, y en tanto no llegemos a cierto punto permitimos acelerar el actor # esto permite graduar la fuerza del salto sin que el jugador pueda volar y permite activar la gravedad una vez que se llega al punto máximo def jump @mid_air = true if @vel_y.abs < 6.0 @vel_y += Gosu::offset_y(1, 3.5) else @falling = true end end # dibujamos el actor en la posicion indicada def draw @sprite.draw(@x,@y, 1 ) end end
La clase World
La clase world controla la interacción entre los actores del juego, asi como efectos como la gravedad que afectan a los actores
require "json" class World attr_reader :actors,:gravity,:friction, :horizon attr_accessor :viewport_height, :viewport_width def initialize @actors = [] #arreglo que contiene los actores del juego @gravitational_force = 0.85 # constante de la fuerza de gravedad @gravity_acceleration = 0.0 # aceleración generada por fuerza de gravedad end # el horizonte sería nuestro suelo ¿tal vez debería llamarlo suelo? def horizon @viewport_height - 140 end # agrega un actor def add_actor(actor) @actors << actor end #define nuestras reglas de gravedad def gravity @actors.each {|actor| if actor.y >= horizon #Si nuestro actor se encuentra en el suelo detenemos la caida y toda aceleración vertical. if actor.falling actor.vel_y = 0 end @gravity_acceleration = 0 actor.y = horizon actor.falling = false actor.mid_air = false elsif actor.vel_y.abs > 0.0 # aplicamos la fuerza de gravedad siempre y cuando el jugador no se encuentre en el suelo @gravity_acceleration = Gosu::offset_y(1, @gravitational_force) actor.vel_y -= @gravity_acceleration end } end def show @actors.each { |actor| actor.draw } end end
Como ya mencioné el código de este programa se puede descargar de github. Lo que quedaría es agregar un bloque, y programar las colisiones, aunque quizás no lo haga manualmente sino que cambie mi sistema de física por Chipmunk que parece algo mucho más completo y bien hecho
Comments
Comments powered by Disqus