Help with dodge mechanic

Hey All,
I’ve been lurking in the forums for a little while - just getting into arduboy/c++ and I’m trying to branch out of tutorial purgatory and make something from scratch.

My eventual goal is to set up a really rudimentary “Punch-out” style game, but I’m trying to wrap my head around individual mechanics. In this case I’m trying to nail down an efficient way to reproduce the dodge mechanics of punch-out. Here’s what I have so far:

#include <Arduboy2.h>
Arduboy2 arduboy;

#define IDLE  55

int locationX = 55;
int locationY = 50;
int dodgeCoords [] = {4, 3, 2, 2, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, -1, -1, -1, -2, -2, -3, -4};
int dodgeIndex = 0;

void plDodge() {
    locationX += dodgeCoords[dodgeIndex];
    dodgeIndex++;
    if (dodgeIndex <= 21) 
    {
      return locationX;
    } 
    else
    { 
      dodgeIndex = 0;
      locationX = IDLE;
    }
}

void setup() {
  // put your setup code here, to run once:
  arduboy.begin();
  arduboy.setFrameRate(30);
  arduboy.clear();
}

void loop() {
  if (!arduboy.nextFrame()) {return;}
  arduboy.clear();
  arduboy.pollButtons();
  if (arduboy.pressed(RIGHT_BUTTON)) 
  {
    plDodge();  
  }
  arduboy.setCursor(locationX, locationY);
  arduboy.print(locationX);
  arduboy.print('\n');
  arduboy.print(dodgeIndex);
  arduboy.display();
}`

The result is a little moving text file that does a smooth little ‘dodge’ to the right over and over while the right button is held down, and pauses in place when the right button is released. My aim was to have the position of the text (eventually a player sprite) go through the complete dodge motion after pressing the right button once, and shouldn’t continuously loop if the button is being held down.
I’ve tried changing the arduboy.pressed to arduboy.justPressed, but as is, the position is updated once for each time I press the button.
I hope this makes sense (and that I’m in the right category). Thanks for helping a total n00b out.

1 Like

Could you test the code:

  if (arduboy.pressed(RIGHT_BUTTON)) 
  {
    plDodge();  
  }

to

  if (arduboy.pressed(RIGHT_BUTTON) && locationX == IDLE) 
  {
    plDodge();  
  }

So that the dodge only happens when you are in the idle position?

Alternatively, you could use a flag to indicate if you are in the motion or not. Or you could set dodgeIndex to some known value (like -1 or 255) to show that you are not in the motion.

I’m not quite sure what your objective is.

What exactly are “the dodge mechanics of punch-out”?


By the way, plDodge is attempting to return a value despite being marked void.
Is that supposed to be return; or is the function supposed to return a value?

Also your test should be dodgeIndex < 21 because dodgeBuffer only has 21 items, not 22.

And you don’t need arduboy.clear() in setup() because it gets called at the start of loop().

Apologies for not being clearer. When I say the “dodge mechanics,” I just mean pushing the left or right buttons in Punch Out causes the character to briefly move to the left or right, and then returns back to his idle position. see the first portion of the gif below:
Punch-Out

I’ve adjusted the code to no longer include return - I left it in there from a previous attempt to use a for loop to iterate through and update the ‘player’ position. I’m not sure whether the plDodge function needs to return anything, as long as the position of the ‘player’ (currently the text displaying the x value of the cursor) gets updated.

Thanks for the feedback. I’ve removed the extraneous clear(), and updated the plDodge function to the following:

void plDodge() {
  if (dodgeIndex < 21) {
      dodgeIndex++;
      locationX += dodgeCoords[dodgeIndex];
  } 
  if (dodgeIndex >= 21){
    locationX = IDLE;
    dodgeIndex = 0;
  }
}

At the moment, I still can’t get the position to cycle through each value in dodgeCoords fluidly with one button press… Thanks for your help so far!

Did you try my code addition? I think it will fix your problem.

Also …

void plDodge() {
  if (dodgeIndex < 21) {
      dodgeIndex++;
      locationX += dodgeBuffer[dodgeIndex];
  } 
  if (dodgeIndex >= 21){
    locationX = IDLE;
    dodgeIndex = 0;
  }
}

… could be …

void plDodge() {
  if (dodgeIndex < 21) {
      dodgeIndex++;
      locationX += dodgeBuffer[dodgeIndex];
  }
  else {
    locationX = IDLE;
    dodgeIndex = 0;
  }
}

… as the dodgeIndex < 21 or not.

Hey thank you for the tip above. I was just getting ready to reply to your comment. I think I would need to change how the function works to get the change you made to work, but it may be the way to go.

With plDodge in its current state, if I make the changes you suggested, pushing the right button results in locationX being updated to 58, and then since it’s no longer in IDLE position, pushing or holding right doesn’t do anything. I’m pretty sure my goal can be achieved with a while or a for loop, but I haven’t had any success with that thus far. Not sure what I’m missing. Here’s an example of something I’ve attempted. This results in the dodgeIndex being updated, but the ‘player’ more or less disappears, without going through the steps (it would seem):
void plDodge() {
for (int x = 0; x < 21; x++){
dodgeIndex++;
locationX += dodgeCoords[dodgeIndex];
}
}

Your new approach would loop through all the indexes in a single pass and would not allow the various images to be rendered. Your first approach does a single update per loop() iteration and would allow for the image to be repainted each pass.

1 Like

Okay that makes a lot more sense. Is it possible to redraw the position of an object or text within a for loop in this manner?

Okay. I have something that (roughly) works. See below:

#include <Arduboy2.h>
Arduboy2 arduboy;
#define IDLE  55

int locationX = IDLE;
int locationY = YDEF;
int dodgeBuffer [] = {4, 3, 2, 2, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, -1, -1, -1, -2, -2, -3, -4};
int dodgeIndex = 0;
bool dodging = 0;

void plDodge() {
  if (dodging == 1 && dodgeIndex <= 21){
    dodgeIndex++;
    locationX += dodgeBuffer[dodgeIndex];
  } else {
    dodging = 0;
    locationX = IDLE;
    dodgeIndex = 0;
  }
}

void setup() {
  // put your setup code here, to run once:
  arduboy.begin();
  arduboy.setFrameRate(30);
}

void loop() {
  if (!arduboy.nextFrame()) {return;}
  arduboy.clear();
  arduboy.pollButtons();
    if (arduboy.justPressed(RIGHT_BUTTON))
    {
      dodging = 1;
    }
  if (dodging){
    plDodge();
  }
  arduboy.setCursor(locationX, locationY);
  arduboy.print(locationX);
  arduboy.print('\n');
  arduboy.print(dodgeIndex);
  arduboy.display();
}

I doubt the final version (Lord willing!) will look like the above, but it’s a start. This was super helpful - thanks for the input!

dodging is a boolean so you an simply do if (dodging && dodgingIndex <= 21) {

I think you have moved on but you could not have both players updating simultaneously if you do dhte updates in a loop like that.

Technically yes,
but when arduboy.display() is called in loop() you’d end up with all the images being rendered at once

That will probably do it.


A few suggestions:

Use true and false for bool, not 1 or 0.
1 and 0 are integers, not booleans.
The only reason they work in the first place is because of some implicit type conversions that are happening.

Particularly if (dodging == 1 && is going to be more expensive than just doing if (dodging &&.

Unless you’ve added a new value to dodgeBuffer,
then you’ve added the bug back in.

You’ll save RAM if you use int8_t instead,
which you can do since your numbers are all between -128 and 127.

(You could also move them into progmem, or even halve the size of the array by using a few number tricks, but neither of those things are particularly urgent and I don’t want to dump too many suggestions on you at once.)


I missed some of the earlier conversation because I didn’t get any notifications because nobody replied to me directly, quoted me or @-mentioned me.

@Pharap Apologies - still getting accustomed to the platform (I thought that when I clicked ‘reply’ to your comment earlier, I took that to mean you would be getting replied to directly. Go figure).

I’ve made updates to what I have so far per your recommendations. Thank you again for the feedback! I’ll post updates once I get it into a more finished state.

1 Like

You might have clicked the reply at the bottom of the thread by mistake.
If you didn’t then that implies that there’s a bug in the system somewhere.

In case you don’t notice:

  • The ‘reply to thread’ button is white on a blue background.
  • All the ‘reply to this comment’ buttons are just black on a white background,
    on the same row as the like button and the ‘link to this comment’ button.

They more or less use the same font and symbol, and the ‘tooltips’ for the buttons are overly verbose,
so it can be hard to notice the difference if you don’t already know that there is a difference.

That’s mainly Discourse’s fault. :P

If you have any more questions or want any advice, don’t hesitate to ask.

1 Like