sobota, 5 listopada 2016

Główna mechanika gry

Witam 

Dziś zajmiemy się ostatnią częścią naszej gry czyli klasą engine zacznijmy więc od pliku nagłówkowego
#include "pole.h"
#pragma once

class Engine
{
        //wskaźniki do okna i czcionki które otrzymamy z klasy game 
sf::RenderWindow *window;
sf::Font *font;
        //stworze tekstów odnośnie wyniku gry
sf::Text text;
sf::Text info;

 //stworzenie naszej planszy i planszy przeciwnika
    Pole pole[10][10];
    Pole pole_przec[10][10];


    enum Game{MARK,SHOT,OVER}; //zmienna wskazująca na jakim etapie gry jesteśmy
    Game state;
void update(); //aktualizuje informacje
void draw(); //rysuje wszystkie elementy
int mark=0; //wskazuje ile statków zaznaczyliśmy
void IAmark(); //zaznaczanie statków przez komputer
void IAshot(); //zgadywanie naszych statków przez komputer
int points=0,IApoints=0; //zmiene wskazujące ile statków zestrzeliliśmy


public:


// konstruktor i destruktor
    Engine(sf::RenderWindow &win, sf::Font &fon);
    ~Engine();

    void runEngine(); //główna funkcja obsługująca mechanikę

};

Teraz zajmijmy się plikiem engine.cpp

#include "pole.h"
#pragma once

#include "engine.h"
#include <Windows.h>
#include <cstdlib>
#include <ctime>
#include <cstdio>


using namespace sf;

Engine::Engine(sf::RenderWindow &win, sf::Font &fon)
{
    window = &win;
    font=&fon;

//sformatowanie wyświetlanych tekstów
    text.setFont(*font);
    text.setCharacterSize(240);
    text.setColor(Color::Black);
    info.setFont(*font);
    info.setColor(Color::Black);
    info.setCharacterSize(35);
    info.setString("Press ESC");
    info.setPosition(1280/2-info.getGlobalBounds().width/2,720/2-info.getGlobalBounds().height/2+150);

//ustawienie pozycji pól 
    for(int x=0; x<10; x++)
    {
        for(int y=0; y<10; y++)
        {
            pole[x][y].setPosition(x,y,100,100);
            pole_przec[x][y].setPosition(x,y,680,100);
            pole_przec[x][y].setIA(true);
        }
    }
}


Engine::~Engine()
{
}

void Engine::runEngine()
{
    bool menu=false;
    state=MARK;
    IAmark(); //zaznaczenie statków przez komputer



    while(!menu) //główna pętla aplikacji
    {
//ustawienie informacji o wyniku gry
        if(IApoints>19&&points>19)
        {
            state=OVER;
            text.setString("DRAW");

        }
        else if(IApoints>19)
        {
            state=OVER;
            text.setString("LOSE");
        }
        else if(points>19)
        {
            state=OVER;
            text.setString("WIN");
        }


        Event event;
        Vector2f mouse(Mouse::getPosition(*window)); //pobranie pozycji myszki

        while(window->pollEvent(event));
        {
            if (Keyboard::isKeyPressed(Keyboard::Escape))
//powrót do meny po naciśnięciu ESC
                menu=true; //powrót 

            if (event.type == sf::Event::Closed)
                window->close();

//sprawdzenie dla każdego pola przeciwnika czy jesteśmy na etapie zgadywania statków przeciwnika i czy kliknęliśmy dane pole
    for(int x=0; x<10; x++)
    {
        for(int y=0; y<10; y++)
                {
                    if(pole_przec[x][y].getBounds(mouse)&& state==SHOT && pole_przec[x][y].getShot()==false &&
                            (event.type==Event::MouseButtonReleased && event.key.code ==Mouse::Left ))
                    {
                        pole_przec[x][y].setShot(true)
                        if(pole_przec[x][y].getShip()==false||points>19) //jeśli nie trafiliśmy komputer zaznacza swój statek w przeciwnym razie komputer zgaduje 
                            IAshot();
                        else points++;



                    }
                }
            }

//sprawdzenie dla każdego pola gracza czy jesteśmy na etapie zaznaczania naszych statków i czy kliknęliśmy dane pole
          for(int x=0; x<10; x++)
            {
             for(int y=0; y<10; y++)
                {
                    if(pole[x][y].getBounds(mouse)&& state==MARK && pole[x][y].getShip()==false &&
                            (event.type == Event::MouseButtonReleased && event.key.code== Mouse::Left ))
                    {
                        pole[x][y].setShip(true);
                        mark++;
                        if(mark>=20)
                            state=SHOT;

                    }
                }
            }


        }
//zaktualizowanie danych i narysowanie planszy
        update();
        draw();
    }


}

