Stora spelplaner

redigera

Det finns spel som har en större spelplan än vad man kan se på skärmen. Exempel på det är bl.a. Age of Empires I och Starcraft I. Samma sak gäller om man vill skapa ett rymdspel som kan vara 600 pixlar brett men tusentals pixlar långt eftersom man skall kunna flyga länge innan man stöter på en boss. I den typen av spel glider man runt med en "View". Tänk dig att det är en fyrkantig kamera som kan zooma in på en liten del av spelplanen. Just den delen är vad man skall visa upp för spelaren, inget annat. På det viset slipper man belasta datorn med att rita upp grafik som ingen kan se.

OBS! Det finns ingen bra översättning på "View", men man kan man kalla det för "vy", vilket är en direktöversättning. I engelska spelprogrammeringsböcker förekommer även ordet "viewport" för det bildutsnitt som visas på skärmen.

Det är enkelt att skapa en view:

sf::Vector2f Center(1000, 1000); //Mitten av bakgrundsbilden
sf::Vector2f HalfSize(400, 300); // 400 åt varje håll i X-led, 300 åt varje håll i Y-led
sf::View View1(Center, HalfSize); //Utplacering av view

// Eller

sf::View View2(sf::FloatRect(600, 700, 1400, 1300));
//Övre vänsterhörn = 600,700 Nedre högerhörn = 1400,1300

Storleken i X-led blir 600-1400 = 800 och i Y-led 1300-700 = 600. Det här är initialstorleken. Du kan skriva:

sf::View View2(sf::FloatRect(100, 100, 200, 200));

Då blir Viewen bara 100 x 100 pixlar stor och visar en liten del av bakgrunden, men så fort du zoomar ut ändras detta. Därför är det enklast att ha viewen lika stor som det "RenderWindow" du skapat, och det är som standard 800x600.

När som helst under spelets gång kan du ändra placeringen av viewen, t.ex. om du vill centrera den på en speciell spelpjäs:

View.SetCenter(400, 300); //Placera 400 in och 300 ner på bakgrundsbilden
View.SetHalfSize(400, 300); //800 x 600 stor view, tangerar över- och vänsterkant

Eller, om det är en rektangel du vill använda:

View.SetFromRect(sf::FloatRect(0, 0, 800, 600)); //Samma ställe som ovan

Piltangenterna

redigera

Vill man flytta runt "Viewen" med piltangenterna är inte det heller särskilt svårt, koden är:

// Flytta din view med piltangenterna
float Offset = 200.f * App.GetFrameTime(); //Ställ hur snabbt den flyttas runt här
if (App.GetInput().IsKeyDown(sf::Key::Up)) View.Move( 0, -Offset); 
if (App.GetInput().IsKeyDown(sf::Key::Down)) View.Move( 0, Offset); 
if (App.GetInput().IsKeyDown(sf::Key::Left)) View.Move(-Offset, 0); 
if (App.GetInput().IsKeyDown(sf::Key::Right)) View.Move( Offset, 0);

Set View

redigera

Det sista man gör efter alla förflyttningar, innan man rensar skärmen, är att sätta ner sin view på spelplanen. Man gör det för att spelet inte skall rita upp någonting annat än det som syns i Viewen. Kommandot kan se ut så här:

App.SetView(View); // Rensa skärmen, sätt ut viewport
App.Clear(sf::Color(0, 255, 0)); //rensa allt i fönstret

I de flesta spel är det inte önskvärt att man kan zooma in och ut. Då ser man till att man skapar en view som är lika stor som "RenderWindow", sedan flyttar man bara omkring den tills man når kanten av bakgrundsbilden och stoppar där. Då kan man aldrig se mer än själva spelplanen. Koden för zoom är annars t.ex.:

if (App.GetInput().IsKeyDown(sf::Key::A)) View.Zoom(1.001f);  //Zooma in
if (App.GetInput().IsKeyDown(sf::Key::S)) View.Zoom(0.999f); //Zooma ut

Koordinater

redigera

I exemplet nedan skriver vi ut text som hela tiden finns kvar inuti vår View. Det åstadkommer vi genom kommandot:

App.SetView(App.GetDefaultView()); 

När vi använder oss av det kommandot placeras texten i koordinaterna inuti vår View, om vi inte har det kommandot placeras texten ut på koordinater som passar på bakgrundsbilden istället.

Det är lätt att glömma att de koordinater man använder i en view inte har 0,0 överst i vänsterhörn i Viewen. Ett sätt att transformera koordinater mellan spelets bakgrundsbild och Viewen är:

// Få fram muskoordinaterna i Viewen.
sf::Vector2f MousePos = App.ConvertCoords(App.GetInput().GetMouseX(), App.GetInput().GetMouseY());

Slutgiltig kod

redigera

Här nedanför finns kod för ett enkelt projekt där du kan testa de olika funktionerna som beskrivits här.

Bakgrund

redigera

Vi skall göra ett enkelt projekt och till det behöver vi en bakgrundsbild av vilken storlek som helst. Bakgrundsbilden skall ändå få storleken förändrad i programmet. Den måste heta background.jpg och sparas i projektets mapp. Jag valde en väldigt plottrig med frukt och grönsaker för att man lätt skall kunna se var man är i bilden:

www.public-domain-image.com/still-life/slides/still-life-picture-of-a-pumpkin-and-other-various-fruit-on-black-background.jpg

Musmarkör

redigera

Vi skall också ändra musmarkören. Musmarkörer är filer av typen tga (targa) och endera får du försöka hitta en lämplig på Internet eller tillverka den själv i ett bildbehandlingsprogram. Den måste heta: cursor.tga och sparas i projektets mapp. Vi tar med den bara för att visa att man kan behålla musmarkören inuti en view.

I SFML kan du lägga till en cursor/musmarkör, men du kan inte trolla bort original-musmarkören på ett enkelt sätt (programmet här nedanför visar just detta). Orsaken till det är att koden går att använda i Windows, i Linux och i Apples datorer, men dessa hanterar musmarkörer olika. Därför måste man skriva olika kod för de olika operativsystemen om man vill "trolla bort" original-musmarkören.

#include <iostream>
#include <SFML/System.hpp>
#include <SFML/Window.hpp>
#include <SFML/Graphics.hpp>
// #include <SFML/Audio.hpp> bara om du vill ha ljud
// #include <SFML/Network.hpp> bara om du gör nätverksspel

//#define SFML_STATIC //Se till så att det inte behövs extra DLL-filer

// using namespace std;    // utifall att konsollen behövs för felsöknning

int main() 
{ 
//Skapa fönstret 
sf::RenderWindow App(sf::VideoMode(800, 600), "SFML Views"); 
// Skapa en sprite för bakgrunden
sf::Image BackgroundImage; 
if (!BackgroundImage.LoadFromFile("background.jpg")) return EXIT_FAILURE; 
sf::Sprite Background(BackgroundImage); 
// Skapa en annan för musmarkören
sf::Image CursorImage; 
if (!CursorImage.LoadFromFile("cursor.tga")) return EXIT_FAILURE; 
sf::Sprite Cursor(CursorImage); 
// Ändra bakgrundens storlek så att den är större än skärmen
Background.Resize(2000, 2000); 
// Skriv en instruktionstext 
sf::String Text("Använd piltangenterna för att styra kameran\nAnvänd A och S tangenterna för att zooma in och ut"); 
//Flytta in texten på skärmen
Text.Move(10, 500); 
//Ge texten vit färg
Text.SetColor(sf::Color::White); 

// Skapa en view som har samma storlek som skärmen
//placerad i mitten av bakgrundsbilden
sf::Vector2f Center(1000, 1000); //Mitten av bakgrundsbilden
sf::Vector2f HalfSize(400, 300); // 400 åt varje håll i X-led, 300 åt varje håll i Y-led
sf::View View(Center, HalfSize); //Utplacering av view

//sf::View View2(sf::FloatRect(600, 700, 1400, 1300)); //Om du vill testa fyrkant istället


// Placera musmarkören i mitten vid start
Cursor.SetCenter(32, 32); 
Cursor.SetPosition(Center); //Mitt på bakgrundsbilden
//Cursor.SetPosition(0,0);

// Starta spelloopen
while (App.IsOpened()) 
  { // Händelser 
  sf::Event Event; 
  while (App.GetEvent(Event)) 
    { // Stäng
    if (Event.Type == sf::Event::Closed) App.Close(); 
    // Stäng
    if ((Event.Type == sf::Event::KeyPressed) && (Event.Key.Code == sf::Key::Escape)) App.Close();
    } 

  // Flytta din view med piltangenterna
  float Offset = 200.f * App.GetFrameTime(); 
  if (App.GetInput().IsKeyDown(sf::Key::Up)) View.Move( 0, -Offset); 
  if (App.GetInput().IsKeyDown(sf::Key::Down)) View.Move( 0, Offset); 
  if (App.GetInput().IsKeyDown(sf::Key::Left)) View.Move(-Offset, 0); 
  if (App.GetInput().IsKeyDown(sf::Key::Right)) View.Move( Offset, 0); 
  // Zooma in och ut med A och S tangenterna
  if (App.GetInput().IsKeyDown(sf::Key::A)) View.Zoom(1.001f); 
  if (App.GetInput().IsKeyDown(sf::Key::S)) View.Zoom(0.999f); 

  // Placera ut viewen så att den kan ritas ut
  App.SetView(View); // Rensa skärmen
  App.Clear(sf::Color(0, 255, 0)); //rensa allt i fönstret 
  // Rita ut bakgrunden
  App.Draw(Background); 
  // Rita ut musmarkören 
  sf::Vector2f CursorPos = App.ConvertCoords(App.GetInput().GetMouseX(), App.GetInput().GetMouseY()); 
  Cursor.SetPosition(CursorPos); 
  App.Draw(Cursor); 
  // Återställ till standardvärden
  App.SetView(App.GetDefaultView()); 
  // Rita ut instruktionstexten
  App.Draw(Text); 
  // Visa upp det vi gjort till spelaren
  App.Display(); 
  } 
  return 0; 
} 
//Merparten av koden kommer härifrån:
//http://www.sfml-dev.org/tutorials/1.6/sources/graphics-views.cpp