How to go from Functions to Objects?

I’ve read the PShape tutorial article, specifically about Retained Mode with a Custom PShape Class, and looked at the accompanying examples, but I can’t wrap my head around any of it. I’ve avoided Object-Oriented Programming for quite some time, and I think it’s time for me to finally put it to use. In my game, I currently use a function to draw my walls. It looks something like this:

void drawWall(float x, float y, float w, float h, PImage wallTexture) {
beginShape();
texture(wallTexture);
vertex(x,y,0,0);
vertex(x+w,y,1,0);
vertex(x+w,y+h,1,1);
vertex(x,y+h,0,1);
endShape();
}

The real function I’m using is for 3D walls in P3D, but this mockup has the essentials: parameters and execution. My problem is “converting” this into an object, specifically one that uses retained mode to save on performance, which is pretty low for some of the game’s players. My primary struggle is wrapping my head around having the correct number of objects with the parameters that I need when I need them. With the function, I can just tell the game to draw a set of walls in a certain pattern by using a few drawWall() functions. With objects, however, I don’t know how to change the parameters of the walls or how to avoid constantly creating new objects any time I want a wall.

I gave it a couple of hours of trial and error, and this is all I could come up with:

class wall {
  PShape s;
  float x;
  float y;
  float w;
  float h;
  wall(float tempX, float tempY, float tempW, float tempH) {
    // First create the shape
    s = createShape();
    s.beginShape();
    // You can set fill and stroke
    s.fill(255);
    s.stroke(0);
    // Here, we are hardcoding a series of vertices
    s.vertex(0,0,0,0);
    s.vertex(5,0,1,0);
    s.vertex(5,5,1,1);
    s.vertex(0,5,0,1);
    s.endShape(CLOSE);
    x=tempX;
    y=tempY;
    w=tempW;
    h=tempH;
  }
  void display() {
    // Locating and drawing the shape
    pushMatrix();
    translate(x,y);
    scale(w,h);
    shape(s);
    popMatrix();
  }
}

So really, I’m looking for help on making a leap from functions to objects, or at least tips on saving performance in P3D if objects aren’t the only way.

Hi,

Don’t get exactly what you’re trying to achieve but maybe that can put you in the right direction

class Wall {
  PVector pos;
  PVector size;
  String name;
  boolean orient;
  
  public Wall(String n,float x,float y,float w,float h) {
    name = n;
    pos=new PVector(x,y);
    size=new PVector(w,h);
    orient=w>h;    
  }
  
  void show() {
    pushMatrix();
    translate(pos.x,pos.y);
    fill(128);
    stroke(255);
    rect(0,0,size.x,size.y);
    fill(255);
    translate(size.x/2,size.y/2);
    if (!orient) {
      rotate(radians(90));
    }
    text(name,0,0);    
    popMatrix();
  }  
}

ArrayList<Wall> walls;
  

void setup() {
  size(500,500);
  walls = new ArrayList<Wall>();
  textAlign(CENTER,CENTER);
  walls.add(new Wall("Top",0,0,width,20));
  walls.add(new Wall("Bottom",0,height-20,width,20));
  walls.add(new Wall("Left",0,20,20,height-40));  
  walls.add(new Wall("Right",width-20,20,20,height-40));    
}

void draw() {
  background(0);
  for (Wall w:walls)
    w.show();
}

dummy

1 Like

Ah! I think I can describe the problem a bit better now. Here, you add all the walls with their designated parameters in setup. I was wanting to know how to do this in draw() without constantly adding new walls to the ArrayList. Is there a way to test if the ArrayList already contains a wall with certain values for the parameters or something? With a function, for example, you just put the function in draw() and it will draw the wall with the parameters you want, and you can decide to just not draw it with if statements.

if (playerIsNearby) {
drawWall(etc, etc, etc);
}

With objects, however, it seems as though you must keep track of all of your walls in some manner with an ArrayList. Would the solution look something like this?

if (playerIsNearby) {
  if (walls.contains(Wall("Top",0,0,width,20))==false) {
    walls.add(new Wall("Top",0,0,width,20));
  }
}
else if (walls.contains(Wall("Top",0,0,width,20))) {
  walls.remove(Wall("Top",0,0,width,20));
}

No! Indeed it is much easier to use objects than to put it in let’s say “spaghetti code” :slight_smile:

Here is a simple example. But you have some things you should consider. As I understand you want to code a game. So first step you need to think about what’s you idea. should it be an open world (ie procedural level design), or do you have static levels. On the latter you need to think about a meta description of your level (ie. textfile which describe the level and its objects ie. walls, obstacles and their positions in the level). So you can code a setup level function (ie. in a World object) which parses that description and generate your objects… If you think about the former (open world) my suggestion would be … start with the static first :slight_smile:

Example for nearby detection… Hope that helps!

