Week 7: Midterm

Inspiration:

I really like trains, so I wanted my game to represent that aspect of my interests. I was inspired by the Dino game on Google Chrome, as that had similar characteristics.

Process:

I basically tried to brute force this entire code. I found a video of someone who made their own version of the Dino game from Google, from which I drew some inspiration.

I have five classes: Ground, Tree, Obstacle, Player, and Station.

The ground is simply a line that acts as the rail, and has regularly appearing lines underneath which represent the ties of the track.

The obstacles are now only the red signals, but it used to have the green signals and stations. There is a boolean for SPAD (Signal Passed at Danger) which triggers a fail if you pass a red signal too quickly.

The trees now include the green signals, as the trees and green signals are all passive background objects.

The player always stays in the same spot and “controls” the train. They are really controlling the speed at which the objects move across the background. The W and S keys control the speed.

The station has a green rectangle underneath the image that is suppose to denote the stopping zone, however the station no longer loads and I don’t know why.

Final work:

Challenges:

I had lots of challenges. If you had seen my midterm progress post, you can tell how different the two versions are. The biggest two issues are that the game will fail seemingly for no reason, and the station apparently never shows up. I think that is because the green signals and station both used to be a part of obstacles, there is some vestige that no longer appears on screen, but still fails. I also tried to get the station to load only after a certain amount of time, but once it was moved to its own class, it stopped working.

If you keep your speed under 3 km/h, you won’t fail, but also the station will never appear. Because I was attempting to fix this issue, I didn’t have time to add sound.

Code:

PImage myTrain;
PImage greenSignal;
PImage redSignal;
PImage trainStation;
PImage tree;
PImage tree1;

ArrayList<Obstacle> obstacles = new ArrayList<Obstacle>();
ArrayList<Station> stations = new ArrayList<Station>();
ArrayList<Tree> trees = new ArrayList<Tree>();
ArrayList<Ground> grounds = new ArrayList<Ground>();

int obstacleTimer = 0;
int minTimeBetObs = 100;
int randomAddition = 0;
int groundCounter = 0;
float speed = 0;

int groundHeight = 100;
int playerXpos = 100;
int highScore = 0;

Player driver;

void setup(){
  size(1024,400);
  frameRate(60);
   
  
  myTrain = loadImage("myTrain0000.png");
  myTrain.resize(0, 100);
  greenSignal = loadImage("signalGreen0000.png");
  greenSignal.resize(50, 0);
  redSignal = loadImage("signalRed0000.png");
  redSignal.resize(50, 0);
  trainStation = loadImage("stationTrain0000.png");
  trainStation.resize(500, 0);
  tree = loadImage("chree0000.png");
  tree.resize(0, 100);
  tree1 = loadImage("chree0001.png");
  tree1.resize(0, 100);
  
  driver = new Player();
}

void draw(){
  background(250);
  stroke(0);
  strokeWeight(2);
  line(0, height - groundHeight, width, height - groundHeight);
  
  updateObstacles();
  addStations();
  
  if(driver.score > highScore){
    highScore = driver.score;
  }
  
  textSize(20);
  fill(0);
  text("score: " + driver.score, 5, 20);
  text("High Score: " + highScore, width - (140 + (str(highScore).length() * 10)), 20);
  text("Speed (km/h): " + speed, width/2, 20);
  text("Press W to Accelerate, S to Deccelerate", width/2, 50);
}

void keyPressed(){
  switch(key){
    case'w': speed++;
              break;
    case's': speed--;
              break;
  }
}

void keyReleased(){
  switch(key){
              
    case'r': if(driver.dead){
               restart();
              }
              break;
  }
}

void updateObstacles(){
  showObstacles();
  driver.show();
  if(!driver.dead){
    obstacleTimer ++;
    if(obstacleTimer > minTimeBetObs + randomAddition){
      addObstacles();
    }
    groundCounter++;
    if(groundCounter > 10){
      groundCounter = 0;
      grounds.add(new Ground());
    }
    moveObstacles();
    driver.update();
  }
  else{
   textSize(32); 
   fill(0);
   text("You Failed and Endangered the Lives of Everyone Onboard", 180, 200);
   textSize(16);
   text("(Press R to Restart)", 330, 230);
  }
}

void showObstacles(){
 for(int i = 0; i < grounds.size(); i++){
   grounds.get(i).show();
 }
 for(int i = 0; i < obstacles.size(); i++){
   obstacles.get(i).show();
 }
 for(int i = 0; i < trees.size(); i++){
   trees.get(i).show();
 }
}

void addObstacles(){
  if(random(1) < 0.15){
    trees.add(new Tree(floor(random(3))));
  }
  else{
    obstacles.add(new Obstacle(floor(random(3))));
  }
  randomAddition = floor(random(50));
  obstacleTimer = 0;
}

