2014-01-25 6 views
-1

Мне нужно вызвать обработчик события, чтобы указать пользователю выбрать TCard или TLabel , а затем вернуть это значение в качестве параметра.Настройка eventHandler с возвращаемым значением

У меня есть две единицы GAME, SS_SPELL

Это как код в SS_SPEll работает.

// TSPELL 
// ====== 
// The chronology is: 
// 1. At appropriate points in the game (such as before turn, after cast etc aka trigger points) 
//  the game calls the SpellMeister's RunSpells method. 
// 2. RunSpells checks the database for spells matching the card that 
//  initiated the spell action, and the trigger point at which it did so. 
//  For each one that it finds it will create an appropriate object, which 
//  could be a TSpell descendent or a TSpellAdjuster descendent. 
//  For each TSpell it finds it fires off an onFindSpell event. 
//  See below for details of how TSpellAdjusters are handled. 
// 3. The handler for the onFindSpell events can (should) call the spells' 
//  AimAt method for each potential target. A potential target is a card 
//  or a player. 
// 4. A spell's AimAt method checks if the potential target is a legitimate 
//  target for that spell and if so it calls its ApplySpellTo method to 
//  actually do the dirty deed. 

Так что мне нужно, как только RunSpells получает информация о БД будет проверять, если needs2ndtarget: = 1, если да, то я знаю, что нужна вторая цель для этого заклинания.

Здесь TSpellBase это класс TSpell. В попытке создать это событие я добавил FOnSeek2ndTarget в приватном разделе и FNeed2Target в охраняемой и общественной собственности OnSeek2ndTarget. Вы также увидите TTargetEvt, в настоящее время его настройку для восстановления TCARD, но мне нужно, чтобы он получал TCard или TLAbel, не представляя, как это сделать.

TTargetEvt = procedure (Card : TCard) of Object; 


TSpellBase = class 
    private 
    FOnManaChange: TManaEvt; 
    FOnSeek2ndTarget: TTargetEvt; 

    protected 
    FCardType   : TCardType; 
    FOriginator   : TCard; 
    FNeed2Target   : integer; 

    function LegitimateTarget (Candidate : TObject) : boolean; virtual; 
    public 
    constructor Create; virtual; 

    property CardType : TCardType  read FCardType  write FCardType; // ctLava, ctNature, ctWizard, etc etc 
    property Originator : TCard   read FOriginator write FOriginator; 

    property Need2Target : integer  read FNeed2Target write FNeed2Target; 
    property OnManaChange : TManaEvt read FOnManaChange write FOnManaChange; 
    property OnSeek2ndTarget : TTargetEvt read FonSeek2ndTarget write FOnSeek2ndTarget; 
    end; 

Сейчас в TSpell, я не думаю, что мне нужно что-нибудь chnaged здесь, но его необходимо для процедуры spellmiester.runspell

TSpell = class(TSpellBase) 
    private 
    protected 
    FCategory : TCategory; 
    FLifeToAdd : Byte; 
    FMaxRandom : Byte; 
    FReplaceDmg : Byte; 
    FReplacement : string; 
    FStatTarget : Byte; 
    FTrigger  : TTrigger; 
    procedure ApplySpellTo(Target : TObject); virtual; abstract; // Apply the spell to the target 
    public 
    procedure AimAt(Candidate: TObject); virtual; 

    property Category : TCategory  read FCategory  write FCategory; 
    property LifeToAdd : Byte   read FLifeToAdd write FLifeToAdd; 
    property MaxRandom : Byte   read FMaxRandom write FMaxRandom; 
    property ReplaceDmg : Byte   read FReplaceDmg write FReplaceDmg; 
    property Replacement : string  read FReplacement write FReplacement; 
    property StatTarget : Byte   read FStatTarget write FStatTarget; 
    property Trigger  : TTrigger  read FTrigger  write FTrigger; 
    end; 

