Sunday, April 14, 2013

Creating a XP System

Author: "mktwo"
Перевод: Vadakuma
Оригинал статьи, ее обсуждение

Прежде всего убедитесь, что Вы уже знаете как устанавливать эти коды, т.к. в этом титориале это не объясняется.Во вторых, я полагаю что Вы уже немного знакомы с UnrealScript. Например Вы должны знать как наследуемые классы работают и как делается свой тип игры, как сделать свой собственный HUD, PlayerController и т.д. Если Вы не знаете всего этого то можно некоторые вещи посмотреть на этом сайте(в дальнейшем тут будет намного больше информации о UnrealScript),также на других русских сайтах и естественно на заморских.например тут и тут.



HUD создан по этому тутору

Необходимый набор скриптов, для реализации задачи:
  • MyGame.uc
  • MyPlayerController.uc
  • SeqAct_GiveXP.uc (optional)
  • MyHUD.uс


MyGame.uc
Скрипт описывает созданный тип игры
class MyGame extends UTGame;

// Функция, которая выполняется после каждого убийства
function ScoreKill(Controller Killer, Controller Other)
{
     local MyPlayerController PC;
     
     super.ScoreKill(Killer, Other);
     
     PC = MyPlayerController(Killer); // Cast to the custom MyPlayerController class
     PC.GiveXP(100); //Позволяет изменять кол-во получаемого опыта
}

DefaultProperties
{
//    DefaultPawnClass = class'UTGame.UTPawn'
     PlayerControllerClass = class'MyGame.MyPlayerController'
     HUDType = class'MyGame.MyHUD'
}


MyPlayerController.uc
Получаем экспу, повышаем левел. Методы не находятся в MyPawn,  для того чтобы опыт сохранялся после смерти.(хотя конечно можно и изловчиться)
class MyPlayerController extends UTPlayerController
 config(MyGame);

const MAX_LEVEL = 50;
const XP_INCREMENT = 500; // Кол-во опыта до следующего уровня
var int XP; // Общая сумма собранных XP
var int Level; // Current level
var int XPGatheredForNextLevel; // Количество XP собранных 
var int XPRequiredForNextLevel; // Количество необходимых XP до нового уровня

//При старте игры мы подсчитываем сколько нужно получить опыта чтобы перейти на новый уровень

simulated function PostBeginPlay()
{
    super.PostBeginPlay();
    // Обсчитываем свойства при старте игры
    CalculateLevelProgress();
}

//Здесь мы объявляем функцию,которая позволяет поменять кол-во опыта нужного для следующего  уровня через Kismet 
// Функция вызываемая из Kismet
public function AddXP(SeqAct_GiveXP action)
{
    GiveXP(action.Amount); // Количество опыта получаемого с учетом  установки в Kismete
}

//Функция добавления опыта
public function GiveXP(int amount)
{
     self.XP += amount;
     
     CalculateLevelProgress();
     
     while (self.XPGatheredForNextLevel >= self.XPRequiredForNextLevel && self.Level < MAX_LEVEL)
     {
         self.Level++;
         // Пересчитываем опыт после левел апа
         CalculateLevelProgress();
     }
}

//Дальше мы объявляем функцию которая считает, сколько нужно еще опыта для достижения следующего уровня.
private function CalculateLevelProgress()
{
    local int xpToCurrentLevel; // Текущее количество накопленного опыта
    
    xpToCurrentLevel = XP_INCREMENT * (self.Level - 1);
    self.XPGatheredForNextLevel = self.XP - xpToCurrentLevel;
    self.XPRequiredForNextLevel = self.Level * XP_INCREMENT;
}

DefaultProperties
{
     Level = 1;
     XP = 0;
}


SeqAct_GiveXP.uc (optional)
В этом скрипте мы создаем Sequence Action, который будем использовать в Kismet.
class SeqAct_GiveXP extends SequenceAction;
 
var() int Amount; // Amount of XP this action will give


