Ryu: The Big Adventure!

Creating enemies

Moving towards Ryu

Each enemy is moving when Ryu gets inside his range, while he is alive and while he isn't next to Ryu. When these two conditions have been met, the enemy starts to move to the coordinates of shiftX and shiftY with the speed of delta * .1f. While moving his animation changes to a walking animation.

if (ryuPositionX < -170 && thugHP > 0)
{
  if (thugPosY < 117)
  {
    moveY += delta * .1f;
    thugSprite = thugWalkAnimation;
  }
  if (thugPosY > 120)
  {
    moveY -= delta * .1f;
  }
  if (thugPosX > 170)
  {
    moveX -= delta * .1f;
    thugSprite = thugWalkAnimation;
  }
}

When he reaches the main character he stops, because one of the condition isn't met – that of not being next to him.

Hitting

To be able to hit Ryu, first we need to meet a series of conditions. The enemy must be right in front of Ryu, Ryu mustn't do any hits or skills at the moment and he must be alive.
First the boolean method thugAtRyu() looks if the enemy is at the right place to perform a hit and returns true.

public boolean thugAtRyu(float thugPosX, float thugPosY)
{
  if (thugPosX < 190 && thugPosX > 115 && 
  thugPosY < 130 && thugPosY > 70)
  {
    return true;
  }
  else
  {
    return false;
  }
}

With the next boolean method called ryuAttack(), we look if the main character isn't doing any hits or special skills.

public boolean ryuAttack()
{
  if (ryuHadouken || ryuLowKick || ryuPunch || 
    ryuShoryuken || ryuShoryuken || ryuTatsaku)
  {
    return true;
  }
  else
  {
    return false;
  }
}

As I mentioned before, for each action of Ryu there is a boolean. In this case, using them, we can check for these actions and use them in this method.
The enemy must hit in an interval of time when he is at Ryu. For this purpose we use the method enemyAttackChance().
enemyAttackChance() is the chance the enemy hits.

public boolean enemyAttackChance()
{
  Random rand = new Random();

  if (rand.nextInt(1000) > 900)
  {
    return true;
  }
  else
  {
    return false;
  }
}

This method creates a random number in the range from 1 to 1000 with each cycle of the game. When this number is greater than 900, the method sends a signal to perform a hit.
When all these conditions have been met we can finally execute a punch.

if (thugAtRyu(thugPosX, thugPosY) && !ryuAttack()
    && enemyAttackChance() && showThug && thugHitRyu)
{
  thugSprite = thugHitAnimation;
  getInitialTime = time;

  if (!punchedSnd.playing() && Menu.soundOn)
  {
    punchedSnd.play(1, Menu.soundVolume);
  }

  ryuHurt = true;
  ryuHP--;
  thugHitRyu = false;
}

First, the animation of the enemy changes to a hitting one. After that we create a timer, which returns him to static position after an interval of time. We check to see if sounds have been enabled and we execute a hitting sound. Also we check that this certain sound isn't been used at the moment using punchedSnd.playing(), which returns true if it's used. The reason of doing this is to prevent overlap of the sound. We change the animation to Ryu with the one which represents him in pain and we decrease his hit points. Finally, the timer returns Ryu to his static position.
To create the timer we use the method delay().

public boolean delay(long startTime, int number)
{
  if (startTime + number <= time)
  {
    return true;
  }
  else
  {
    return false;
  }
}

This method uses the variable time, which represents system time. StartTime is the time at which the timer has started, and number is the interval of time until his end. When the interval is over the method returns true and the timer stops.
Ryu's punches are done in the same way.
To do a hit we first have to check if there is an enemy close to Ryu and if he is alive. After that we play a punching sound in the exact same way, we change the animations of the two characters, create a timer and we decrease the enemy's hit points. After the timer has completed, they return to they're starting position and we can start all over again.

Animation for ending

This animation is used when the user completes the level and it's made in the same way as the starting animation. In here we also use three sprites of Ryu, with which we show him as a winner.

public void youWinAnimation(StateBasedGame sbg)
{
  if (winState)
  {
    youWinScale1 += 3;
    youWinScale2 += 2;
    enableInput = false;
    ryuSprite = ryuReadyAnimation;
    ryuSprite.stopAt(6);

    if (ryuSprite.isStopped())
    {
      ryuSprite = ryuWin1Animation;
      ryuSprite.stopAt(3);
      ryuSprite = ryuWin2Animation;
    }
  }

  if (youWinScale1 >= 100 && youWinScale1 <= 105 && Menu.soundOn)
  {
    youWinSnd.play(1, Menu.soundVolume);
  }

  if (youWinScale1 >= 600 && youWinScale1 <= 610 
  {
    youWinScale1 -= 3;
  }

  if (youWinScale2 >= 1200)
  {
    sbg.enterState(0);
  }
}

The method is called youWinAnimation. It's executed with every cicle of the game, but it's activated when the boolean winState returns true. winState returns true when all enemies have been killed. It checks the hit points of each entity and executes when they all are at 0. The check itself is inside update(), which means that it's executed with every cicle of the game.


When true youWinImage is drawn on the screen, with youWinScale1 and youWinScale2 as it's vertical and horizontal size. These variables increase so that the animation can be done. When youWinScale1 reaches 100 a sound is played. When youWinScale1 reaches 600, the image is at it's full size, the scaling stops and a short time after that the user gets moved to the main menu, using sbg.enterState(0);.
Ryu also has an animation for the ending. First, user movement is disabled using enableInput = false;. After that we move to the first sprite ryuReadyAnimation, which is made out of 6 sprites. We stop the animation at the 6th frame using ryuSprite.stopAt(6);, we do a check to see if it's stopped with ryuSprite.isStopped() and if that's true we move to the next sprite - ryuWin1Animation. Again we stop the sprite at the last frame, in this case frame 3, we check for the stopping of the animation and we go to the last animation ryuWin2Animation.

Conclusion

In this project I've shown some of the most important components for building this game. I've mentioned LWJGL and Slick2D, which are needed for this purpose. I've shown the logic of the animation using spritesheets and I've shown some methods of realization, which I've used to create the logic of the game Ryu: The Big Adventure.
From here there are many possibilities for further developing the game:
The artificial intelligence can be drastically improved. Each of the enemies is create independently, which means that they can have a different A.I. and can do their own things which can differ them from the others. There are different types of character classes in each game, like a tank, healer, archer and warrior, each of them specialized in a certain set of skills, with different advantages and disadvantages.
The tank is a class which has the purpose to take hits and to protect the rest from damage. He does small amounts of damage, but has a lot of HP and is very hard to kill.
The healer uses magical skills to heal his allies and to buff them, increasing they're power. He's easy to kill and doesn't do any kind of damage and so he has to be protected and in the back of every formation, where he uses his healings.
The archer and the warrior are the classes which do the most damage. The tank takes the enemies attention, the healer keeps everyone alive and the archer and warrior do the damage.
Each class will need its own type of A.I. ,which has to be a lot different from the others. This combination of classes can cause a lot of problems for the player, forcing him to use different type of strategies for each one of them.
A database can be added, which can keep high scores. The score can be based on how long it took to complete the level, on what difficulty, how much HP remaining does the player haves at the end and others.
The game can be ported to other platforms like iOS, Windows Mobile, Android and Blackberry or it can be played online using an internet browser.


Source: Github Download: Link

1 2
3

← Обратно