Koda spel i Ruby

Lektion 4: Dags att sätta gränser

Den här lektionen kommer att handla mycket om pixlar – de där små punkterna som bilden på en datorskärm är uppbyggd av. Vi ska se till så att vårt rymdskepp kan flyga i alla riktningar, men också så att det håller sig i spelfönstret och inte kommer på villovägar.

Först ska vi ta och ändra lite i Hero-klassens metod move_forward, den som får rymdskeppet att röra sig framåt. Vi vet att spelfönstret är 640 pixlar brett. Vi vet också att bilden av rymdskeppet är 70 pixlar bred. Eftersom rymdskeppets position mäts i övre vänstra hörnet på bilden, så vill vi att skeppet ska stanna 70 pixlar från högerkanten, det vill säga när värdet på @x är 570.

Återigen är det här lättare att förstå om man provar. Lägg till följande if-sats i move_forward-metoden:


def move_forward
  @x = @x + 5
  if @x > 570
    @x = 570
  end
end
      

Spara och provkör. Som du märker kan skeppet inte längre köra ut från fönstret. If-satsen kontrollerar nämligen om värdet på @x är större än 570, och om så är fallet ändras värdet tillbaka till 570.

Fast tänk om vi får för oss att ändra bredden på spelfönstret? Då kommer ju skeppet att stanna på fel ställe. Därför är det bättre att skriva så här:


def move_forward
  @x = @x + 5
  if @x > @window.width - @icon.width
    @x = @window.width - @icon.width
  end
end
      

Denna kod är lite mer elegant. Den gör så att rymdskeppet alltid stannar precis vid högerkanten på spelfönstret, oavsett hur brett fönstret är. På grund av if-satsen kan @x aldrig bli större än fönstrets bredd minus bildens bredd ("width" betyder just "bredd").

Men det går fortfarande inte att flyga skeppet i någon annan riktning än framåt. Därför lägger vi först till ytterligare tre if-satser i Window-klassens update-metod:


def update
  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
end	  
      

Sedan lägger vi till de move-metoder som saknas i Hero-klassen, direkt efter move_forward:


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  
	  

För att få skeppet att flyga framåt såg vi till att värdet på @x ökade när man tryckte på högerpilen. När det ska flyga bakåt måste vi i stället minska värdet på @x. Det sker i metoden move_back. If-satsen i metoden gör så att @x aldrig kan bli mindre än 0. Därmed kan skeppet inte heller flyga ut från den vänstra kanten på fönstret.

De båda metoderna move_up och move_down fungerar på samma sätt. Men här är det y-värdet – skeppets position i höjdled – som ändras. Tack vare if-satserna kan @y aldrig bli mindre än 0 eller större än fönstrets höjd minus bildens höjd. Skeppet kan inte längre försvinna!

Hela programmet ska nu se ut så här:


require 'gosu'

class Window < Gosu::Window
  def initialize
    super(640, 480, false)
    @hero = Hero.new(self)
  end
  
  def update
    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
  end
  
  def draw
    @hero.draw
  end
end  

class Hero
  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
end

window = Window.new
window.show	  
	  

Puh! De två senaste lektionerna har varit ganska mastiga, och om du behöver ta en paus nu så förstår jag dig. När du är redo att fortsätta ska vi ta och lägga till något som vårt rymdskepp ska undvika – en asteroid!