Critique my Idea

Started by
4 comments, last by Ultimape 17 years, 4 months ago
I've written my first "game", although you can't actually interact with it... yet. Simple text based rendering I have a 2d gameworld, which manages "organisms". it is a vector of vectors of pointers to organisms. each game loop, all organisms are manipulated and they "ask" the game world for things. they can ask it what is at a specific cell they can ask it for coords of a random cell of TYPE adjacent to where they are, (where type can be any organism type, or empty) they can ask it to kill a cell they can ask it to move a cell There is a base class organism (pure virtual) and derived classes: predator "lion", prey "antelope" and they have 4 options: eat, move, breed, starve antelopes don't eat or starve, they just move and breed (after 3 moves) lions can eat if there is a surrounding antelope, move, breed (after 8moves), and starve (if not eaten in 3 moves) each organism manages its own logic for what to do when asked to do something it makes a rather interesting pattern, where the lions overtake the ants until there aren't enough ants to eat, and then they die off, letting the ants repopulate, thus repeating the cycle. running at 140x40, it makes some rather psychedelic patterns, complete with swirling and such. What are some ideas to expand on this... what other organisms should I add, what else should they do? I had ideas of making a "player" organism which is controlled by the user and a "bullet" organism which "eats" in a straight line till it can't move anymore and disappears. or maybe some "life" properties, where if they are overpopulated, the antelopes die. I've already extended it to move diagonally by having the game world return diagonals, and not just up down left and right. Also, i made the antlions canibalize if they were going to starve.
Advertisement
It seems that you are making some sort of life simulation. Well, it is fairly complex, so the first question I have to ask if you have actually implemented a program that does this or if it's just some wild idea.
Projects of this sort can be greatly interesting. I would resist the urge to try to make a "real game" out of it. Instead, have the user interact by controlling the parameters of the simulation. E.g., instead of hard-coding the "age of maturity" of each animal, have the user provide the value.

But if you really want *critique*, I'm going to have to see the code. ;)
Do you like my code? I've endevord to use consistant formatting and attempted to make good comments.

it was a real b*tch to get the organsim and maiworld to compile, interdependancy hell. But I figured it out with help from articles here on game dev.




twodpoint.h
/******************************************************************************| file        | twodpoint.h                                                    || author      | 'Ultim'Ape-Iñago                                               || date        | 2006/11/13                                                     || description | Defines a cell position                                        |\******************************************************************************/#ifndef TwoDPoint_H_INCLUDED#define TwoDPoint_H_INCLUDEDclass TwoDPoint{  private:    int posx;    int posy;  public:    TwoDPoint ( int PosY =-1,int PosX=-1 );    bool operator == ( const TwoDPoint &other );    void set(int PosY,int PosX);    void print();    int x();    int y();};#endif // CELL_H_INCLUDED


twodpoint.cpp
#include <iostream>#include "twodpoint.h"TwoDPoint::TwoDPoint ( int y,int x ){  set(x,y);}boolTwoDPoint::operator == ( const TwoDPoint &other ){  if ( this->posx == other.posx && this->posy == other.posy ) {    return true;  } else {    return false;  }}voidTwoDPoint::set(int y,int x){  posx = x;  posy = y;}intTwoDPoint::x(){  return posx;}intTwoDPoint::y(){  return posy;}voidTwoDPoint::print(){  std::cout << "("<<posy<<","<<posx<<")";}


enumerations.h
#ifndef ENUMERATIONS_H_INCLUDED#define ENUMERATIONS_H_INCLUDEDclass MaiWorldGrid;enum CreatureType {  BAD  = 0,  NONE = 1,  EMPTY = 1,  ANT = 2,  DOODLEBUG = 3};#endif // ENUMERATIONS_H_INCLUDED


maierthgame.h
/******************************************************************************| file        | maierthgame.h                                                  || author      | 'Ultim'Ape-Iñago                                               || date        | 2006/11/13                                                     || description | A simulation of animal preditory behavior                      ||             | The main program file                                          |\******************************************************************************/#ifndef MAIERTHGAME_H_INCLUDEDD#include "maiworld.h"#include "enumerations.h"#endif