Здесь я добавил FOnSeek2ndTarget в приватной секции. и свойство Итак, теперь, когда заклинание забрасывается, оно будет , и теперь вызывается runsspells.

TSpellMeister = class 
    private 
    FonFindSpell : TRcvSpell; 
    FOnManaChange : TManaEvt; 
    FOnSeek2ndTarget : TTargetEvt; 
// FonNewAdjuster : TRcvSpell; 
    protected 
    FAdjusters : TAdjusters; 
    FQuery : TADOQuery; 

    public 
    constructor Create(DBCon: TADOConnection); 
    destructor Destroy; override; 

    function IfNull(const Value, Default : OleVariant) : OleVariant; 
    procedure Adjust(Attacker : TCard; Victim : TObject; var TheDamage : integer); overload; 
    procedure Adjust(Attacker : TCard;     var TheCost : integer); overload; 
    procedure RunSpells(Card : TCard; Trigger : TTrigger); 

    property onFindSpell : TRcvSpell read FonFindSpell write FonFindSpell; 
    property OnManaChange : TManaEvt read FOnManaChange write FOnManaChange; 
    property OnSeek2ndTarget: TTargetEvt read FOnSeek2ndTarget write FOnSeek2ndTarget; 
// property onNewAdjuster : TRcvSpell read FonNewAdjuster write FonNewAdjuster; 
    end; 

Это где проблема, я добавил foundspell.Need2ndTarget это получает данные из базы данных, если это 1, то для этого нужно пользователю выбрать другую цель для заклинания. В настоящее время я добавил

если FoundSpell.Need2Target = 1 then FOnSeek2ndTarget (Карта);

, но я уверен, что это не правильно ...

//************************************************************************** 
procedure TSpellMeister.RunSpells(Card: TCard; Trigger: TTrigger); 
//************************************************************************** 
var 
    OneSpell : TSpellBase; 
    FoundSpell : TSpell; // Just so only have to cast once 