void moveObstacles(){
  for(int i = 0; i < grounds.size(); i++){
   grounds.get(i).move(speed);
   if(grounds.get(i).posX < -playerXpos){
     grounds.remove(i);
     i--;
   }
 }
 for(int i = 0; i < obstacles.size(); i++){
   obstacles.get(i).move(speed);
   if(obstacles.get(i).posX < -playerXpos){
     obstacles.remove(i);
     i--;
 }
 }
 for(int i = 0; i < trees.size(); i++){
   trees.get(i).move(speed);
   if(trees.get(i).posX < -playerXpos){
     trees.remove(i);
     i--;
   }
 }
}

void addStations(){
  if(driver.score > 10){
    stations.add(new Station(1));
  }
}

void restart(){
  driver = new Player();
  obstacles = new ArrayList<Obstacle>();
  trees = new ArrayList<Tree>();
  grounds = new ArrayList<Ground>();
  
  obstacleTimer = 0;
  randomAddition = floor(random(50));
  groundCounter = 0;
  speed = 0;
}

class Ground{
  float posX = width;
  float posY = height - groundHeight + 1;
  int w = 1;
  
  Ground(){
  }
  
  void show(){
   stroke(0);
   strokeWeight(3);
   line(posX, posY, posX + 10, posY);
  }
  
  void move(float speed){
   posX -= speed; 
  }
}

class Obstacle{
  float posX;
  int w, h;
  int type;
  
  Obstacle(int t){
    posX = width;
    type = t;
    switch(type){
      case 0: w = 30;
              h = 60;
              break;
    }
  }
  
  void show(){
    switch(type){
      case 0: image(redSignal, posX - redSignal.width/2, height - groundHeight - redSignal.height);
              break;
    }
  }
  
  void move(float speed){
    posX -= speed;
  }
  
  boolean SPAD(float playerX){
    float playerRight = playerX + myTrain.width/2;
    float thisRight = posX + redSignal.width/2;
    
    if(playerRight > thisRight && speed > 3){
       return true;
     }
     else{
       if(playerRight > thisRight + 1){
         return false;
       }
     }
    return false;  
  }
}

class Player{
 float posY = 0;
 int size = 20;
 boolean dead = false;
 
 int runCount = -5;
 int lifespan;
 int score;
 
 Player(){
 }

 
 void show(){
   image(myTrain, playerXpos - myTrain.width/2, height - groundHeight - (myTrain.height - 15));

   
   if(!dead){
     runCount++;
   }
   if(runCount > 5){
     runCount = -5;
   }
 }
 
 void move(){
     posY = 0; 
   for(int i = 0; i < obstacles.size(); i++){
     if(dead){
       if(obstacles.get(i).SPAD(playerXpos)){
         dead = true; 
       }
     }
     else{
       if(obstacles.get(i).SPAD(playerXpos)){
         dead = true;
       }
     }
     
   }
   
   for(int i = 0; i < stations.size(); i++){
     if(dead){
       if(stations.get(i).overshoot(playerXpos)){
         dead = true; 
       }
     }
     else{
       if(stations.get(i).overshoot(playerXpos)){
         dead = true;
       }
     }
     
   }
 }
 
 void update(){
  incrementCounter();
  move();
 }
 
 void incrementCounter(){
  lifespan++;
  if(lifespan % 3 == 0){
    score += 1;
  }
 }
}


class Station{
  float posX;
  int w, h;
  int type;
  
  Station(int t){
    posX = width;
    type = t;
    switch(type){
      case 0: w = 60;
              h = 40;
              break;
    }
  }
  
  void show(){
    switch(type){
      case 0: image(trainStation, posX - trainStation.width/2, height - groundHeight - trainStation.height);
              noStroke();
              fill(0, 255, 0, 50);
              rect(posX - trainStation.width/2, height - groundHeight, trainStation.width, 50);
              break;
    }
  }
  
  void move(float speed){
    posX -= speed;
  }
  boolean overshoot(float playerX){
    float playerRight = playerX + myTrain.width/2;
    float thisRight = posX + trainStation.width/2;
    
    if(playerRight > thisRight){
       return true;
     }
    return false;  
  }
  
  boolean stopped(float playerX){
    float playerRight = playerX + myTrain.width/2;
    float thisRight = posX + trainStation.width/2;
    
    if(posX - trainStation.width/2 < playerRight && playerRight < thisRight){
       return true;
     }
    return false;
    }
  }

class Tree{
  float w, h;
  float posX, posY;
  int type;
  
  Tree(int t){
    posX = width;
    type = t;
    switch(t){
      case 0: w = 20;
              h = 40;
              break;
      case 1: w = 20;
              h = 40;
              break;
      case 2: w = 20;
              h = 40;
              break;
    }
  }
  
  void show(){
    switch(type){
      case 0: image(tree, posX - tree.width/2, height - groundHeight - (posY + tree.height - 50));
              break;
      case 1: image(tree1, posX - tree1.width/2, height - groundHeight - (posY + tree1.height - 50));
              break;
      case 2: image(greenSignal, posX - greenSignal.width/2, height - groundHeight - greenSignal.height);
              break;
    }
  }
  
  void move(float speed){
    posX -= speed;
  }
}

 

Leave a Reply