maierthgame.cpp
#include <iostream>#include "maierthgame.h"#include "maiworld.h"int main(){  srand ( time ( NULL ) );  MaiWorldGrid gameWorld(76,19); //default game world  gameWorld.populateGridRandom ( DOODLEBUG,0.0125 );  gameWorld.populateGridRandom ( ANT, 0.25);  do{  system("cls");  gameWorld.displayGrid();  std::cout<< "Population "<< gameWorld.getCount() << "\n ([Enter] for next frame)";  gameWorld.eatAll(DOODLEBUG);  gameWorld.moveAll(DOODLEBUG);  gameWorld.breedAll(DOODLEBUG);  gameWorld.starveAll(DOODLEBUG);  gameWorld.eatAll(ANT);  gameWorld.moveAll(ANT);  gameWorld.breedAll(ANT);  gameWorld.starveAll(ANT);  gameWorld.turnDone(DOODLEBUG);  gameWorld.turnDone(ANT);  }  while(std::getchar());}


maiworld.h
/******************************************************************************| file        | maiworld.h                                                     || author      | 'Ultim'Ape-Iñago                                               || date        | 2006/11/13                                                     || description | The world class holds positional data and a list of organisims |\******************************************************************************/#ifndef MAIWORLDGRID_H_INCLUDED#define MAIWORLDGRID_H_INCLUDED#include "enumerations.h"#include "twodpoint.h"#include <vector>using std::vector;class Organism; //forward declairationclass DoodleBug;// forward declairationclass Ant;      // forward declairationconst int DEFAULTWIDTH = 20;const int DEFAULTHEIGHT = 20;class MaiWorldGrid{  public:    MaiWorldGrid ( int width = DEFAULTWIDTH,                   int height = DEFAULTHEIGHT );    CreatureType queryCell ( TwoDPoint position ); // Get creature type within cell.    TwoDPoint queryNearest ( CreatureType creature,                             TwoDPoint position ); //Get nearest cell of creature type.    void killCell ( TwoDPoint position ); // remove creature at position    void moveCell ( TwoDPoint posSource,                    TwoDPoint posDest ); // move creature from source to destination, removing creature at dest if exist    void createCell ( CreatureType creature,                      TwoDPoint position ); // create creature at position, removing at position if already exist    void displayGrid (); // print grid to stdout    void populateGridRandom ( CreatureType creature,                              int number ); // create number of creatures randomly around grid    void populateGridRandom ( CreatureType creature,                              double percentage ); // create number of creatrues randomly around grid, perportional to the size of grid    void eatAll ( CreatureType creature );    void moveAll ( CreatureType creature );    void breedAll ( CreatureType creature );    void starveAll ( CreatureType creature );    void turnDone (CreatureType creature);    int getCount() { return creatureCount; }  private:    vector < vector <Organism *> > grid; // the game world grid    //list < Organism> creatures; // array of creatures on gameworld    int creatureCount;};#include "organism.h"#include "organism.ant.h"#include "organism.doodlebug.h"#endif


