My First Project: Space game Concept Paper.

Started by
6 comments, last by Tom Sloper 13 years, 6 months ago
I've recently been learning Java, and with it, programming in general (CS1 class in college).

As a side project I'm looking to create a simple space based game. With that idea in mind, I'm tossing up a simple concept paper on this project to help get me started. In class we've started on this small game with a bird eating insects, but I was able to finish that. This project will be one of my own ideas.

The summary:

This is a little space based top down game (viewpoint similar to asteroids).

The purpose of the game is to fly around a sector of space (represented by a 2d array of tiles.) Destroying enemy ships, Upgrading your ship, and exploring planets to find the items you need to open a wormhole that will get you to the "big bad".

When flying through space, the controls of the ship will be:

arrows: up/dn control speed.
Arrows: Left/right rotate ship.
Space: Fire.

Moving off of the edge of the screen will load the next tile.

Tiles will have a mix of moving enemies, moving meteors, stationary planets, and stationary "Capital ships."

Flying over a planet will enter Planetary investigation mode.

Controls for planetary investigation:
Direction arrows: move ship in desired direction.
Space: fires guns
Right Control Btn: Aquires items from the planet surface.

The planet's surface is a large area with a camera that focuses on the player's ship. When the ship moves, the ground moves around the ship instead.


When attacking a capital ship, you destroy the guns on the outside, and then fly onto the inside to destroy the core:

Controls for Capital ship attacks.
(similar to "r-type")
Arrows up/down: move ship up or down
arrows left or right: move ship left or right (up to 1/2 screen)



Exploring planets, destroying ships, etc. earn upgrades for the ship, and possibly one of the 3 pieces needed to open the wormhole that opens the final boss battle which takes place within normal space.


If your curious about the variety of controls, this project is designed to be a learning process for me, the various controls and play styles are designed to be practice, not necessarily good game design.

I will be using java utility "AnimApp" and "AAlib" as my graphical tools, as such the graphics in the game will be VERY simple (basic shapes).

I also will not be having sound in the game at this point in time.

The player will be able to choose between a 10x10 or a 20x20 grid for the game. Tiles will be generated randomly, with the exception of certain key tiles, which will be placed randomly but pre-built.

Planets will be randomly generated.

The capital ship segments will be randomly generated.



Feedback will be appreciated. I will attempt to post the finished product when complete. I may post unfinished versions for feedback.
Ideas presented here are free. They are presented for the community to use how they see fit. All I ask is just a thanks if they should be used.
Advertisement
Hi there,

Your project sounds interesting. My main feedback is that it seems pretty ambitious considering you're just learning Java.

Quote:Exploring planets, destroying ships, etc. earn upgrades for the ship, and possibly one of the 3 pieces needed to open the wormhole that opens the final boss battle which takes place within normal space.


This is more complicated. I would start off with normal ships and maybe a bigger capital ship.

Quote:
The player will be able to choose between a 10x10 or a 20x20 grid for the game.


Why the choice? I would just choose one for now.

Quote:
Tiles will be generated randomly, with the exception of certain key tiles, which will be placed randomly but pre-built.

Planets will be randomly generated.

The capital ship segments will be randomly generated.


Randomly generated is more complicated than hard-coded.

Anyways, good luck. Do post your result. A working prototype would be a good way to get more feedback.
Quote:Original post by loom_weaver
Hi there,

Your project sounds interesting. My main feedback is that it seems pretty ambitious considering you're just learning Java.

Quote:Exploring planets, destroying ships, etc. earn upgrades for the ship, and possibly one of the 3 pieces needed to open the wormhole that opens the final boss battle which takes place within normal space.


This is more complicated. I would start off with normal ships and maybe a bigger capital ship.

Quote:
The player will be able to choose between a 10x10 or a 20x20 grid for the game.


Why the choice? I would just choose one for now.

Quote:
Tiles will be generated randomly, with the exception of certain key tiles, which will be placed randomly but pre-built.

Planets will be randomly generated.

The capital ship segments will be randomly generated.


Randomly generated is more complicated than hard-coded.

Anyways, good luck. Do post your result. A working prototype would be a good way to get more feedback.


I'm hoping that it doesn't get overly complicated. Most of the things will end up being simple flags. (I.E. one upgrade for weapons, one for engine, etc.) These will simply enter into some if-thens when flagged true and change the procedure.