//  ----  Player class -----
class Player {
  PVector pos;
  float size = 40;
  float speed = 2;
  public Player(PVector p) {
    pos = p;
  }
  
  public void update(int k) {
    if(k == 'd')      pos.x += speed;
    else if(k == 'a') pos.x -= speed;
    else if(k == 'w') pos.y -= speed;
    else if(k == 's') pos.y += speed;
  }
  
  public void show() {
    pushMatrix();
    translate(pos.x,pos.y);
    fill(255,0,0);
    noStroke();
    ellipse(0,0,size,size);
    popMatrix();
  }  
}

//  ----  Wall class -----
class Wall {
  PVector pos;
  PVector size;
  String name;
  boolean orient;
  boolean visible;
  
  public Wall(String n,float x,float y,float w,float h) {
    name = n;
    pos=new PVector(x,y);
    size=new PVector(w,h);
    orient=w>h;
    visible=false;
  }
  
  public void update(Player p) {
    if (orient) {
      visible = abs(p.pos.y-pos.y) < p.size*2;
    }
    else {
      visible = abs(p.pos.x-pos.x) < p.size*2;           
    }
  }
  
  public void show() {
    if (!visible)
      return;
    pushMatrix();
    translate(pos.x,pos.y);
    fill(128);
    stroke(255);
    rect(0,0,size.x,size.y);
    fill(255);
    translate(size.x/2,size.y/2);
    if (!orient) {
      rotate(radians(90));
    }
    text(name,0,0);    
    popMatrix();
  }  
}

Player player;
ArrayList<Wall> walls;
  
//  ----  main sketch -----
void setup() {
  size(500,500);
  textAlign(CENTER,CENTER);

  walls = new ArrayList<Wall>();
  walls.add(new Wall("Top",0,0,width,20));
  walls.add(new Wall("Bottom",0,height-20,width,20));
  walls.add(new Wall("Left",0,20,20,height-40));  
  walls.add(new Wall("Right",width-20,20,20,height-40));
  
  player = new Player(new PVector(width/2, height/2));
}

void draw() {
  background(0);
  if (keyPressed) {
    player.update(key);
  }
  player.show();
  
  for (Wall w:walls) {
    w.update(player);
    w.show(); 
  }    
}

Example

out

I appreciate the help! Some background info: The game has actually been worked on for over a year. It’s a procedurally generated world with a grid of rooms, and it uses some perlin noise with your location as the input to determine how the rooms are shaped. As you move, parts of the world load/unload. Right now each “part” or “chunk” of the world is a room, and the shape of that room is determined by a lot of those drawWall() functions I was talking about. The nice thing about those functions is that I can do something like this:

for (int x=floor(playerX/500.0)-5; x<floor(playerX/500.0)+5; x++) {
  for (int z=floor(playerZ/500.0)-5; z<floor(playerZ/500.0)+5; z++) {
    int roomID=round(map(noise(x/100.0,z/100.0),0,1,0,100000))%10;
    switch (roomID) {
     // Normally I have various cases with different room layouts
      default:
        // Use functions, these parameters don't mean anything, just an example
        drawWall(x*500,0,z*500,100,100,100);
        drawWall(x*500+200,0,z*500+200,100,100,100);
      break;
   }
  }
}

The drawWall() functions are only called if the room is near the player (hence the for loops using your playerX and playerZ) and if the noise function comes up with the proper roomID. The problem with using objects here is that I don’t know how to achieve the same effect without knowing the number of wall objects that I need. Would converting this to objects be too tedious or unnecessary?

Hello @CosmicCrowMC

I’m not sure what you mean here:

You will still use the drawWall() function you created when you move your code into your Wall class.

It may be clearer if you create a super simple version of your project to work out how parameters work within a class.

There are a variety of ways you can control when new objects are made. But you are getting ahead of yourself. First, I would do a simplified version of your current code to translate into an OOP format…

:nerd_face:

if you want to go to oop you need to imagine your game as it contains different entities. Mean you have different entities which implements each the todos for them self. I’d tried to show you how with the simplified code above. Maybe that meta description below helps you better to understand …

Player {
	init: setup the player (ie pos)
	update: update the players ie. pos
	draw: draw the player
}

Wall {
	init: setup the wall
	update: do stuff if needed
	draw:   draw it
}

Room {
	contains wall(s)
	init: init the walls of the room
	update: do stuff if needed (call update of wall(s) if needed);
	draw: draws the wall(s) of the Room
}

World {
	contains room(s)
	init: init rooms of the world
	update(player): update world wrt players pos. (ie select room which the player is nearby);(call update of rooms if needed)
	draw: draw the selected room
}

Game {
	contains player
	contains world
	update: Player.update; 
            World.update(player);
            check ie if player has special circumstances(ie isdead,level up,etc.. 
	draw: World.draw;Player.draw
}

and so on … hope that helps …

Cheers!

1 Like