maiworld.cpp
#include <iostream>#include "maiworld.h"MaiWorldGrid::MaiWorldGrid ( int width,                             int height ){  grid.resize ( height ); // make rows  for ( int i = 0;i < height;i++ ) grid.resize ( width );  for ( int row = 0; row < height;row++ )    for ( int col = 0; col < width; col++ )      grid[row][col] = NULL;  //for ( vector<vector<Organism*> >::iterator row = grid.begin();row < grid.end();row++ ) { //for each row//   grid[row].resize ( width, NULL ); // make columns, with value null in each// }  creatureCount = 0;}CreatureTypeMaiWorldGrid::queryCell ( TwoDPoint position ){// CHECK FOR IF OFF EDGE OF GRID  if ( position.x() < 0 || position.y() < 0 ) {    return BAD;  }  if ( position.x() >=  grid.size() || position.y() >=  grid[0].size()  ) {    return BAD;  }  if ( grid[position.x() ][position.y() ] == NULL ) { // if NULL pointer    return EMPTY; // no creature there  } else {    return grid[position.x() ][position.y() ]->getType();  }}TwoDPointMaiWorldGrid::queryNearest ( CreatureType creature,                             TwoDPoint position ){  vector<TwoDPoint> templist;  TwoDPoint up = TwoDPoint ( position.x() + 1, position.y() );  TwoDPoint down = TwoDPoint ( position.x() - 1, position.y() );  TwoDPoint left = TwoDPoint ( position.x(), position.y() - 1 );  TwoDPoint right = TwoDPoint ( position.x (), position.y() + 1 );/*UNCOMMENT FOR DIAGANALS!*///  TwoDPoint upright = TwoDPoint ( position.x ()+1, position.y() +1 );//  TwoDPoint upleft = TwoDPoint ( position.x ()+1, position.y()  -1);//  TwoDPoint downright = TwoDPoint ( position.x ()-1, position.y() +1 );//  TwoDPoint downleft = TwoDPoint( position.x ()-1, position.y() -1 );//look for creature in all directions  if ( queryCell ( up ) == creature ) {    templist.push_back ( up );  }  if ( queryCell ( down ) == creature ) {    templist.push_back ( down );  }  if ( queryCell ( left ) == creature ) {    templist.push_back ( left );  }  if ( queryCell ( right ) == creature ) {    templist.push_back ( right );  }/* UNCOMMENT FOR DIAGONALS!*///    if ( queryCell ( upright ) == creature ) {//    templist.push_back ( upright );//  }////    if ( queryCell ( downright ) == creature ) {//    templist.push_back ( downright );//  }////    if ( queryCell ( upleft ) == creature ) {//    templist.push_back ( upleft );//  }////    if ( queryCell ( downleft ) == creature ) {//    templist.push_back ( downleft );//  }//do stuff  if ( templist.size() == 0 ) { // no creatures found    return position; // return the middle  } else { // some creatures found    return templist[rand() %  templist.size()  ]; // return random creature  }}voidMaiWorldGrid::killCell ( TwoDPoint position ){  Organism * temp; // create temp  temp = grid[position.x() ][position.y() ]; // copy organism to temp  grid[position.x() ][position.y() ] = NULL; // remove from grid  delete temp; // delete organism// also need to delete from linked list  if ( creatureCount > 0 ) {    creatureCount--;  }}voidMaiWorldGrid::moveCell ( TwoDPoint posSource,                         TwoDPoint posDest ){  if ( grid[posDest.x() ][posDest.y() ] != NULL ) { // if something in dest    killCell ( posDest ); // kill it    posDest.print();  }  grid[posDest.x() ][posDest.y() ] = grid[posSource.x() ][posSource.y() ]; // move creature over  grid[posSource.x() ][posSource.y() ] = NULL; // remove from original location}voidMaiWorldGrid::createCell ( CreatureType creature,                           TwoDPoint position ){  Organism * temp;  if ( creature == ANT ) {    temp = new Ant ( *this, creature, position );  } else if ( creature == DOODLEBUG ) {    temp = new DoodleBug ( *this, creature, position );  } else if ( creature == NONE || creature == EMPTY ) {    temp = NULL;  }  if ( temp != NULL ) {// add to linked list    grid[position.x() ][position.y() ] = temp;    creatureCount++;  }}voidMaiWorldGrid::displayGrid (){  std::cout << " /";  for ( int col = 0; col < grid[0].size(); col ++ ) { // for each col    std::cout << "-";  }  std::cout << "\\\n";  for ( int row = 0; row < grid.size(); row++ ) { //for each row    std::cout << " |";    for ( int col = 0; col < grid[row].size(); col ++ ) { // for each col      if ( grid[row][col] != NULL ) { // if creature        grid[row][col]->print(); // call creatures print      } else { // if no creature        std::cout << " "; // draw empty space      }    }    std::cout << "|\n";  }  std::cout << " \\";  for ( int col = 0; col < grid[0].size(); col ++ ) { // for each col    std::cout << "-";  }  std::cout << "/";  std::cout << std::endl;}voidMaiWorldGrid::populateGridRandom ( CreatureType creature, int number ){  int maxCreatures = grid.size() * grid[0].size();  if ( number > maxCreatures - creatureCount ) { // if making too many creatuers    number = maxCreatures - creatureCount; // only create up to availble space  }  int row;  int col;  TwoDPoint position ( -1, -1 );  bool placed = false;  for ( int i = 0; i < number; i++ ) {    placed = false;    while ( !placed ) {      row = rand() % grid.size();      col = rand() % grid[0].size();      if ( grid[row][col] == NULL ) { // if no creature        position = TwoDPoint ( row, col );        createCell ( creature, position ); // create creature        placed = true;      }    }  }}voidMaiWorldGrid::populateGridRandom ( CreatureType creature, double percentage ){  int maxCreatures = grid.size() * grid[0].size();  int number = static_cast<int> ( maxCreatures * percentage );  populateGridRandom ( creature, number ); // no sense writing redundant code :D}voidMaiWorldGrid::eatAll ( CreatureType creature ){  for ( int row = 0; row < grid.size();row++ ) { //for each row    for ( int col = 0;col < grid[row].size();col++ ) { // for each col      if ( grid[row][col] != NULL ) { // if creature        if ( grid[row][col]->getType() == creature ) { //and the creature            grid[row][col]->eat(); // call creature's eat        }      }    }  }}voidMaiWorldGrid::moveAll ( CreatureType creature ){  for ( int row = 0; row < grid.size();row++ ) { //for each row    for ( int col = 0;col < grid[row].size();col++ ) { // for each col      if ( grid[row][col] != NULL ) { // if creature        if ( grid[row][col]->getType() == creature ) { //and the creature          grid[row][col]->move(); // call creature's move        }      }    }  }}voidMaiWorldGrid::breedAll ( CreatureType creature ){  for ( int row = 0; row < grid.size();row++ ) { //for each row    for ( int col = 0;col < grid[row].size();col++ ) { // for each col      if ( grid[row][col] != NULL ) { // if creature        if ( grid[row][col]->getType() == creature ) { //and the creature          grid[row][col]->breed(); // call creature's breed        }      }    }  }}voidMaiWorldGrid::starveAll ( CreatureType creature ){  vector<Organism*> templist;  // find all starving creatures of creature type  for ( int row = 0; row < grid.size();row++ ) { //for each row    for ( int col = 0;col < grid[row].size();col++ ) { // for each col      if ( grid[row][col] != NULL ) { // if a creature        if ( grid[row][col]->getType() == creature ) { //and the creature type          if ( grid[row][col]->starve() ) {// if starving            templist.push_back ( grid[row][col] );          }        }      }    }  }  for ( int creature = 0;creature < templist.size();creature++ ) { //for each creature    killCell ( templist[creature]->getPosition() ); // kill creature  }}voidMaiWorldGrid::turnDone ( CreatureType creature ){  for ( int row = 0; row < grid.size();row++ ) { //for each row    for ( int col = 0;col < grid[row].size();col++ ) { // for each col      if ( grid[row][col] != NULL ) { // if a creature        if ( grid[row][col]->getType() == creature ) { //and the creature type          grid[row][col]->unMoved();        }      }    }  }}


