4

I have a batch of sprites (textured OpenGL ES 2.0 Quads) which I loop through to move. Here is a simplified version of my code:

//'sprite' & other values have been are assumed to exist for the purpose of the question

public void moveQuadBatch(){

    //Loop for as many sprites as there are to draw
    for (loop = 0; loop < sprite.number; loop++){

        moveQuadNumber(loop); //this method will move the sprite that corresponds to the number loops so we can move through the entire batch and move each individual sprite


    }
}

Now, for some batches, there is a countdown timer, or some other condition (and there isn't for others, like above). Therefore, I've created a similar method for these objects like so:

public void moveQuadBatchWithCheck(){

    //Loop for as many sprites as there are to draw
    for (loop = 0; loop < sprite.number; loop++){

        //Only do this if the particular sprite's countdown/delay counter has reached 0 (counting down from another method not seen here)
        if (sprite.delay[loop]<0){

            moveQuadNumber(loop); //this method will move the sprite that corresponds to the number loops so we can move through the entire batch and move each individual sprite

        }
    }
}

However, I'm not entirely happy about this as there is a lot of code duplication. Instead of having these 2 methods is there any way I can use the first one and somehow 'slipstream' the additional check into the for loop? Or otherwise cut down on the duplication that I have here? This is a simple example, there are others and currently I have multiple methods which are all very similar.

Edit

As mentioned, the above is somewhat simplified. I could have some for loops which check another value (other than delay for example), and some could check 2 conditions.

3
  • Add some arguments to the method. Depending on the value of the arguments you can take different actions. Commented Feb 15, 2014 at 2:10
  • Could you explain by way of an example @B.J.Smegma? Thanks Commented Feb 15, 2014 at 2:12
  • See the answer from Claudiu. Commented Feb 15, 2014 at 2:15

4 Answers 4

3
public void moveQuadBatch(bool checkDelay) {
    for (loop = 0; loop < sprite.number; loop++){
        if (!checkDelay || sprite.delay[loop] < 0) {
             moveQuadNumber(loop);
        }
    }
}

Now moveQuadBatch(false) is your first function and moveQuadBatch(true) is your second one.


As to "inserting extra code", you're basically talking about functions. In Python an elegant approach would be to pass a function in and offload all logic to the function, e.g:

    def moveQuadBatch(predicate=None):
        for loop, sprite in enumerate(self.sprites): 
            if not predicate or predicate(loop, sprite):
                self.moveQuadNumber(loop)

Then you would use it as such:

inst.moveQuadBatch()  
inst.moveQuadBatch(lambda loop, sprite: sprite.delay[loop] < 0)
inst.moveQuadBatch(lambda loop, sprite: sprite.doesItBlend(loop))

You can do this same thing in Java but not quite as neatly: you have to define a predicate class and instances of it. This is the approach B.J. Smegma was advocating.

public interface QuadBatchPredicate {
    public boolean shouldMove(int loop, Sprite sprite);
}

Your function would look like this:

public void moveQuadBatch(QuadBatchPredicate pred) {
    for (loop = 0; loop < sprite.number; loop++){
        if (pred == null || pred(loop, sprite)) {
             moveQuadNumber(loop);
        }
    }
}
public void moveQuadBatch() {
    moveQuadBatch(null);
}

Then you can use anonymous classes to define the predicates:

moveQuadBatch();
moveQuadBatch(new QuadBatchPredicate() {
    public boolean shouldMove(int loop, Sprite sprite) {
        return sprite.delay[loop] < 0;
    }
});
moveQuadBatch(new QuadBatchPredicate() {
    public boolean shouldMove(int loop, Sprite sprite) {
        return sprite.doesItBlend();
    }
});

A bit cruftier than the Python solution, but it gets the point across. Now you can "insert code" into the function by defining the predicate, in-line, to be whatever you want it to be. Plus you can save often-used ones so you don't repeat them all over the place:

QuadBatchPredicate checkBlends = new QuadBatchPredicate() {
    public boolean shouldMove(int loop, Sprite sprite) {
        return sprite.doesItBlend();
    }
};
Sign up to request clarification or add additional context in comments.

5 Comments

Thanks @Claudiu, less comments? I've always read complaints from people who don't comment their code? Regarding the 'loop' variable, the first comment explains that all variables / objects are assumed to exist - this to keep irrelevant code out of the question. This is OK, however, as mentioned, this is only for 2 different possibilities, in my actual code, I have many others, some with additional checks on things other than 'delay' etc.... is there any way to use the main for loop but change the code within it for whatever I need to check - thanks! :-)
@Zippy: can you give some more examples of the checks you do? that will help put together an answer. ah and thanks i missed the first comment, i assumed it was not relevant..
@Zippy: Oh about less comments, I mean you shouldn't have comments that just say what the code does, e.g. int i; //i will be our loop iterator, for (i=0; i < 100; i++) { //loop i starting from 0 and ending at 99, incrementing by 1 each time, etc. I get that sprite[delay] < 0 means "Only do this if the particular sprite's countdown/delay counter has reached 0", no need to spell it out =). and actually it's harder to read if you spell it out like that.
I understand, feel free to edit the comments out :-) I always like to comment as much as I can as I feel it makes the question more readable.
@Zippy: See if my edit is more to your liking. really allows you to use whatever predicate you want. functional programming FTW
2