begin 
    assert(assigned(FonFindSpell),'TSpellMeister.RunSpells : No onFindSpell event handler!'); 
    // Search the database 
    FQuery.Active := FALSE; 
    FQuery.Parameters.ParamByName(SQL_PARAM_SPELL_ORIGINATOR).Value := Card.CName; 
    FQuery.Parameters.ParamByName(SQL_PARAM_SPELL_TRIGGER ).Value := Trigger; 
    FQuery.Active := TRUE; 

    // Iterate through the spell records. For each one, create a category-specific 
    // TSpell descendant and fire off an onFindSpell event. 

    if FQuery.RecordCount > 0 then 
    begin 
    FQuery.Recordset.MoveFirst; 
    while not FQuery.Recordset.EOF do 
    begin 
     case TCategory(FQuery.Recordset.Fields[DB_FLD_CATEGORY].Value) of 
     caAboveLife    : OneSpell := TSpellAboveLife.Create; 
     caDamage     : OneSpell := TSpellDamage.Create; 
     caDamagePlus    : OneSpell := TSpellDamagePlus.Create; 
     caDamagePlusPercent  : OneSpell := TSpellDamagePlusPercent.Create; 
     caDamagePercentIncrease : OneSpell := TSpellDamagePercentIncrease.Create; 
     caDamagePercentDecrease : OneSpell := TSpellDamagePercentDecrease.Create; 
     caDamageSpells   : OneSpell := TSpellDamageSpells.Create; 
     caDestroy     : OneSpell := TSpellDestroy.Create; 
     ..... 
     else      raise ERangeError.CreateFmt(ERROR_INVALID_DB_NUMBER,[DB_FLD_CATEGORY,FQuery.Recordset.Fields[DB_FLD_CATEGORY].Value]); 
     end; 
     try 
     if assigned(OneSpell) then 
     begin 
      OneSpell.CardType  := TCardType (IfNull(FQuery.Recordset.Fields[ DB_FLD_CARD_TYPE ].Value,0)); 
      OneSpell.Originator := Card; 
      OneSpell.OnManaChange := Self.OnManaChange; 
      OneSpell.OnSeek2ndTarget := self.OnSeek2ndTarget; 
      assert(OneSpell.Originator.COwner is TPlayer,'TSpellMeister.RunSpells : OneSpell.Originator.COwner not a player: ' + OneSpell.Originator.COwner.ClassName); 
      try 
       FoundSpell := TSpell(OneSpell); 
       FoundSpell.Originator := Card; 
       FoundSpell.Trigger  := Trigger; 
       FoundSpell.CardType := TCardType (FQuery.Recordset.Fields[ DB_FLD_CARD_TYPE ].Value); 
       FoundSpell.Category := TCategory (FQuery.Recordset.Fields[ DB_FLD_CATEGORY ].Value); 
       FoundSpell.LifeToAdd :=    IfNull(FQuery.Recordset.Fields[ DB_FLD_LIFE_TO_ADD ].Value,0); 
       FoundSpell.MaxRandom :=    IfNull(FQuery.Recordset.Fields[ DB_FLD_MAX_RANDOM ].Value,0); 
       FoundSpell.PerCent  :=    IfNull(FQuery.Recordset.Fields[ DB_FLD_PER_CENT ].Value,0); 
       FoundSpell.Plus  :=    IfNull(FQuery.Recordset.Fields[ DB_FLD_PLUS  ].Value,0); 
       FoundSpell.ReplaceDmg :=    IfNull(FQuery.Recordset.Fields[ DB_FLD_REPLACE_DMG ].Value,0); 
       FoundSpell.Replacement :=    IfNull(FQuery.Recordset.Fields[ DB_FLD_REPLACEMENT ].Value,0); 
       FoundSpell.StatTarget :=    IfNull(FQuery.Recordset.Fields[ DB_FLD_STAT_TARGET ].Value,0); 
       FoundSpell.Target  := TTargetType(IfNull(FQuery.Recordset.Fields[ DB_FLD_TARGET  ].Value,0)); 
       FoundSpell.Need2Target :=    IfNull(FQuery.Recordset.Fields[ DB_FLD_NEED2TARGET ].Value,0); 
       assert(FoundSpell.Originator.COwner is TPlayer,'TSpellMeister.RunSpells : FoundSpell.Originator.COwner not a player: ' + OneSpell.Originator.COwner.ClassName); 
       if FoundSpell.Need2Target = 1 then 
       FOnSeek2ndTarget(Card); 
       FonFindSpell(FoundSpell); 
      finally 
       FreeAndNil(OneSpell); 
      end; 
      end; 

     except     // I think this is OK but is there a possible bug if 
     FreeAndNil(OneSpell); // spell adjuster added to list then destroyed? 
     end;      // List item would then be invalid. 

     FQuery.Recordset.MoveNext; 
    end; 
    end; 
end; 

Таким образом, все, что есть блок ss_spells, ныне game блок, который использует ss_spells блок в forum.create я есть

FSpellMeister.OnSeek2ndTarget := self.Handle2ndTarget; 

без понятия, что положить в Handle2ndTarget в настоящее время его просто

//**************************************************************************** 
procedure TFGame.Handle2ndTarget(Card : TCard); 
begin 
    showmessage('Select a target HANDLE2ndTARGET'); 
end; 

просто чтобы увидеть, если я мог бы по крайней мере, получить здесь ..

Так с этим мой вопрос, если вы не можете сделать это, Как я установить вар в ss_Spells к TObject (tcard или TLabel), когда foundspell.Need2ndTarget := 1 с помощью событие FOnSeek2ndTarget();

+0

Я действительно нет идея вообще не то, что вы просите. Здесь слишком много кода. Прежде всего вам нужно будет решить, что ваш вопрос, и спросить об этом. Не стоит публиковать весь ваш код и надеяться, что мы сможем решить, каков ваш вопрос. Вы хотите, чтобы событие возвращало значение? Сделать возвращаемое значение параметром 'var'. Это оно? –