organism.h
/******************************************************************************| file        | organism.h                                                     || author      | 'Ultim'Ape-Iñago                                               || date        | 2006/11/13                                                     || description | Defines the properties of a general organism                   |\******************************************************************************/#ifndef ORGANISM_H_INCLUDED#define ORGANISM_H_INCLUDED#include "enumerations.h"#include "twodpoint.h"class MaiWorldGrid; // forward declairationclass Organism{  public:    Organism();    Organism ( MaiWorldGrid &worldGridRef,               CreatureType type,               TwoDPoint position );    void setType ( CreatureType type );    CreatureType getType();    void setWorld (MaiWorldGrid &worldGridRef );    MaiWorldGrid* getWorld();    void setPosition ( TwoDPoint position );    TwoDPoint getPosition();    bool hasMoved();    void Moved();    void unMoved();    virtual void eat() = 0;    virtual void move() = 0;    virtual void breed() = 0;    virtual bool starve() = 0;    virtual void print() = 0;  protected:    MaiWorldGrid *worldGrid;    CreatureType type;    TwoDPoint position;    bool isMoved;};#endif


organism.cpp
#include "organism.h"Organism::Organism(){  worldGrid = 0; // no refrence?  type = EMPTY; // "none"  position.set ( -1, -1 );  isMoved = false;}Organism::Organism ( MaiWorldGrid &worldGridRef, CreatureType type, TwoDPoint position ){  setWorld ( worldGridRef );  setType ( type );  setPosition ( position );  isMoved = false;}voidOrganism::setType ( CreatureType type ){  this->type = type;  return;}CreatureTypeOrganism::getType(){  return type;}voidOrganism::setWorld ( MaiWorldGrid &worldGridRef ){  this->worldGrid = &worldGridRef;  return;}MaiWorldGrid *Organism::getWorld(){  return worldGrid;}voidOrganism::setPosition ( TwoDPoint position ){  this->position = position;  return;}TwoDPointOrganism::getPosition(){  return position;}boolOrganism::hasMoved(){  return isMoved;}voidOrganism::Moved(){  isMoved = true;}voidOrganism::unMoved(){  isMoved = false;}