Make an interface as so:

public interface MyInteface {
void do_something(int loop);
}

Make different implementations of that interface depending on your needs e.g.

public class MyInterfaceImpl {
    public void do_something(int loop) {
         if (!checkDelay || sprite.delay[loop] < 0) {
              moveQuadNumber(loop);
         }
    }

Then your method could look simple as this:

public void moveQuadBatch(MyInterface interface) {
    for (int loop = 0; loop < sprite.number; loop++){
        interface.do_something(loop)
    }
}

4 Comments

Very interestin @B.J.Smegma. So basically, I would create a method in the MyInterfaceImpl class for every possible outcome that I require and then just put that within my loop?
You would create implementation of the interface for every different thing that you do inside for loop. Then you would call your method with those different implementations depending on your needs.
Basically a pared-down implementation of map, while mine is a pared-down implementation of filter .. i do dislike Java
Are you saying I would need to define a different interface/class for every possible outcome? Or have, for example a 'doSomething(int loop), then a doSomethingElse(int loop)' method in the same interface. If the latter, how would I then call whichever method is required? I can't explicitly type interface.doSomethingElse(loop) as that would mean again, having multiple moveQuadBatch() methods which would defeat the purpose. Or maybe I'm not understanding this completely? Thanks!
1

You could add "effects" to your sprites.

public class Sprite {
    private boolean active = true;
    private ArrayList<Effect> effects = new ArrayList<>();

    public void update(int time) {
        for(Effect e: effects) {
            e.update(this, time);
        }
    }

    public void addEffect(Effect effect) {
        effects.add(effect);
    }

    public void setActive(boolean active) {
        this.active = active;
    }
}

public interface Effect {
    void update(Sprite sprite, int time);
}

public class Delay implements Effect {
    private int delay;

    public Delay(int delay) {
        this.delay = delay;
    }

    public void update(Sprite sprite, int time) {
        delay -= time;
        if(delay > 0) sprite.setActive(false);
        else sprite.setActive(true);
    }
}

Comments

0

I would create a seperate method for the delay check and change your method like this:

public void moveQuadBatchWithCheck(bool check){
    for (loop = 0; loop < sprite.number; loop++){
        if(check){
            if (sprite.delay[loop]<0){
                moveQuadNumber(loop); 
                }
       }
       else{
           moveQuadNumber(loop);
           }
    }

Then when you want to check call the method with true in the parameter.

Not sure if this is what you're looking for though, but I hope it helps.

2 Comments

Agreed, please see edit in main question. Thanks :-)
You are truly right. I was on my phone so it took me a while to answer the question. Now I was saw your answer and I felt stupid.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.