My random generation will be fairly simple. I'll be pre-making the objects and then simply having the generator place them in. The school project I used a while back I placed obstacles into the world using random generation. It should be doable with the level I'm looking at.

The thing that I think is going to kill me is I want asteroids to try to bounce convincingly off of each other (as circles) though without figuring in speed (everything will move and bounce at equal speed, no rotation)

I have a fairly good idea of the code I need in my head for most of the concepts. I'm just hoping it comes together fairly nicely.

Ideas presented here are free. They are presented for the community to use how they see fit. All I ask is just a thanks if they should be used.
So it's a multi-screen asteroids when it comes to navigation.
Would you elaborate on planetary explaration? For first, what's the goal of this mode? How does the player benefits from this?
As far as I've got it, planetary exploration is very similar, in rewarding, to standard space exploration.
Quote:The capital ship segments will be randomly generated.
Maybe like in shellcore (a flash game)? Sounds good, but I bet you really mean "procedurally generated".

Previously "Krohm"

Quote:Original post by Krohm
So it's a multi-screen asteroids when it comes to navigation.

Pretty much.

Quote:Would you elaborate on planetary explaration? For first, what's the goal of this mode? How does the player benefits from this?
As far as I've got it, planetary exploration is very similar, in rewarding, to standard space exploration.


My thoughts for both the planets and the capital ships will be that those will be what contain most of the upgrades. I'm not positive how I will do it with the capital ships quite yet, but when it comes to the planets they will be found and picked up during planetary exploration.

Quote:
Quote:The capital ship segments will be randomly generated.
Maybe like in shellcore (a flash game)? Sounds good, but I bet you really mean "procedurally generated".


Yes, procedurally generated is probably the better name. Random just rolls off the tongue a bit better.

Ideas presented here are free. They are presented for the community to use how they see fit. All I ask is just a thanks if they should be used.
Ok. I have my first early test bed ready to go. This is a simple, game based on the space exploration portion of the game. In this version, you control the space ship, avoid the large meteors, and try to shoot the small flying spaceships.

Controls:
Up/Down: increase/decrease speed
Left/Right: rotate the spaceship
Spacebar: fires the gun

The "map" is a 2 dimensional array, you start off in the lower left corner (0.0). You may move to other tiles by flying off of the edges, though the outside tiles have edges you cannot fly through.

On the start screen you can choose between a "small" 3x3 tiles game or a "Large" 5x5 tiles game.

This is a "complete" game with start screen, points, lives, and health.

There are no advanced graphics (or even sprites). There are no sound effects.

Source code is as follows:

The main function is in the StarGame class.


Stargame.java
import java.awt.event.KeyEvent;import java.util.ArrayList;import java.util.Random;public class StarGame extends AnimApp{  private Ship a;  public Ship player, shot;  private int k,t,l,r,c;  public int points = 0, lives = 4, health = 5, maxHealth=5;  public int enemycount = 5, meteorcount = 5;  public Room[][] map;  public String screen = "start";  public int mapSize = 5;  public int row =0, col = 0;  public boolean fire = false;  public int shotSpeed = 20;  private StartScreen start;  public StarGame()  {    super( "StarGame", 500, 500, 33333333 );  }  public void prepare()  {     if(screen.equals("map"))       {        player = new Ship(false , 10, 250, 100, RGB.WHITE, 0, 45 );      shot = new Ship (true ,7, 250, 100, RGB.BLUEGREEN,0,45);           map = new Room [mapSize][mapSize];          for(r=0; r < mapSize; r++)      {        for(c=0; c < mapSize; c++)        {          map[r][c] = new Room(this);          map[r][c].prepare(meteorcount);          map[r][c].populate(enemycount);        }      }    }      else if(screen.equals("start"))      {          start = new StartScreen(this);        start.prepare();       }  }   public void doFrame()  {    if(screen.equals("map"))    {      player.draw();      player.fly();      shot.fly();      if (fire == true)        shot.draw();      map[row][col].action();     }     else if(screen.equals("start"))       start.action();            }  public void keyPressed( KeyEvent e )  {    int key=0;    int code = e.getKeyCode();    double dirnAmount = 5;    double speedAmount = 1;    if( code == KeyEvent.VK_LEFT )    {      key = 1;     }    else if( code == KeyEvent.VK_RIGHT )    {      key = 2;     }    else if( code == KeyEvent.VK_UP )    {      key = 3;     }    else if( code == KeyEvent.VK_DOWN )    {      key = 4;     }    else if( code == KeyEvent.VK_SPACE )    {      key = 5;     }    else if( code == KeyEvent.VK_ENTER )    {      key = 6;     }        if(screen.equals("map"))      map[row][col].keys(key);    else if(screen.equals("start"))      start.keys(key);  }  public static void main(String[] args)  {    new StarGame();  }}