organism.doodlebug.h
/******************************************************************************| file        | organism.doodlebug.h                                           || author      | 'Ultim'Ape-Iñago                                               || date        | 2006/11/13                                                     || description | Defines special properties of a doodlebug                      |\******************************************************************************/#ifndef ORGANISM_DOODLEBUG_H_INCLUDED#define ORGANISM_DOODLEBUG_H_INCLUDED#include "enumerations.h"#include "twodpoint.h"#include "organism.h"class MaiWorldGrid;class DoodleBug : public Organism{  public:    DoodleBug();    DoodleBug ( MaiWorldGrid &WorldGridRef,                CreatureType type,                TwoDPoint position );    void eat();    void move();    void breed();    bool starve();    void print();    //protected:    // MaiWorldGrid &world;    // CreatureType type;    // TwoDPoint position;    // bool hasMoved;  private:    int hunger; // keeps track how hungry the creature is    int horny; // keeps track of how horny the creature is};#include "maiworld.h"#endif


organism.doodlebug.cpp
#include <iostream>#include "organism.doodlebug.h"DoodleBug::DoodleBug() : Organism(){  hunger = 0;  horny = 0;}DoodleBug::DoodleBug ( MaiWorldGrid &WorldGridRef,                       CreatureType type,                       TwoDPoint position )    : Organism ( WorldGridRef,                 type,                 position ){  hunger = 0;  horny = 0;}voidDoodleBug::eat(){  if ( hasMoved() ) { // if moved this turn    return; // do nothing  }  TwoDPoint dest = worldGrid->queryNearest ( ANT, position );  if (dest == position && hunger >=3) { // if super hungry    //dest = worldGrid->queryNearest (DOODLEBUG, position); // become canaible  }  if ( dest == position ) { // if not find food    return; // do not eat, do not collect move penatly  } else { // if found food    worldGrid->killCell ( dest ); // munch munch!    hunger = 0; // MMMmmm!  food    horny++; // survived a turn, me so horny!    worldGrid->moveCell ( position, dest ); // move me there    position = dest;    Moved();    return; // done eating  }}voidDoodleBug::move(){  if ( hasMoved() ) { // if moved this turn    return; // do nothing  }  horny++; // survived a turn, me so honry!  hunger++; // surived a turn, me so hungry!  TwoDPoint dest = worldGrid->queryNearest ( EMPTY, position );  if ( dest == position ) { // if no surrounding spot    Moved(); // has moved this turn    return; // do nothing  } else { // if found surrounding spot    worldGrid->moveCell ( position, dest ); // move me there    position = dest; // record the move    Moved(); // has moved this turn;    return; // done moving  }}voidDoodleBug::breed(){  if ( horny >= 8 ) { // if want sex now!    TwoDPoint dest = worldGrid->queryNearest ( EMPTY, position );    if ( dest == position ) { // but no room for sex      return; // no sex for you    } else { // else if is room for sex      worldGrid->createCell ( DOODLEBUG, dest ); // yay sex!      horny = 0; // no more sex drive      return; // doen sexing    }  } else { // else not horny    return; // so do nothing  }}boolDoodleBug::starve(){  if ( hunger >= 3 ) { // if not eaten enough    return true; // should be killed  } else { // else    return false; // stay alive  }}voidDoodleBug::print(){    std::cout<<"X";}


organism.ant.h
/******************************************************************************| file        | organism.ant.h                                                 || author      | 'Ultim'Ape-Iñago                                               || date        | 2006/11/13                                                     || description | Defines special properties of an ant                           |\******************************************************************************/#ifndef ORGANISM_ANT_H_INCLUDED#define ORGANISM_ANT_H_INCLUDED#include "enumerations.h"#include "twodpoint.h"#include "organism.h"class MaiWorldGrid;class Ant : public Organism{  public:    Ant();    Ant ( MaiWorldGrid &WorldGridRef,          CreatureType type,          TwoDPoint position );    void eat();    void move();    void breed();    bool starve();    void print();    //protected:    // MaiWorldGrid &world;    // CreatureType type;    // TwoDPoint position;    // bool hasMoved;  private:    int hunger;    int horny;};#include "maiworld.h"#endif


organism.ant.cpp
#include <iostream>#include "organism.ant.h"Ant::Ant() : Organism(){  hunger = 0;  horny = 0;}Ant::Ant ( MaiWorldGrid &WorldGridRef,           CreatureType type,           TwoDPoint position )    : Organism ( WorldGridRef,                 type,                 position ){  hunger = 0;  horny = 0;}voidAnt::eat(){  hunger = 0; // ants don't need to eat, intsa full}voidAnt::move(){  if ( hasMoved() ) { // if moved this turn    return; // do nothing  }  horny++; // survived a turn, me so honry!  hunger++; // surived a turn, me so hungry!  TwoDPoint dest = worldGrid->queryNearest ( EMPTY, position );  if ( dest == position ) { // if no surrounding spot    Moved(); // has moved this turn    return; // do nothing  } else { // if found surrounding spot    worldGrid->moveCell ( position, dest ); // move me there    position = dest; // record the move    Moved(); // has moved this turn;    return; // done moving  }}voidAnt::breed(){  if ( horny >= 1 ) { // if want sex now!    TwoDPoint dest = worldGrid->queryNearest ( EMPTY, position );    if ( dest == position ) { // but no room for sex      horny = 0;      return; // no sex for you    } else { // else if is room for sex      worldGrid->createCell ( ANT, dest ); // yay sex!      horny = 0; // no more sex drive      return; // doen sexing    }  }}boolAnt::starve(){  return false; // ants don't starve}voidAnt::print(){    std::cout<<"o";}
I sugest slow expantions into it.
Try to make a food chain, then a food tree.

Plants grow at a set rate per square so long as it still has growth on it.
A dead square "reseeds" after some time if there are plants ajacent.

Ants eat plants off a square at some rate till that square dies, or the ant
decides to move on.

Lions eat ants.

-------------
Lions chase ants.
Ants run from lions.
Lions run from large enough populations of ants.
Ants like to wonder, and dont always notice lions aproaching.

-------------
Add a second Ant like animal with different parameters.
Add a new Lion like animal with different parameters.
Add different plants that have different things that eat them.

ect.
ect.
ect.


There is TONES of room to make this into a fun little demo thing to watch and
tweek the parameters of.
Quote:Original post by KulSeran
I sugest slow expantions into it.
Try to make a food chain, then a food tree.

Plants grow at a set rate per square so long as it still has growth on it.
A dead square "reseeds" after some time if there are plants ajacent.

Ants eat plants off a square at some rate till that square dies, or the ant
decides to move on.

Lions eat ants.


Yes, I like where this is going... the ants as it is are basically just plants in that they are breeding (seeding) in random directions. Adding in a "grazing" option would be pretty neat funcitonality. Although it would be hard to tell if the ant was grazing or moving. Maybe things like trees and other non movable objects / varied terrain.

Quote:Original post by KulSeranLions chase ants.
Ants run from lions.
Lions run from large enough populations of ants.
Ants like to wonder, and dont always notice lions aproaching.


I could expand the map's queryneraest into a quiry directonal... allowing the ants to look around... hehe, it'd be cool for lions to hide in thick vegitation.

I'd need some basic pathfinding or steering behavior... that would be realitively easy, if timeconsuming. Yay flocking!



Quote:Original post by KulSeranAdd a second Ant like animal with different parameters.
Add a new Lion like animal with different parameters.
Add different plants that have different things that eat them.


Like cheetas (fast), leopards (ambush), crocidials (water only)... hmm. I should make it an entire african savhanna



Quote:Original post by KulSeran
There is TONES of room to make this into a fun little demo thing to watch and
tweek the parameters of.


I should make the gameworld display not just in ascii, but in opengl. that would make it very interesting to watch.

This topic is closed to new replies.

Advertisement