//Добавляем немного инфы чтобы было удобнее использовать в kismete
DefaultProperties
{
     // Имя  функции в Kismet Editor
     ObjName="Add XP"
     // Имя  функции при использовании
     HandlerName="AddXP"
     Amount = 0
     // Показывает входы и выходы модуля в Kismetе
     VariableLinks(1)=(ExpectedType=class'SeqVar_Int', LinkDesc="Amount", bWriteable=true,   PropertyName=Amount)
}


MyHUD.uc
Скрипт рисует на экране шкалы со здоровьем, текущем уровнем и количеством опыта.
class MyHUD extends UTHUD;

function DrawBar(String  Title, float Value, float MaxValue,int X, int Y, int R, int G, int B) // Функция рисования шкал
{
     local int PosX; //объявляем переменную представляющую позицию откуда начинать рисовать
     local int BarSizeX; //Объявляем переменную регулирующую
     
     PosX = X; //Начальная точка, откуда начинаем рисовать прямоугольник
     BarSizeX = 300 * FMin(Value / MaxValue, 1); // размер активного прямоугольника (Увеличивайте 300 чтобы увеличить прямоугольник)
 
     //Рисуем закрашенный прямоугольник
     Canvas.SetPos(PosX,Y);
     Canvas.SetDrawColor(R, G, B, 200);
     Canvas.DrawRect(BarSizeX, 12);
 
     //Рисуем пустой прямоугольник
     Canvas.SetPos(BarSizeX+X,Y);
     Canvas.SetDrawColor(255, 255, 255, 80);
     Canvas.DrawRect(300 - BarSizeX, 12); //Увеличивайте 300 чтобы увеличить прямоугольник
 
     //Рисуем наше заглавие
     Canvas.SetPos(PosX+300+5, Y); //Change 300 to however big your bar is
     Canvas.SetDrawColor(R, G, B, 200);
     Canvas.Font = class'Engine'.static.GetSmallFont();
     Canvas.DrawText(Title);
} 


function DrawGameHud()
{
     local MyPlayerController PC; 
     PC = MyPlayerController(PlayerOwner);
     
     if ( !PlayerOwner.IsDead() && !UTPlayerOwner.IsInState('Spectating')) //If player is not dead or spectating... ( you could also //use DrawLivingHud() )
     {        
         DrawBar("Health:"@PlayerOwner.Pawn.Health@"%",PlayerOwner.Pawn.Health, PlayerOwner.Pawn.HealthMax,20,20,200,80,80); //...draw our health-bar
         DrawBar("Level:"@PC.Level, PC.Level, PC.MAX_LEVEL ,20,40,200,200,200); //...and our level-bar
         if ( PC.Level != PC.MAX_LEVEL ) //If our player hasn't reached the highest level...
         {
             DrawBar("XP:"@PC.XPGatheredForNextLevel$"/"$PC.XPRequiredForNextLevel, PC.XPGatheredForNextLevel, PC.XPRequiredForNextLevel, 20, 60, 80, 255, 80); //...draw our XP-bar
         }
     }
}


Используем Kismet для изменения системы получения опыта

Сначала Вы должны сделать триггер, жмем Add Actor > Add Trigger.

Дальше выбираем триггер и идем в kismet. Добавляем триггер New Event Using Trigger_0 > Touch. Добавляем Add XP-action.

Соединяем Touched с In.

Далeе New Variable > Player > Player и цепляем к target.

New Variable > Int > Int и пишем количество начисляемого опыта за одно убийство и цепляем к Amount

Сохраняем и наслаждаемся результатом!

3 comments:

  1. А подойдёт ли эта система для ММО игр?

    ReplyDelete
    Replies
    1. Представленная система являет собой лишь упрощенный пример как можно реализовать накопление и использование опыта/очков.
      Здесь нет возможности сохранять накопленные очки и изменения(все очки сбрасываются при перезагрузки уровня/игры или уничтожения класса MyPlayerController), также нет поддержки сетевого режима.
      Т.е. конкретно от представленных скриптов в сетевой игре толку мало, но их реально адаптировать под работу по сети.

      Delete
  2. Hi i have been using this sample of code for awhile you are great man! i need help making a sequence condition for a slot machine volume trigger that activates random win 1-100 if the player has 1 dollar (score) to put into the machine. but, i cannot figure this out can you help me and would it be based off this code also?

    ReplyDelete