+0

Да, я попытался показать код, который перегружен вопросом. Я удалил много. жаль, что это так долго .. Но да, мне нужно знать, как использовать событие, чтобы вернуть параметр var –

+0

'FNeed2Target: Integer'. Не используйте '0' и' 1' для указания логического состояния. Объявите переменную как 'Boolean'. –

ответ

4

Просто измените подпись вашего TTargetEvt типа, например:

TTargetEvt = procedure (Card : TCard; var Target: TObject) of Object; 

Затем обновить RunSpells() соответственно:

var 
    Target: TObject; 
... 
if FoundSpell.Need2Target = 1 then 
begin 
    Target := nil; 
    if Assigned(FOnSeek2ndTarget) then FOnSeek2ndTarget(Card, Target); 
    // use Target as needed... 
end; 
... 

Затем обновите ваш обработчик соответственно:

procedure TFGame.Handle2ndTarget(Card : TCard; var Target: TObject); 
begin 
    Target := ...; 
end; 
+0

FOnSeek2ndTarget (карта, цель); это чтение в цель? таким образом, в handle2ndTarget, если я задал Target: = slot1. то в runpells значение Target теперь является слотом1? –

+0

Это правильно. Спецификатор 'var' в параметре события передает адрес памяти локальной переменной RunSpell' Target' в обработчик, что позволяет обработчику напрямую обращаться к переменной и изменять ее значение. –

+0

Отлично, что решает большинство моих проблем, теперь в runpell он получает информацию db, которая говорит мне, требует ли заклинание 2-й цели.поэтому после того, как все это будет проверено, и оно обратится к Handle2ndTarget, мне нужен Target: = пользователь нажимает на .. как бы вы это сделали, чтобы иметь возможность вернуть значение цели –

2

Мне нужно знать, как использовать событие для возврата параметра var.

Определите событие, как это:

type 
    TMyEvent = procedure(var ReturnValue: Integer) of object; 

А затем добавить свойство события обычным образом:

.... 
private 
    FOnMyEvent: TMyEvent; 
.... 
published 
    property OnMyEvent: TMyEvent read FOnMyEvent write FOnMyEvent; 
.... 

Нюанс приходит как поверхность событие. Как правило, если вы пишете компонент, который предлагает события, вы должны учитывать вероятность того, что к событию не будет обработчика. И если событие предназначено для возврата значения, как у вас нет обработчика, а также возвращаемого значения? Хитрость заключается в том, чтобы назначить параметр по умолчанию, прежде чем вы начертите событие. Например:

procedure TMyComponent.DoMyEvent(out ReturnValue: Integer); 
begin 
    Result := DefaultValueForMyEventHandler;// you supply something meaningful here 
    if Assigned(FOnMyEvent) then 
    FOnMyEvent(Result); 
end; 

Таким образом, если потребитель компонента не поставляется обработчик для события, то метод все еще дает разумное значение.

Если вы прочтете это и подумайте, что для FOnMyEvent это не имеет значения nil, тогда ваш дизайн неправильный. Если вы хотите заставить потребителя обеспечивать поведение, а не позволять полагаться на значение по умолчанию, то событие является неправильным механизмом. В этом случае попросите потребителя предоставить поведение через параметр, возможно, подкрепленный сигнатурой конструктора компонента. Или, может быть, каким-то другим способом.

Я только что дал вам базовый пример, не связанный с вашим кодом. Я попытался понять концепции. Надеюсь, вы сможете адаптировать это к вашим конкретным потребностям.

+0

, но что, если мне нужен ReturnValue, это объект. можете ли вы выполнить TMyEvent = procedure (var ReturnValue: TObject) объекта, ' –

+0

Конечно. Вы можете использовать любые типы, которые вам нравятся. –

Смежные вопросы