Ryu: The Big Adventure!

Създаване на противниците

Придвижване към Ryu

Противника се движи когато Ryu навлезе в обхватът му, докато самият противник е жив и докато той не се намира до Ryu. Когато тези две условия са изпълнени, противникът започва да се придвижва към shiftX и shiftY координатите със скорост delta * .1f. По време на придвижването аналогично се променя и анимацията на противника, към анимация на придвижване.

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;
  }
}

Когато стигне до играча той спира, защото тогава едно от условията за движение не е изпълнено – това да не се намира до него.

Удряне

За да можем да ударим главният герой, първо трябва да сме изпълнили серия от условия. Противника трябва да се намира в непосредствена близост до Ryu, Ryu трябва да не изпълнява удари или умения и самият противник трябва да е жив.
Първо булевият метод thugAtRyu()следи дали противника се намира на точното място, за да изпълни удар и връща true.

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

Със следващият булев метод, наречен ryuAttack(), ние следим дали героят не извършва някакъв удар или специално умение.

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

Както споменахме, за всяко едно действие на Ryu има съответна булева стойност. В този случай, чрез тях можем да следим действията на главният герой и да ги използваме в нашия метод.
Противникът трябва да удря през определено време, когато вече се намира срещу Ryu, за да се придобие реалност към действията му. За целта се използва метода enemyAttackChance().
enemyAttackChance() е шансът врагът да удари, когато се намира в непосредствена близост до Ryu.

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

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

Метода създава случайно число в интервала от 1 до 1000, с всеки един цикъл на играта. Когато числото е по-голямо от 900, метода изпраща сигнал за изпълняване на удар.
Когато всички тези условия са изпълнени преминаваме към изпълнението на удара.

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;
}

Първо, анимацията на врагът се променя към такава на удряне. След това създаваме таймер, който да връща противника към статичното си положение, след като вече е изпълнил удара. Проверяваме дали звуците са позволени в тази сесия на играта и изпълняваме звук на удряне. Също така проверяваме дали конкретният звук не се изпълнява в момента, чрез punchedSnd.playing(), който връща true когато това е вярно. Целта е да не се получава застъпване на звука, което може да доведе до какафония. Променяме анимацията на Ryu със съответната, изобразяваща състояние на болка и отнемаме от неговите жизнени точки. Накрая същият таймер връща и Ryu към статичното му положение.
За създаването на таймера използваме метода delay().

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

Този метод използва променливата time, която представлява системното времето под формата на цифра. StartTime е времето когато е започнал таймера, а number е интервала от време до неговото приключване. Когато интервалът изтече метода връща стойност true и таймера приключва.
По сходен начин се изпълняват и ударите на Ryu.
За да нанесем удар първо проверяваме за противник в близост до Ryu и дали противника е жив. След това изсвирваме звука за удряне, по абсолютно същия начин, привключваме анимацийте на двата героя, създаваме таймер и отнемаме от жизнените точки на врага. След приключване на таймера, героите се връщат към началното си състояние и можем да започнем от начало.

Анимация за край

Анимацията за благополучен край е създадена по сходен модел с тази за начало. Тук обаче освен само нея използваме и три спрайта на Ryu, чрез които го изобразяваме в доволно състояние – състояние на успех.

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);
  }
}

Метода се нарича youWinAnimation. Той се обхожда с всеки един цикъл на играта, но се активира, когато булевата winState върне стойност на вярно. winState връща вярна стойност, когато всички противници са убити. Проверката става като се прочетат стойностите на жизнените точки на всички противници и те са равни на 0. Самата проверка се намира в update(), следователно тя се проверява с всеки цикъл на играта.


При вярност youWinImage изображението се изрисува на екрана, като youWinScale1 и youWinScale2 са неговите вертикални и хоризонтални размери. Тези стойности постепенно се увеличават, за да се създаде необходимата анимация. Когато стойността на youWinScale1 премине 100, се възпроизвежда и звук, за успешно завършване на играта. Когато стойността на youWinScale1 премине 600, изображението вече е в пълния си размер и скалирането приключва и малко след това играча бива прехвърлен към началното меню, чрез sbg.enterState(0);.
Споменахме и че Ryu също извършва анимация. Първо движението на героя се забранява с enableInput = false;. След това преминаваме към първият спрайт ryuReadyAnimation, който е изграден от 6 кадъра. Спираме анимацията на последния 6-ти кадър с ryuSprite.stopAt(6);, правим проверка дали тя е спряла с ryuSprite.isStopped() и ако това е вярно преминаваме към втория спрайт - ryuWin1Animation. Отново спираме спрайта на последният кадър, в случая кадър 3, проверяваме за спиране на анимацията и привключваме към последната анимация ryuWin2Animation.
Всички тези анимации и спрайтове придават усещане са успешно приключила игра.

Заключение

В проекта бяха описани основните компоненти, за изграждането на нашата игра. Бяха споменати, без да бъдат детайлно изследвани – LWJGL и Slick2D библиотеките, които макар и изградени от трети страни, са необходими компоненти на средата. Разгледана беше в основи логиката на анимирането чрез спрайтове и бяха изложени някои идеи за реализация, използвани при създаването на логиката на играта Ryu: The Big Adventure.
Оттук нататък възможностите за развитие и подобрение на средата са много.
От функционална гледна точка може да бъде подобрен изкуственият интелект на опонентите. Всеки един от опонентите е създаден отделно, което означава че и характерите им могат да се направят различни. В игрите се използват различни класове герои като танк, лечител, стрелец и войн, всеки един специализиран в определени умения и с различни предимства и недостатъци.
Танкът e герой който има за цел да поема ударите и да предпазва останалите от щети. Той върши малко щети, но за сметка на това е много здрав и труден за убиване.
Лечителят използва магически сили за да лекува събратята си и да увеличава тяхната сила. Той е лесен за убиване и не извършва никакви щети и затова мястото му е в най-задните части на боя, от където използва магията си за лекуване.
Стрелецът и войнът са класовете които извършват най-много щети. Докато танкът задържа вниманието на враговете, лечителят поддържа всички живи, стрелецът и войнът трябва да вършат щети, които да доведат до победа за екипа.
Всеки един клас опонент ще изисква свой собствен изкуствен интелект, коренно различен от на останалите. Комбинацията от тези класове могат да създадат много проблеми за главният герой, принуждавайки го да използва различни стратегии за всеки един от тях.
Може да бъде добавена и база данни, която да съхранява резултати. Резултатите ще се бъзират на това, за колко време е преминато нивото, на каква трудност е преминато нивото, колко здраве е останало на героя в края на нивото и др.
Могат да се търсят други платформи за представяне, например да се създадат портове на играта за уеб браузър и за мобилни устройства, като iOS, Windows Mobile, Android и Blackberry.


Source: Github Download: Link

1 2
3

← Обратно