# Trying to convert my platform game into a model view controller pattern

**URL:** <https://discourse.processing.org/t/trying-to-convert-my-platform-game-into-a-model-view-controller-pattern/40641>\
**Category:** Project Guidance\
**Created:** [January 19, 2023, 2:33am UTC](https://discourse.processing.org/t/trying-to-convert-my-platform-game-into-a-model-view-controller-pattern/40641 "2023-01-19T02:33:18Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![Berthe](https://avatars.discourse-cdn.com/v4/letter/b/a9a28c/32.png) [@Berthe](https://discourse.processing.org/u/Berthe)\
**Post date:** [January 19, 2023, 2:33am UTC](https://discourse.processing.org/t/trying-to-convert-my-platform-game-into-a-model-view-controller-pattern/40641/1 "2023-01-19T02:33:18Z")

</div>

so here is the main class

```auto
final static float MOVE_SPEED = 4;
final static float SPRITE_SCALE = 50.0/128;
final static float SPRITE_SIZE = 50;
final static float GRAVITY = 0.6;
final static float JUMP_SPEED = 14; 

final static float RIGHT_MARGIN = 400;
final static float LEFT_MARGIN = 60;
final static float VERTICAL_MARGIN = 40;

final static int NEUTRAL_FACING = 0;
final static int RIGHT_FACING = 1;
final static int LEFT_FACING= 2;

final static float WIDTH = SPRITE_SIZE * 16; //50*16 = 800
final static float HEIGHT = SPRITE_SIZE * 12; // height = yaxis which is bottom
final static float GROUND_LEVEL = HEIGHT-SPRITE_SIZE ;

//declare global variables
Player player;
PImage snow, crate, red_brick, brown_brick,gold,spider,p;
ArrayList<Sprite> platforms;
ArrayList<Sprite> coins;
Enemy enemy;
int numCoins;
boolean isGameOver;

float view_x = 0;
float view_y = 0;

//initialize them in setup().
void setup(){
  size(800, 600);
  imageMode(CENTER);
  //create player object
  PImage p = loadImage("player.png");
  player = new Player(p, 0.8);
  player.center_x = 100;
  player.change_y =GROUND_LEVEL;
  
  platforms = new ArrayList<Sprite>();
  coins = new ArrayList<Sprite>();
  numCoins = 0;
  isGameOver = false;
  
  gold = loadImage("gold1.png");
  spider = loadImage("spider_walk_right1.png");
  red_brick = loadImage("red_brick.png"); 
  brown_brick = loadImage("brown_brick.png");
  crate = loadImage("crate.png");
  snow = loadImage("snow.png");
  createPlatforms("map.csv");
}

// modify and update them in draw().
void draw(){
  background(255);
  scroll(); // scroll is called first if not game doesn't work
 //display objects
 displayAll();
 //update objects
 if(!isGameOver){
 updateAll();
 collectCoins();
 checkDeath();
 }
} 

void displayAll(){
   for(Sprite platform: platforms){
    platform.display();
  }
  
  player.display();
  enemy.display();
 
  fill(255,0,0);
  textSize(32);
  text("Coin:" + numCoins, view_x + 50, view_y + 50); // views to scroll with screen
  text("Lives:" + player.lives, view_x + 50, view_y + 100);
  
  if(isGameOver){
    fill(0,0,255);
    text("GAME OVER", view_x + width/2-100, view_y + height/2);
    if(player.lives == 0){
   // text("You Lose!" ,view_x + width/2-100, view_y + height/2 + 50);
    } else{
    text("You Lose!",view_x + width/2-100, view_y + height/2 + 50);
    text("Press SPACE to restart!",view_x + width/2-100, view_y + height/2 + 100);
    }
  }

}

void updateAll(){
  for(Sprite c: coins){
    c.display();
    ((AnimatedSprite)c).updateAnimation(); // casting c in animated sprite cause, 
  } //it doesnt have method update animation
  resolvePlatformCollisions(player,platforms);
  player.updateAnimation();
  enemy.updateAnimation();
  enemy.update();
  
  collectCoins();
  checkDeath();
}

void checkDeath(){
boolean collideEnemy = checkCollision(player,enemy);
boolean fallOffCliff = player.getBottom() > GROUND_LEVEL;
if(collideEnemy || fallOffCliff){
  player.lives--;
  if(player.lives == 0){
    isGameOver = true;
  }
  else{ //reset the player
  player.center_x = 100;
  player.setBottom(GROUND_LEVEL);
  }
 }
}

void collectCoins(){
  ArrayList<Sprite> coin_list = checkCollisionList(player,coins);
  if(coin_list.size() > 0){
  for(Sprite coin: coin_list){
  numCoins++;
  coins.remove(coin);
   }
 }
 //collect everything to win
 if(coins.size() == 0){
 isGameOver = true;
 }
}
void scroll(){
  float right_boundary = view_x + width - RIGHT_MARGIN;
  if(player.getRight() > right_boundary){
   view_x += player.getRight()-right_boundary; 
  }
  float left_boundary = view_x + LEFT_MARGIN;
  if(player.getLeft() < left_boundary){
   view_x -= left_boundary - player.getLeft(); 
  }
  float bottom_boundary = view_y + height - VERTICAL_MARGIN;
  if(player.getBottom() > bottom_boundary){
   view_y += player.getBottom()-bottom_boundary; 
  }
  float top_boundary = view_y + VERTICAL_MARGIN;
  if(player.getTop() < top_boundary){
   view_y -= top_boundary - player.getTop(); 
  }
  translate(-view_x, -view_y); // to move everything under my feet 
}

// returns true if sprite is one a platform.
public boolean isOnPlatforms(Sprite s, ArrayList<Sprite> walls){
  // move down say 5 pixels
  s.center_y += 5;
  // check to see if sprite collide with any walls by calling checkCollisionList
  // move back up 5 pixels to restore sprite to original position.
 ArrayList<Sprite> col_list = checkCollisionList(s,walls);
  s.center_y -= 5;
  // if sprite did collide with walls, it must have been on a platform: return true
  // otherwise return false.
    if(col_list.size() > 0){
      return true;
    }
    else{
    return false;
    }
}

// implement this method.
public void resolvePlatformCollisions(Sprite s, ArrayList<Sprite> walls){
  // add gravity to change_y of sprite
  s.change_y += GRAVITY;
  
  // move in y-direction by adding change_y to center_y to update y position.
 s.center_y += s.change_y;
  
  // Now resolve any collision in the y-direction:
  // compute collision_list between sprite and walls(platforms).
   ArrayList<Sprite> col_list = checkCollisionList(s, walls);
     if(col_list.size() > 0){
    Sprite collided = col_list.get(0);
    if(s.change_y > 0){
      s.setBottom(collided.getTop());
    }
    else if(s.change_y < 0){
      s.setTop(collided.getBottom());
    }
    s.change_y = 0;
  }
  // move in x-direction by adding change_x to center_x to update x position.
      s.center_x += s.change_x;
   // Now resolve any collision in the x-direction:
  // compute collision_list between sprite and walls(platforms).   
  col_list = checkCollisionList(s, walls);
    if(col_list.size() > 0){
    Sprite collided = col_list.get(0);
    if(s.change_x > 0){
        s.setRight(collided.getLeft());
    }
    else if(s.change_x < 0){
        s.setLeft(collided.getRight());
    }
  }    
}

boolean checkCollision(Sprite s1, Sprite s2){
  boolean noXOverlap = s1.getRight() <= s2.getLeft() || s1.getLeft() >= s2.getRight();
  boolean noYOverlap = s1.getBottom() <= s2.getTop() || s1.getTop() >= s2.getBottom();
  if(noXOverlap || noYOverlap){
    return false;
  }
  else{
    return true;
  }
}

public ArrayList<Sprite> checkCollisionList(Sprite s, ArrayList<Sprite> list){
  ArrayList<Sprite> collision_list = new ArrayList<Sprite>();
  for(Sprite p: list){
    if(checkCollision(s, p))
      collision_list.add(p);
  }
  return collision_list;
}

void createPlatforms(String filename){
  String[] lines = loadStrings(filename);
  for(int row = 0; row < lines.length; row++){
    String[] values = split(lines[row], ",");
    for(int col = 0; col < values.length; col++){
      if(values[col].equals("1")){
        Sprite s = new Sprite(red_brick, SPRITE_SCALE);
        s.center_x = SPRITE_SIZE/2 + col * SPRITE_SIZE;
        s.center_y = SPRITE_SIZE/2 + row * SPRITE_SIZE;
        platforms.add(s);
      }
      else if(values[col].equals("2")){
        Sprite s = new Sprite(snow, SPRITE_SCALE);
        s.center_x = SPRITE_SIZE/2 + col * SPRITE_SIZE;
        s.center_y = SPRITE_SIZE/2 + row * SPRITE_SIZE;
        platforms.add(s);
      }
      else if(values[col].equals("3")){
        Sprite s = new Sprite(brown_brick, SPRITE_SCALE);
        s.center_x = SPRITE_SIZE/2 + col * SPRITE_SIZE;
        s.center_y = SPRITE_SIZE/2 + row * SPRITE_SIZE;
        platforms.add(s);
      }
      else if(values[col].equals("4")){
        Sprite s = new Sprite(crate, SPRITE_SCALE);
        s.center_x = SPRITE_SIZE/2 + col * SPRITE_SIZE;
        s.center_y = SPRITE_SIZE/2 + row * SPRITE_SIZE;
        platforms.add(s);
      }
      else if(values[col].equals("5")){
        Coin c = new Coin(gold, SPRITE_SCALE);
        c.center_x = SPRITE_SIZE/2 + col * SPRITE_SIZE;
        c.center_y = SPRITE_SIZE/2 + row * SPRITE_SIZE;
        coins.add(c);
      }
      else if(values[col].equals("6")){
        float bLeft = col* SPRITE_SIZE;
        float bRight = bLeft + 4 *SPRITE_SIZE;
        enemy = new Enemy(spider, 50/72.0, bLeft, bRight); // spider has scaling of 72px so scaled down to 50
        enemy.center_x = SPRITE_SIZE/2 + col * SPRITE_SIZE;
        enemy.center_y = SPRITE_SIZE/2 + row * SPRITE_SIZE;
      }
    }
  }
}
 

// called whenever a key is pressed.
void keyPressed(){
  if(keyCode == RIGHT){
    player.change_x = MOVE_SPEED;
  }
  else if(keyCode == LEFT){
    player.change_x = -MOVE_SPEED;
  }
  else if(key == 'a' && isOnPlatforms(player, platforms)){
    player.change_y = -JUMP_SPEED;
  }
  else if(isGameOver && key == ' '){
  setup();
  }
}

// called whenever a key is released.
void keyReleased(){
  if(keyCode == RIGHT){
    player.change_x = 0;
  }
  else if(keyCode == LEFT){
    player.change_x = 0;
  }
}
´´´

secondly here is the Sprite class

```

public class Sprite{  
PImage image;  
float center\_x, center\_y;  
float change\_x, change\_y;  
float w, h;  
public Sprite(String filename, float scale, float x, float y){  
image = loadImage(filename);  
w = image.width \* scale;  
h = image.height \* scale;  
center\_x = x;  
center\_y = y;  
change\_x = 0;  
change\_y = 0;  
}  
public Sprite(String filename, float scale){  
this(filename, scale, 0, 0);  
}  
public Sprite(PImage img, float scale){ // called in sprite animated  
image = img;  
w = image.width \* scale;  
h = image.height \* scale;  
center\_x = 0;  
center\_y = 0;  
change\_x = 0;  
change\_y = 0;  
}  
public void display(){  
image(image, center\_x, center\_y, w, h);  
}  
public void update(){  
center\_x += change\_x;  
center\_y += change\_y;  
}

void setLeft(float left){  
center\_x = left + w/2;  
}  
float getLeft(){  
return center\_x - w/2;  
}  
void setRight(float right){  
center\_x = right - w/2;  
}  
float getRight(){  
return center\_x + w/2;  
}  
void setTop(float top){  
center\_y = top + h/2;  
}  
float getTop(){  
return center\_y - h/2;  
}  
void setBottom(float bottom){  
center\_y = bottom - h/2;  
}  
float getBottom(){  
return center\_y + h/2;  
}  
}

```auto
here is the Animated class

```

public class AnimatedSprite extends Sprite{  
PImage currentImages;  
PImage standNeutral;  
PImage moveLeft;  
PImage moveRight;  
int direction;  
int index;  
int frame;  
// implement the constructor, remember to call super() appropriately.  
// initialize direction, index and frame. The PImage arrays can be initialized  
// as null.  
public AnimatedSprite(PImage img, float scale){  
super(img,scale);  
direction = NEUTRAL\_FACING;  
index = 0;  
frame = 0;  
}  
// frame is increased by 1  
// every 5 frames do:  
public void updateAnimation(){  
frame++;  
if(frame % 5 == 0){  
selectDirection();  
selectCurrentImages();  
advanceToNextImage();  
}  
}  
// if sprite is moving right, set direction to RIGHT\_FACING  
// else if it is moving left, set direction to LEFT\_FACING  
// otherwise set it to NEUTRAL\_FACING  
public void selectDirection(){  
if(change\_x \> 0){  
direction = RIGHT\_FACING;  
}  
else if(change\_x \< 0){  
direction = LEFT\_FACING;  
}  
else{  
direction = NEUTRAL\_FACING;  
}  
}

// if direction is RIGHT\_FACING, LEFT\_FACING or NEUTRAL\_FACING  
// set currentImages to the appropriate PImage array.  
public void selectCurrentImages(){  
if(direction == RIGHT\_FACING){  
currentImages = moveRight;  
}  
else if(direction == LEFT\_FACING){  
currentImages = moveLeft;  
}  
else {  
currentImages = standNeutral;  
}  
}  
// increase index by 1  
// if index is at end of array loop back to 0  
// assign image variable(from Sprite class) to currentImages at index.  
public void advanceToNextImage(){  
index++;  
if(index \>= currentImages.length){  
index = 0;  
}  
image = currentImages [index];  
}  
}

```auto

i have got the player, enemy. coin classes too but that will be much to upload here, could someone help me out please?
```

---

<div class="post-metadata">

**Author:** ![mnse](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/mnse/32/16520_2.png) [@mnse](https://discourse.processing.org/u/mnse)\
**Post date:** [January 20, 2023, 7:34pm UTC](https://discourse.processing.org/t/trying-to-convert-my-platform-game-into-a-model-view-controller-pattern/40641/2 "2023-01-20T19:34:02Z")

</div>

Hi @Berthe,

Why [MVC](https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller?wprov=sfla1) and not ie [ECS](https://en.wikipedia.org/wiki/Entity_component_system?wprov=sfla1) pattern ?  
Guess there is no easy way and you need to dig deeper into studying the different patterns and try to apply it on your own…

Cheers  
— mnse

---

<div class="post-metadata">

**Author:** ![Berthe](https://avatars.discourse-cdn.com/v4/letter/b/a9a28c/32.png) [@Berthe](https://discourse.processing.org/u/Berthe)\
**Post date:** [January 20, 2023, 7:46pm UTC](https://discourse.processing.org/t/trying-to-convert-my-platform-game-into-a-model-view-controller-pattern/40641/3 "2023-01-20T19:46:16Z")

</div>

Hey @mnse

I choosed that pattern because I was trying to do that as a project on IntelliJ and using processing as a library, but the fact that my game mostly rely on images for the animation it made it quite problematic to do the separation