void Engine::draw()
{

    window->clear(Color::White);
// jeśli gra się nie skończyła rysujemy plansze
    if(state!=OVER
    for(int x=0; x<10; x++)
    {
        for(int y=0; y<10; y++)
            {
                window->draw(pole[x][y]);
                window->draw(pole_przec[x][y]);
            }
        }
//jeśli gra się skończyła wyświetlamy informacje o wyniku gry
    if(state==OVER)
    {
        text.setPosition(1280/2-text.getGlobalBounds().width/2,720/2-text.getGlobalBounds().height/2-100);
        window->draw(text);
        window->draw(info);
    }


    window->display();
}

void Engine::update() //aktualizowanie informacji dla każdego pola
{
    for(int x=0; x<10; x++)
    {
        for(int y=0; y<10; y++)
        {
            pole[x][y].update();
            pole_przec[x][y].update();
        }
    }
}

void Engine::IAmark(
{
    int x,y;
    srand(time(NULL ));
//dwadzieścia razy losujemy pole na którym komputer zaznaczy swój statek jeśli pole było zaznaczone wcześniej losujemy drugi raz
    for(int i=0i<20i++)
    {
        do
        {
            x=rand()%10;
            y=rand()%10;
        }
        while(pole_przec[x][y].getShip()==true);

        pole_przec[x][y].setShip(true);
    }
}

void Engine::IAshot()
{
    int x,y;
    srand(time(NULL ));
//losujemy pole w które komputer będzie strzelał jeśli pole było zaznaczone wcześniej losujemy drugi raz
    do
    {
         x=rand()%10;
         y=rand()%10;
    }
    while(pole[x][y].getShot()==true);

    pole[x][y].setShot(true);
    if(pole[x][y].getShip()==true&&IApoints<20) //jeśli trafił wywołujemy funkcje jeszcze raz
    {
        IApoints++;
        IAshot();
    }
}

Teraz wystarczy w pliku game.h włączyć plik engine.h i skompilować i możemy podziwiać działającą grę.

Podsumowanie 

Dziś wreszcie udało nam się skończyć naszą aplikację okienkową. Kod całej aplikacji możecie znaleźć na moim profilu github. Jak zwykle zachęcam do zadawania pytań i zgłaszania propozycji w komentarzach.

czwartek, 3 listopada 2016

Menu gry

Witam 

Dziś zrobimy podstawowe menu dodajmy więc dwa pliki game.h i game.cpp odrazy otwórzmy ten pierwszy i zadeklarujmy wszystkie potrzebne zmienne i funkcje.

game.h

#include <SFML\Graphics.hpp>
#include <Windows.h>
#include <string>
#include "pole.h"

using namespace std;
using nam espace sf;
//dodanie potrzebnych bibliotek i zadeklarowanie przestrzeni nazw

class Game
{
public:
Game(void);
~Game(void)
//konstruktor i destruktor

void runGame(); //główna funkcja obsługująca grę

protected:
enum GameState {MENU,GAME,GAME_OVER,END}; //zmienna określająca status gry
GameState state

private:
Font font;

void menu(); //funkcja wyświetlająca grę
void single(); //funkcja wyświetlająca grę
};

Teraz zajmijmy się plikiem game.cpp 

#include "game.h"

RenderWindow window

Game::Game(void)
{
ContextSettings settings;
settings.antialiasingLevel = 8;
//stworzenie okna
window.create(VideoMode(1280,720),"Statki",Style::Default,
settings);

state = END;
window.setFramerateLimit(60);
//załadowanie czcionki
if(!font.loadFromFile("tahoma.ttf"))
{
MessageBox(NULL,"Font not found!","ERROR",NULL);
return;
}

state = MENU;
}


Game::~Game(void)
{
}


void Game::runGame()//sprawdza jaki jest status gry i wywołuje odpowiednią funkcję
{
while(state != END)
{
switch (state)
{
case MENU:
menu();
break;
case GAME:
single();
break;
}
}
}


void Game::menu()
{
//ustawienie i sformatowanie tytułu gry
Text title("STATKI",font,80);
title.setStyle(Text::Bold);
title.setColor(Color::Black);

title.setPosition(1280/2-title.getGlobalBounds().width/2,20);

const int ile = 2;
//ustawienie i sformatowanie opcji wyboru
Text tekst[ile];

string str[] = {"Play","Exit"};
for(int i=0;i<ile;i++)
{
tekst[i].setFont(font);
tekst[i].setCharacterSize(65);

tekst[i].setString(str[i]);
tekst[i].setPosition(1280/2-tekst[i].getGlobalBounds().width/2,250+i*120);
}

while(state == MENU)
{
Vector2f mouse(Mouse::getPosition(window));
Event event;

while(window.pollEvent(event))
{
//Wciśnięcie ESC lub przycisk X
if(event.type == Event::Closed || event.type == Event::KeyPressed &&
event.key.code == Keyboard::Escape)
state = END;

//kliknięcie MENU
else if(tekst[0].getGlobalBounds().contains(mouse&&
event.type == Event::MouseButtonReleased && event.key.code == Mouse::Left)
{
state = GAME;
}

//kliknięcie EXIT
else if(tekst[1].getGlobalBounds().contains(mouse&&
event.type == Event::MouseButtonReleased && event.key.code == Mouse::Left)
{
state = END;
}
}
//sprawdzenie czy gracz najechał na tekst i udpowiednie ustawienie koloru
for(int i=0;i<ile;i++)
if(tekst[i].getGlobalBounds().contains(mouse))
tekst[i].setColor(Color::Cyan);
else tekst[i].setColor(Color::Black);

//narysowanie wszystkich elementów
window.clear(Color::White);

window.draw(title);
for(int i=0;i<ile;i++)
window.draw(tekst[i]);

window.display();
}
}
// funkcja wywołująca właściwą grę
void Game::single()
{
Engine engine(window,font);

engine.runEngine();

state = MENU;
}

Na razie zawartość funkcji single dajmy sobie w komentarze ponieważ klasa engine nie została utworzona i program się nie wykona.


Teraz skompilujmy nasz program i podziwiajmy nasze menu

Podsumowanie

Dziś zrobiliśmy dużo, udało nam się stworzyć piękne menu. w następnej części zajmiemy się klasą engine. Jak zwykle cały kod aplikacji znajdziecie na moim profilu github. Jak zawsze zachęcam do zadawania pytań i komentowania.