Vårt rymdskepp är redan utrustat med en laserkanon – du ser de två piporna sticka ut framtill på skeppet. Men kanonen har ingen ammunition, och kan därför inte skjuta. Så nu ska vi ta och ladda den med ett laserskott! (Här bortser vi helt från hur laser fungerar i verkligheten.)
Vi ska alltså lägga till ännu ett objekt i spelet. Och vid det här laget vet du nog hur det går till. Först måste vi skapa ytterligare en klass, den här gången med namnet Laser
. Så direkt efter Asteroid
-klassen skriver vi:
class Laser
def initialize(window, hero)
@window = window
@hero = hero
end
def update
end
def draw
end
end
Laserskottet måste veta både i vilket spelfönster det ska ritas, och vilket rymdskepp det hör till. Det fixar vi i initialize
-metoden.
Som vanligt behöver vi en bild, och den ligger här nedanför. Jag vet att den ser konstig ut, men det blir bra det här, jag lovar! Högerklicka, spara och flytta bilden till rätt mapp.
Laserskottet ska få en startposition precis under rymdskeppets laserkanon. Och dit ska det återvända varje gång kanonen "laddas om". I stället för att skriva samma kod på olika ställen i klassen så skapar vi en speciell metod, laser_home
, som vi använder för att skicka skottet "hem" till kanonen. Denna metod ska vi anropa dels i initialize
, dels i update
:
class Laser
def initialize(window, hero)
@window = window
@hero = hero
@icon = Gosu::Image.new(@window, "laser.png", true)
laser_home
end
def laser_home
@x = @hero.x + 46
@y = @hero.y + 3
end
def update
laser_home
end
def draw
@icon.draw(@x, @y, 1)
end
end
Koden i laser_home
gör så att skottet hamnar 46 pixlar till höger och 3 pixlar nedåt i förhållande till skeppets övre, vänstra hörn. Det vill säga precis i nivå med laserkanonen. Ovan har jag också sett till så att datorn vet vilken bild som ska användas för att visa skottet, och att bilden ritas ut när draw
anropas.
Om du studerar draw
-metoden noga så kanske du märker en skillnad jämfört med motsvarande metoder i Hero
- och Asteroid
-klasserna? Det står @icon.draw(@x, @y, 1)
i stället för @icon.draw(@x, @y, 2)
. Siffran i slutet bestämmer i vilket lager bilden ska ritas. Så laserskottet ritas i lager ett, under rymdskeppet som ritas i lager två.
Vi måste också lägga till vår laser i Window
-klassen. Först ordnar vi så att laserskottet skapas i initialize
-metoden, genom att lägga till följande rad:
@laser = Laser.new(self, @hero)
Sedan gör vi detta lilla tillägg i Window
-klassens update
-metod:
@laser.update
I draw
-metoden skriver vi:
@laser.draw
Och så ska vi se till så att laserskottet kan läsa av rymdskeppets x- och y-position. Direkt efter class Hero
skriver vi:
attr_reader :x, :y
Efter de här små tilläggen så ska hela programmet se ut så här:
require 'gosu'
class Window < Gosu::Window
def initialize
super(640, 480, false)
@hero = Hero.new(self)
@laser = Laser.new(self, @hero)
@asteroids = 5.times.map {Asteroid.new(self)}
@running = true
end
def update
if @running
if button_down? Gosu::Button::KbRight
@hero.move_forward
end
if button_down? Gosu::Button::KbLeft
@hero.move_back
end
if button_down? Gosu::Button::KbUp
@hero.move_up
end
if button_down? Gosu::Button::KbDown
@hero.move_down
end
@laser.update
@asteroids.each {|asteroid| asteroid.update}
if @hero.hit_by?(@asteroids)
@running = false
end
end
end
def draw
@hero.draw
@laser.draw
@asteroids.each {|asteroid| asteroid.draw}
end
end
class Hero
attr_reader :x, :y
def initialize(window)
@window = window
@icon = Gosu::Image.new(@window, "spaceship.png", true)
@x = 100
@y = 215
end
def move_forward
@x = @x + 5
if @x > @window.width - @icon.width
@x = @window.width - @icon.width
end
end
def move_back
@x = @x - 5
if @x < 0
@x = 0
end
end
def move_up
@y = @y - 5
if @y < 0
@y = 0
end
end
def move_down
@y = @y + 5
if @y > @window.height - @icon.height
@y = @window.height - @icon.height
end
end
def draw
@icon.draw(@x, @y, 2)
end
def hit_by?(asteroids)
asteroids.any? {|asteroid| Gosu::distance(@x, @y, asteroid.x, asteroid.y) < 50}
end
end
class Asteroid
attr_reader :x, :y
def initialize(window)
@window = window
@icon = Gosu::Image.new(@window, "asteroid.png", true)
@x = @window.width + rand(1000)
@y = rand(@window.height - @icon.height)
@speed = 3 + rand(5)
end
def update
@x = @x - @speed
if @x < -@icon.width
@x = @window.width
@y = rand(@window.height - @icon.height)
@speed = 3 + rand(5)
end
end
def draw
@icon.draw(@x, @y, 2)
end
end
class Laser
def initialize(window, hero)
@window = window
@hero = hero
@icon = Gosu::Image.new(@window, "laser.png", true)
laser_home
end
def laser_home
@x = @hero.x + 46
@y = @hero.y + 3
end
def update
laser_home
end
def draw
@icon.draw(@x, @y, 1)
end
end
window = Window.new
window.show
Om du nu provkör spelet är risken att du blir besviken – du kommer nämligen inte att märka någon som helst skillnad jämfört med förra lektionen. Laserkanonen är visserligen laddad, men det syns inte utanpå. Och kanonen går inte att fyra av.
Men håll ut, i nästa lektion blir det betydligt mer action!