StartScreen.java
import java.util.ArrayList;import java.util.Random;public class StartScreen{  private StarGame game;  private int choice;//constructor   public StartScreen(StarGame gameIn)  {    game = gameIn;    choice = 1;  }//for use in the prepare method of StarGame;  public void prepare()  {    AALib.setBackColor( new RGB( 0, 0, 0 ) );  }   //processes during the doFrame method of StarGame.  public void action()  { //ON SCREEN INFORMATION    AALib.setColor( new RGB( 250, 250, 250 ) );    AALib.drawText("Star Cruiser", 60, 300, .5, 0);    AALib.drawText("Small Game", 190, 200, .2, 0);    AALib.drawText("Large Game", 190, 150, .2, 0);    AALib.drawText("Exit", 190, 100, .2, 0);            AALib.setColor( new RGB( 0, 0, 128));    if(choice == 1)    {      AALib.setDepth( 100 );      AALib.begin( "polygon" );       AALib.point( 185, 190 );       AALib.point( 350, 190 );       AALib.point( 350, 230 );       AALib.point( 185, 230 );      AALib.end();    }    else if(choice == 2)    {      AALib.setDepth( 100 );      AALib.begin( "polygon" );       AALib.point( 185, 140 );       AALib.point( 350, 140 );       AALib.point( 350, 180 );       AALib.point( 185, 180 );      AALib.end();    }    else if(choice == 3)    {      AALib.setDepth( 100 );      AALib.begin( "polygon" );       AALib.point( 185, 90 );       AALib.point( 350, 90 );       AALib.point( 350, 130 );       AALib.point( 185, 130 );      AALib.end();    }      }//KEYBOARD CONTROLS    public void keys(int keysIn)  {    if( keysIn == 3 )//up    {      if(choice > 1)       choice--;    }    else if( keysIn == 4 )//down    {       if(choice < 3)       choice++;    }    else if( keysIn == 6 ) //enter    {      if (choice == 1)      {        game.screen = "map";        game.mapSize = 3;        game.prepare();      }      else if (choice == 2)      {        game.screen = "map";        game.mapSize = 5;        game.prepare();      }      else if (choice == 3)      {        System.exit(0);      }    }  }}


Ship.java
import java.util.Random;public class Ship{  public double radius;  // radius of the Ship's collision circle  public double cx, cy;  // coords of the center point of the collision circle  private RGB color;      // color of the Ship  public double speed;   // speed of the Ship (duh!)  public double dirn;    // angle of travel in degrees (standard trig)   public boolean filled;  public Ship(boolean filledIn, double radiusIn, double cxIn, double cyIn, RGB colorIn, double speedIn, double dirnIn)  {    radius = radiusIn;  cx = cxIn;  cy = cyIn;    color = colorIn;  speed = speedIn;  dirn = dirnIn;    filled = filledIn;  }  public void draw()  {    AALib.setColor( color );    if(filled)    {      // draw the collision circle:      AALib.drawDisk( cx, cy, radius );    }    else    {      // draw the collision circle:      AALib.drawCircle( cx, cy, radius );      // draw segment from center to edge:      AALib.begin( "lines" );        AALib.point( cx, cy );        AALib.point( cx + radius*Math.cos( Math.toRadians(dirn)),                      cy + radius*Math.sin( Math.toRadians(dirn)) );      AALib.end();    }  }     public void fly()  {    cx += speed*Math.cos( Math.toRadians(dirn) );    cy += speed*Math.sin( Math.toRadians(dirn) );  }  public void turn( double amount )  {    dirn += amount;  }  public void accelerate( double amount )  {   if(speed < 10)      speed += amount;   else     speed = 10;  }  public boolean isOffLeftEdge()  {    return cx-radius < 0;    }  public boolean isOffRightEdge()  {    return cx + radius > 500;    }   public Boolean isOffTopEdge()  {    return cy+ radius > 450;  }    public boolean isOffBottomEdge()  {    return cy-radius < 0;  }  public boolean meteorCollision(Meteor other)  {    double xSqr, ySqr, radSqr;    xSqr = (cx-other.cx)*(cx-other.cx);    ySqr = (cy-other.cy)*(cy-other.cy);    radSqr = (radius+other.radius) * (radius+other.radius);    return xSqr + ySqr < radSqr;  }  public boolean enemyCollision(Enemy other)  {    double xSqr, ySqr, radSqr;    xSqr = (cx-other.cx)*(cx-other.cx);    ySqr = (cy-other.cy)*(cy-other.cy);    radSqr = (radius+other.radius) * (radius+other.radius);    return xSqr + ySqr < radSqr;  }}


RGB.java
public class RGB{  public int red, green, blue;  public RGB( int r, int g, int b )  {  red = r;  green = g;  blue = b;  }  public static RGB RED = new RGB( 255, 0, 0 );  public static RGB GREEN = new RGB( 0, 255, 0 );  public static RGB BLUE = new RGB( 0, 0, 255 );  public static RGB WHITE = new RGB( 255, 255, 255 );  public static RGB YELLOW = new RGB( 255, 255, 0 );  public static RGB BLACK = new RGB( 0, 0, 0 );  public static RGB ORANGE = new RGB( 255, 128, 84 );  public static RGB BLUEGREEN = new RGB( 0, 255, 255 );}

Ideas presented here are free. They are presented for the community to use how they see fit. All I ask is just a thanks if they should be used.
Source continued...

Room.java
import java.util.ArrayList;import java.util.Random;public class Room{  public ArrayList<Enemy> enemies;  //things to kill  public ArrayList<Meteor> meteors; //things to not hit   private int l, k,t=0; //loop variables  private StarGame game; //For back referencing//constructor   public Room(StarGame gameIn)  {    enemies = new ArrayList<Enemy>();    meteors = new ArrayList<Meteor>();    game = gameIn;  }//for use in the prepare method of StarGame;  public void prepare(int meteorIn)  {    AALib.setBackColor( new RGB( 0, 0, 0 ) );    boolean good = false;                    while(t<meteorIn)  //supposed to keep meteors seperate    {      Meteor temp = new Meteor();      if(game.player.meteorCollision(temp) == false)       {        if (meteors.size() == 0)        {          meteors.add(temp);          t++;        }        else        {          l=0;          while (l < meteors.size())          {            if(temp.meteorCollision(meteors.get(l)))            {              good = false;              l = meteors.size();            }            else            {              l++;              good = true;            }                   }          if(good)          {            meteors.add(new Meteor());            t++;          }               }      }    }  }//populates the room with enemies, runs every time you enter a new screen  public void populate(int enemyIn)  {    enemies.clear();    for(k=0; k<enemyIn; k++)    {      enemies.add( new Enemy() );    }  }//processes during the doFrame method of StarGame.  public void action()  {    for( t=0; t<meteors.size(); t++ )  //meteor draw and collision detection    {     meteors.get(t).draw();     if(game.player.meteorCollision(meteors.get(t)))        {          game.lives--;           if(game.lives>0)          {           game.player = new Ship(false, 10, 250, 100, RGB.WHITE, 0, 45 );           game.health = game.maxHealth;           game.map[game.row][game.col].populate(game.enemycount);          }          else           {            game.player = new Ship(false, 0,0,0,RGB.BLACK,0,0);            game.map[game.row][game.col].populate(game.enemycount);          }        }    }    for( k=0; k<enemies.size(); k++ )  //collision detection between enemy/player and draw    {      enemies.get(k).draw();      enemies.get(k).fly();      Random generator = new Random();      l = generator.nextInt(100);        if(l<50)        enemies.get(k).dirn += 10;      else        enemies.get(k).dirn -= 10;           if(enemies.get(k).isOffSideEdge())        enemies.get(k).dirn = 180-(enemies.get(k).dirn);      if(enemies.get(k).isOffHorizEdge())        enemies.get(k).dirn = 360-(enemies.get(k).dirn);      if(game.player.enemyCollision(enemies.get(k)))      {        game.health --;         enemies.remove(enemies.get(k));        if(game.health == 0)        {          game.lives --;          if(game.lives>0)          {           game.player = new Ship(false, 10, 250, 100, RGB.WHITE, 0, 45 );           game.health = game.maxHealth;           game.map[game.row][game.col].populate(game.enemycount);          }          else           {            game.player = new Ship(false, 0,0,0,RGB.BLACK,0,0);            game.map[game.row][game.col].populate(game.enemycount);          }        }      }    }   //ROOM SWITCHING    if (game.player.isOffLeftEdge())    {          if(game.row > 0)        {         game.row--;         game.map[game.row][game.col].populate(game.enemycount);         game.player.cx = 500 - game.player.radius;        }      else        game.player.cx = game.player.radius;    }    if(game.player.isOffRightEdge())    {        if(game.row < game.mapSize-1)        {         game.row++;         game.map[game.row][game.col].populate(game.enemycount);         game.player.cx = game.player.radius;        }      else        game.player.cx = 500-game.player.radius;    }    if(game.player.isOffTopEdge())    {      if(game.col < game.mapSize -1)      {        game.col++;        game.map[game.row][game.col].populate(game.enemycount);        game.player.cy = game.player.radius;      }      else        game.player.cy = 450 - game.player.radius;    }          if(game.player.isOffBottomEdge())    {      if(game.col > 0)      {        game.col--;        game.map[game.row][game.col].populate(game.enemycount);        game.player.cy = 450 - game.player.radius;      }      else        game.player.cy = game.player.radius;    }          //Shot Declarations    if( game.shot.isOffTopEdge()|| game.shot.isOffBottomEdge()||                             game.shot.isOffRightEdge()|| game.shot.isOffLeftEdge()      )        {          game.fire = false;          game.shot.cx = game.player.cx;          game.shot.cy = game.player.cy;          game.shot.dirn = game.player.dirn;          game.shot.speed = game.player.speed;        }    for( t=0; t<meteors.size(); t++ )    {     if(game.shot.meteorCollision(meteors.get(t)))        {          game.fire = false;          game.shot.cx = game.player.cx;          game.shot.cy = game.player.cy;          game.shot.dirn = game.player.dirn;          game.shot.speed = game.player.speed;        }    }    for( k=0; k<enemies.size(); k++ )    {      if(game.shot.enemyCollision(enemies.get(k)))      {       game.points += enemies.get(k).points;       enemies.remove(enemies.get(k));      }    }//ON SCREEN INFORMATION    AALib.setColor( new RGB( 250, 250, 250 ) );    AALib.drawText("Score: "+game.points +"   Lives: " + game.lives+"   Health: " + game.health , 10, 450, .1, 0);    AALib.drawText("Room: "+ game.row+"."+game.col, 300, 450, .1, 0);    if(game.lives == 0)    {        AALib.setColor( new RGB( 250, 250, 250 ) );      AALib.drawText("GAME OVER", 50, 250, .5, 3);    }  }//KEYBOARD CONTROLS    public void keys(int keysIn)  {    double dirnAmount = 5;    double speedAmount = 1;    if( keysIn == 1 )//left    {      if(game.fire == false)      {        game.player.turn( dirnAmount );        game.shot.dirn = game.player.dirn;      }      else        game.player.turn( dirnAmount );    }    else if( keysIn == 2 )//right    {      if(game.fire == false)      {        game.player.turn( -dirnAmount );        game.shot.dirn = game.player.dirn;      }      else        game.player.turn( -dirnAmount );    }    else if( keysIn == 3 ) //up    {      if(game.fire == false)      {        game.player.accelerate( speedAmount );        game.shot.speed = game.player.speed;      }      else        game.player.turn( speedAmount );     }    else if( keysIn == 4 ) //down    {      if(game.fire == false)      {        game.player.accelerate( -speedAmount );        game.shot.speed = game.player.speed;      }      else        game.player.turn( -speedAmount );     }    else if( keysIn == 5 )    {      game.fire = true;      game.shot.speed = game.shotSpeed;    }  }}


Enemy.java
import java.util.Random;public class Enemy{  public double radius;  // radius of the Enemy's collision circle  public double cx, cy;  // coords of the center point of the collision circle  private RGB color;      // color of the Enemy  private double speed;   // speed of the Enemy (duh!)  public double dirn;    // angle of travel in degrees (standard trig)   public int points;  public Enemy( double radiusIn, RGB colorIn, double speedIn)  {    Random generator = new Random();     radius = radiusIn;    cx = generator.nextInt( 490 )+5;    cy = generator.nextInt( 44 )+5;    color = colorIn;    speed = speedIn;    dirn = generator.nextInt( 360 );    points = 10;  }  public Enemy ()  {    Random generator = new Random();     int x = generator.nextInt(100);    radius = 5;    cx = generator.nextInt( 490 )+5;    cy = generator.nextInt(440)+5;    dirn = generator.nextInt( 360 );      if(x > 65)    {      color = RGB.YELLOW;      speed = 5;        points = 20;    }    else    {      color = RGB.BLUE;      speed = 2.5;      points = 10;    }  }  public void draw()  {    AALib.setColor( color );    // draw the collision circle:    AALib.drawCircle( cx, cy, radius );    AALib.begin( "polygon" );      AALib.point( cx+radius,cy );      AALib.point( cx, cy+radius );      AALib.point(cx-radius, cy );      AALib.point( cx, cy-radius );    AALib.end();  }  public void fly()  {    cx += speed*Math.cos( Math.toRadians(dirn) );    cy += speed*Math.sin( Math.toRadians(dirn) );  }  public void turn( double amount )  {    dirn += amount;  }  public void accelerate( double amount )  {    speed += amount;  }  public boolean isOffSideEdge()  {    return cx-radius < 0 || cx + radius > 500;    }   public Boolean isOffHorizEdge()  {    return cy+ radius > 450 || cy-radius < 0;  }}


meteor.java
import java.util.Random;public class Meteor{  public double radius;  // radius of the Meteor's collision circle  public double cx, cy;  // coords of the center point of the collision circle  private RGB color;      // color of the Meteor  private double speed;   // speed of the Meteor (duh!)  public double dirn;    // angle of travel in degrees (standard trig)   public int points;  public Meteor( double radiusIn, RGB colorIn, double speedIn)  {    Random generator = new Random();     radius = radiusIn;    cx = generator.nextInt( 500 );    cy = generator.nextInt( 500 );    color = colorIn;  }  public Meteor ()  {    Random generator = new Random();     int x = generator.nextInt(100);    radius = generator.nextInt( 10 )+10;    cx = generator.nextInt( 460 )+20;    cy = generator.nextInt(410)+20;    color = RGB.ORANGE;          }  public void draw()  {    AALib.setColor( color );    double k;    for( k=radius; k>0; k-- )    {      AALib.drawCircle(cx, cy, k );    }  }  public boolean isOffSideEdge()  {    return cx-radius < 0 || cx + radius > 500;    }   public boolean isOffHorizEdge()  {    return cy+ radius > 500 || cy-radius < 0;  }  public boolean meteorCollision(Meteor other)  {    double xSqr, ySqr, radSqr;    xSqr = (cx-other.cx)*(cx-other.cx);    ySqr = (cy-other.cy)*(cy-other.cy);    radSqr = (radius+other.radius) * (radius+other.radius);    return xSqr + ySqr < radSqr;  }}


That should be all the files someone needs to compile and run. I think everyone has access to AAlib and AnimApp.

Feedback and suggestions on how to clean up the code would be greatly apprciated.


Known Issues:
Some enemy ships get trapped along the edges of the screen.
Sometimes the meteors spawn directly over the player, causing an instant game-over. I have code that SHOULD stop that, but it is apparently not working as intended.


P.S. if these posts have moved beyond game design and into game programming, feel free to have them moved.

Ideas presented here are free. They are presented for the community to use how they see fit. All I ask is just a thanks if they should be used.
Quote:Original post by robert4818
P.S. if these posts have moved beyond game design and into game programming, feel free to have them moved.

I have a better idea.
Since it started as a game design thread, I'll let it stay here.
But since it's turning into a programming thread, I'll close it, and you can copy portions as needed and post in a more appropriate forum.
If you want to discuss game design again, go ahead and start a new thread.

-- Tom Sloper -- sloperama.com

This topic is closed to new replies.

Advertisement