Advertisement
Guest User

from http://bp.io/post/1609

a guest
Nov 13th, 2015
623
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 10.35 KB | None | 0 0
  1. #include <string>
  2. #include <iostream>
  3. #include <list>
  4. #include <cstdlib>
  5. #include <ctime>
  6. #include <SFML/Window.hpp>
  7. #include <SFML/Graphics.hpp>
  8. using namespace std;
  9.  
  10. static const int WINDOW_WIDTH = 512, WINDOW_HEIGHT = 512;
  11. static const int TILES_WIDE = 8, TILES_HIGH = 8;
  12. static const int TILE_WIDTH = WINDOW_WIDTH/TILES_WIDE, TILE_HEIGHT = WINDOW_HEIGHT/TILES_HIGH;
  13.  
  14. enum Tile {
  15.     TILE_WATER,
  16.     TILE_DIRT,
  17.  
  18.     TILE_INVALID,
  19. };
  20.  
  21. class Map {
  22. public:
  23.     Map(){}
  24.     Map(string mapString){
  25.         // Convert map string into tiles
  26.         if (mapString.length()!=TILES_WIDE*TILES_HIGH){
  27.             cerr << "map string is wrong length!";
  28.             return;
  29.         }
  30.  
  31.         for(int i=0;i<TILES_WIDE;i++){
  32.             for(int j=0;j<TILES_HIGH;j++){
  33.                 char c = mapString[i + j*TILES_WIDE];
  34.                 Tile tile;
  35.                 switch (c){
  36.                 case ' ': tile = TILE_DIRT; break;
  37.                 case '~': tile = TILE_WATER; break;
  38.                 default: tile = TILE_INVALID; break;
  39.                 }
  40.                 setTile(i, j, tile);
  41.             }
  42.         }
  43.     }
  44.  
  45.     Tile tile(int i, int j){
  46.         if (isValidIndex(i,j)){        
  47.             return mTiles[i + j*TILES_WIDE];
  48.         }
  49.         else return TILE_INVALID;
  50.     }
  51.  
  52.     void setTile(int i, int j, Tile t){
  53.         if (isValidIndex(i,j)){
  54.             mTiles[i + j*TILES_WIDE] = t;
  55.         }
  56.     }
  57.  
  58. protected:
  59.  
  60.     bool isValidIndex(int i, int j){
  61.         return (i>=0 && i<TILES_WIDE && j>=0 && j<TILES_HIGH);
  62.     }
  63.  
  64.     Tile mTiles[TILES_WIDE*TILES_HIGH];
  65. };
  66.  
  67. // Base class for all moveable things
  68. struct Entity {
  69.     // Actual position
  70.     int i, j;
  71.  
  72.     // these are used for position interpolation
  73.     bool isMoving;
  74.     int oldI, oldJ;
  75.     float pi, pj;
  76. };
  77.  
  78. struct Player: Entity {
  79.    
  80. };
  81.  
  82. enum MonsterType {RED_ZOMBIE, GREEN_ZOMBIE};
  83. struct Monster: Entity {
  84.     MonsterType type;
  85. };
  86.  
  87. enum GameState {
  88.     WAITING_FOR_PLAYER_INPUT,
  89.     UPDATING_PLAYER,
  90.     UPDATING_MONSTERS,
  91.  
  92.     // Other game states may be
  93.     // TITLE_SCREEN
  94.     // DEATH_SCREEN
  95.     // UPDATING_BOMBS
  96.     // etc..
  97. };
  98.  
  99. struct Game {
  100.     GameState state;
  101.     sf::Clock clock;
  102.     Map map;
  103.     Player player;
  104.     list<Monster> monsters;
  105. };
  106.  
  107. // Checks to see if theres a monster here
  108. bool isMonsterHere(Game& game, int i, int j){
  109.     for(auto monster: game.monsters){
  110.         if (monster.i==i && monster.j==j) return true;
  111.     }
  112.     return false;
  113. }
  114.  
  115. // Checks to see if theres a player here
  116. bool isPlayerHere(Game& game, int i, int j){
  117.     if (game.player.i==i && game.player.j==j) return true;
  118.     else return false;
  119. }
  120.  
  121. // Linear interpolation
  122. float lerp(float a, float b, float t){
  123.     return a*(1-t) + b*t;
  124. }
  125.  
  126. int main(){
  127.     srand(time(NULL)); // seed randomiser
  128.     sf::RenderWindow window(sf::VideoMode(WINDOW_WIDTH, WINDOW_HEIGHT), "Game");
  129.  
  130.     // Setup game
  131.     Game game;
  132.     game.state = WAITING_FOR_PLAYER_INPUT;
  133.  
  134.     // Setup map
  135.     string mapString =
  136.         "        "
  137.         " ~~~ ~~ "
  138.         "        "
  139.         " ~    ~ "
  140.  
  141.         " ~    ~ "
  142.         " ~    ~ "
  143.         " ~~ ~~~ "
  144.         "        ";
  145.     game.map = Map(mapString);
  146.  
  147.     // Setup player
  148.     game.player.i = 0;
  149.     game.player.j = 0;
  150.     game.player.isMoving = false;
  151.     game.player.oldI = 0;
  152.     game.player.oldJ = 0;
  153.     game.player.pi = 0.0f;
  154.     game.player.pj = 0.0f; 
  155.  
  156.     // Create some monsters
  157.     const int NUM_MONSTERS = 6;
  158.     for(int i=0;i<NUM_MONSTERS;i++){       
  159.         MonsterType type = GREEN_ZOMBIE;
  160.  
  161.         double random = (1.0*rand())/RAND_MAX;
  162.         if (random > 0.8){
  163.             type = RED_ZOMBIE;
  164.         }
  165.  
  166.         // Find an empty dirt spot to place the monster
  167.         int placeI = 0, placeJ = 0;
  168.         while(true){
  169.             int ri = rand()%TILES_WIDE;
  170.             int rj = rand()%TILES_HIGH;
  171.            
  172.             // Check for collision with player or other zombies
  173.             bool canPlaceHere = true;
  174.             canPlaceHere = !isPlayerHere(game, ri, rj);
  175.             canPlaceHere = canPlaceHere && !isMonsterHere(game, ri, rj);
  176.             canPlaceHere = canPlaceHere && game.map.tile(ri, rj)==TILE_DIRT;
  177.             if (canPlaceHere){
  178.                 placeI = ri;
  179.                 placeJ = rj;
  180.                 break;
  181.             }
  182.             // else keep trying
  183.         }
  184.  
  185.         Monster monster;
  186.         monster.type = type;
  187.         monster.i = placeI;
  188.         monster.j = placeJ;
  189.         monster.isMoving = false;
  190.         monster.oldI = monster.i;
  191.         monster.oldJ = monster.j;
  192.         monster.pi = (float) placeI;
  193.         monster.pj = (float) placeJ;
  194.  
  195.         game.monsters.push_back(monster);
  196.     }
  197.  
  198.     // Start loop
  199.     game.clock.restart();
  200.     while (window.isOpen())
  201.     {      
  202.         // Manage Input
  203.  
  204.         sf::Event event;
  205.         while (window.pollEvent(event))
  206.         {
  207.             if (event.type == sf::Event::Closed){
  208.                 window.close();
  209.             }
  210.  
  211.             if (game.state==WAITING_FOR_PLAYER_INPUT){
  212.                 if (event.type==sf::Event::KeyPressed){                
  213.                     int di = 0, dj = 0; // the direction to move in
  214.                     switch (event.key.code){
  215.                         case sf::Keyboard::Left: di = -1; break;
  216.                         case sf::Keyboard::Right: di = 1; break;
  217.                         case sf::Keyboard::Up: dj = -1; break;
  218.                         case sf::Keyboard::Down: dj = 1; break;
  219.                         default: break;
  220.                     }
  221.  
  222.                     if (di!=0 || dj!=0){
  223.                         // Player wants to move so try to move him
  224.                         int i = game.player.i + di;
  225.                         int j = game.player.j + dj;
  226.                        
  227.                         // Check targe tile for collision
  228.                         bool collision = false;
  229.                         Tile t = game.map.tile(i,j);
  230.                         switch (t){
  231.                             case TILE_WATER: case TILE_INVALID: collision = true; break;
  232.                             default: break;
  233.                         }
  234.                         collision = collision || isMonsterHere(game, i, j);
  235.  
  236.                         if (!collision){
  237.                             // Can move there
  238.                             game.player.oldI = game.player.i;
  239.                             game.player.oldJ = game.player.j;
  240.                             game.player.i = i;
  241.                             game.player.j = j;
  242.                             game.player.isMoving = true;
  243.                             game.state = UPDATING_PLAYER;
  244.                             game.clock.restart();
  245.                         }
  246.                     }
  247.                 }
  248.             }
  249.         }
  250.  
  251.         // Update other game state etc
  252.         switch (game.state){
  253.         case WAITING_FOR_PLAYER_INPUT:
  254.             {
  255.                 // Player gets only a short time to make a move
  256.                 // The logic of movement is handled in the event handled               
  257.                 static const float MAX_TIME_TO_MOVE = 2.0f;
  258.                 float t = game.clock.getElapsedTime().asSeconds();
  259.                 if (t >= MAX_TIME_TO_MOVE){
  260.                     game.state = UPDATING_PLAYER;
  261.                     game.clock.restart();
  262.                 }
  263.                 break;
  264.             }
  265.         case UPDATING_PLAYER:
  266.             {
  267.                 static const float MOVE_SPEED = 0.2f; // seconds it takes to move
  268.                 float t = game.clock.getElapsedTime().asSeconds();
  269.                 t = min(MOVE_SPEED, t);
  270.  
  271.                 if (game.player.isMoving){                 
  272.                     game.player.pi = lerp(game.player.oldI, game.player.i, t/MOVE_SPEED);
  273.                     game.player.pj = lerp(game.player.oldJ, game.player.j, t/MOVE_SPEED);
  274.                 }
  275.  
  276.                 if (t >= MOVE_SPEED){
  277.                     game.player.pi = game.player.i;
  278.                     game.player.pj = game.player.j;
  279.                     game.player.oldI = game.player.i;
  280.                     game.player.oldJ = game.player.j;
  281.                     game.player.isMoving = false;
  282.                     game.state = UPDATING_MONSTERS;
  283.                     game.clock.restart();
  284.  
  285.                     // We now update all monsters
  286.                     for(auto& monster: game.monsters){
  287.                         // Monsters move randomly
  288.                         // and sometimes stay still
  289.                         double random = (1.0*rand())/RAND_MAX;
  290.                         if (random > 0.6){
  291.                             // stay still
  292.                             continue;
  293.                         }
  294.  
  295.                         // Here's a list of possible directions (di,dj)
  296.                         static const int DIRS[4][2] = {{1,0},{-1,0},{0,1},{0,-1}};
  297.  
  298.                         // randomly index into the list
  299.                         int randomDirIndex = rand()%4;
  300.                        
  301.                         // And then try each direction in turn
  302.                         for(int dir=0;dir<4;dir++){
  303.                             int index = (dir + randomDirIndex)%4;
  304.                             int di = DIRS[index][0];
  305.                             int dj = DIRS[index][1];
  306.                             int i = monster.i + di;
  307.                             int j = monster.j + dj;
  308.                        
  309.                             // Check targe tile for collision
  310.                             bool collision = false;
  311.                             Tile t = game.map.tile(i,j);
  312.                             switch (t){
  313.                                 case TILE_WATER: case TILE_INVALID: collision = true; break;
  314.                                 default: break;
  315.                             }
  316.                             collision = collision || isPlayerHere(game, i, j) || isMonsterHere(game, i, j);
  317.  
  318.                             if (!collision){
  319.                                 // Can move there
  320.                                 monster.oldI = monster.i;
  321.                                 monster.oldJ = monster.j;
  322.                                 monster.i = i;
  323.                                 monster.j = j;
  324.                                 monster.isMoving = true;
  325.                                 break;
  326.                             }
  327.                         }                      
  328.                     }
  329.                 }
  330.                 break;                               
  331.             }
  332.         case UPDATING_MONSTERS:
  333.             {
  334.                 static const float MOVE_SPEED = 0.4f; // seconds it takes a zombie to move
  335.                 float t = game.clock.getElapsedTime().asSeconds();
  336.                 t = min(MOVE_SPEED, t);
  337.                 for(auto& monster: game.monsters){
  338.                     if (monster.isMoving){
  339.                         monster.pi = lerp(monster.oldI, monster.i, t/MOVE_SPEED);
  340.                         monster.pj = lerp(monster.oldJ, monster.j, t/MOVE_SPEED);
  341.                     }
  342.                 }
  343.                 if (t >= MOVE_SPEED){
  344.                     for(auto& monster: game.monsters){
  345.                         monster.oldI = monster.i;
  346.                         monster.oldJ = monster.j;
  347.                         monster.isMoving = false;
  348.                     }
  349.                     game.state = WAITING_FOR_PLAYER_INPUT;
  350.                     game.clock.restart();
  351.                 }
  352.                 break;
  353.             }
  354.         }
  355.  
  356.         // Draw
  357.         window.clear(sf::Color::Black);
  358.  
  359.         // Draw map
  360.         for(int i=0;i<TILES_WIDE;i++){
  361.             for(int j=0;j<TILES_HIGH;j++){
  362.                 sf::RectangleShape tileRectangle(sf::Vector2f(TILE_WIDTH, TILE_HEIGHT));
  363.  
  364.                 // Convert i,j to top-left screen position of this tile
  365.                 int x = i * TILE_WIDTH;
  366.                 int y = j * TILE_HEIGHT;
  367.                 tileRectangle.setPosition(x, y);
  368.  
  369.                 // Set rect colour based on tile type
  370.                 sf::Color colour;
  371.                 Tile tile = game.map.tile(i,j);
  372.                 switch (tile){
  373.                     case TILE_DIRT: colour = sf::Color::Black; break;
  374.                     case TILE_WATER: colour = sf::Color::Blue; break;
  375.                     default: colour = sf::Color::Magenta; break;
  376.                 }
  377.                 tileRectangle.setFillColor(colour);
  378.                 window.draw(tileRectangle);
  379.             }
  380.         }
  381.  
  382.         // Draw player
  383.         {
  384.             static const int PLAYER_SIZE = TILE_WIDTH/2;
  385.             sf::RectangleShape playerRectangle(sf::Vector2f(PLAYER_SIZE, PLAYER_SIZE));
  386.             int x = game.player.pi * TILE_WIDTH + (TILE_WIDTH - PLAYER_SIZE)/2;
  387.             int y = game.player.pj * TILE_HEIGHT + (TILE_HEIGHT - PLAYER_SIZE)/2;
  388.             playerRectangle.setPosition(x, y);
  389.             playerRectangle.setFillColor(sf::Color::White);
  390.             window.draw(playerRectangle);
  391.         }
  392.  
  393.         // Draw monsters
  394.         for(auto monster: game.monsters){
  395.             static const int MONSTER_SIZE = TILE_WIDTH - 10;
  396.             sf::RectangleShape monsterRectangle(sf::Vector2f(MONSTER_SIZE, MONSTER_SIZE));
  397.             int x = monster.pi * TILE_WIDTH + (TILE_WIDTH - MONSTER_SIZE)/2;
  398.             int y = monster.pj * TILE_HEIGHT + (TILE_HEIGHT - MONSTER_SIZE)/2;
  399.             monsterRectangle.setPosition(x, y);
  400.  
  401.             // Choose colour based on type
  402.             sf::Color color;
  403.             if (monster.type==RED_ZOMBIE) color = sf::Color::Red;
  404.             else if (monster.type==GREEN_ZOMBIE) color = sf::Color::Green;
  405.             monsterRectangle.setFillColor(color);
  406.             window.draw(monsterRectangle);
  407.         }
  408.  
  409.         window.display();
  410.     }
  411.     return 0;
  412. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement