Programmera spel i C++ för nybörjare/Views
Stora spelplaner
redigeraDet 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
redigeraVill 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
redigeraDet 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
Zoom
redigeraI 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
redigeraI 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
redigeraHär nedanför finns kod för ett enkelt projekt där du kan testa de olika funktionerna som beskrivits här.
Bakgrund
redigeraVi 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
redigeraVi 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