Het Composite Design Pattern Gebruiken voor een RPG Attributes Systeem

() translation by (you can also view the original English article)
Intelligentie, wilskracht, Charisma, wijsheid: naast belangrijke eigenschappen als een spel ontwikkelaar hebt, dit zijn ook gemeenschappelijke kenmerken die worden gebruikt in RPG's. Berekening van de waarden van deze kenmerken--toepassing kan getimede bonussen en rekening houdend met het effect van uitgeruste items--lastig. In deze tutorial zal ik u tonen hoe te een enigszins gewijzigde samengestelde patroon gebruiken om dit te gaan, op de vlieg.
Opmerking: Hoewel deze tutorial is geschreven met behulp van Flash en AS3, u moet zitten kundig gebruik dezelfde technieken en concepten in bijna elke omgeving spelontwikkeling.
Introductie
Kenmerken systemen worden zeer vaak gebruikt in RPGs te kwantificeren tekens sterke punten, zwakke punten en capaciteiten. Als u niet bekend met hen bent, scheren de Wikipedia-pagina voor een fatsoenlijk overzicht.
Zodat ze meer dynamische en interessante, verbeteren ontwikkelaars vaak deze systemen door het toevoegen van de vaardigheden, objecten en andere dingen die invloed hebben op de kenmerken. Als u dit doen wilt, moet u een goed systeem dat kan berekenen de definitieve kenmerken (rekening houdend met elke andere effect) en omgaan met de toevoeging of verwijdering van verschillende types van bonussen.
In deze tutorial zullen we een oplossing voor dit probleem ontdekken met behulp van een licht gewijzigde versie van de samengestelde ontwerppatroon. Onze oplossing zal zitten kundig voor omgaan met bonussen, en werkt op elke set kenmerken die u definieert.
Wat Is de samengestelde patroon?
Deze sectie is een overzicht van de samengestelde ontwerppatroon. Als u al bekend met het bent, kunt overslaan en direct naar onze probleem Modeling.
De samengestelde patroon is een ontwerp (een bekende, herbruikbare, algemene ontwerpsjabloon) voor controledoeleinden iets groots in kleinere objecten, om het maken van een grotere groep door het hanteren van alleen de kleine voorwerpen. Het maakt het gemakkelijk te breken van grote stukken informatie in kleinere, meer makkelijk behandelbaar, brokken. Het is in wezen een sjabloon voor het gebruik van een groep van een bepaald object alsof het één object zelf.
We gonna een gebruikte voorbeeld gebruiken om dit te illustreren: denk aan een eenvoudige tekeningstoepassing. U wilt kunt u driehoeken, vierkanten en cirkels te tekenen, en hen anders te behandelen. Maar u wilt ook om te kunnen omgaan met groepen van tekeningen. Hoe kunnen we dat gemakkelijk doen?
De samengestelde patroon is de perfecte kandidaat voor deze job. Door een ''groep tekeningen'' als een tekening zelf te behandelen, zou je gemakkelijk elke tekening binnen deze groep kunnen toevoegen, en de groep als geheel zou nog steeds als een enkele tekening worden gezien.
Op het gebied van programmering, hadden we een basis klasse, tekening
, die heeft het standaardgedrag van een tekening (u kunt verplaatsen, wijzigen van lagen, draaien, enzovoort), en vier subklassen, driehoek
, vierkant
, cirkel
en groeperen
.
In dit geval hebben de eerste drie klassen een eenvoudige gedrag, waarvoor alleen de input van de gebruiker van de fundamentele kenmerken van elke shape. De groep
klasse, zal wel methoden voor het toevoegen en verwijderen van vormen, evenals u een bewerking uitvoert op alle van hen (bijvoorbeeld de kleur van alle vormen in een groep tegelijk veranderen). Alle vier subklassen zou nog steeds beschouwd als een tekening
, zodat u niet hoeft te maken over het toevoegen van specifieke code voor wanneer u wenst te bedienen op een groep.
Om rekening te houden dit een betere vertegenwoordiging, kunnen we bekijken elke tekening als een knooppunt in een boomstructuur. Elk knooppunt is een blad, met uitzondering van de knooppunten van de groep
, die kan hebben kinderen--die op zijn beurt tekeningen binnen die groep.
Een visuele weergave van het patroon
Steken met de tekening app voorbeeld, dit is een visuele representatie van de "tekeningstoepassing" die we over hebben nagedacht. Merk op dat er drie tekeningen in de afbeelding: een groep bestaande uit een cirkel en een vierkant, een driehoek en een vierkant:

En dit is de vertegenwoordiging van de boom van de huidige scène (de wortel is de tekeningstoepassing fase):

Wat als we wilden een andere tekening, dat een groep van een driehoek en een cirkel, binnen de groep is, die maar we momenteel hebben toevoegen? Wij zouden het enkel toevoegen aangezien wij elke willekeurige tekening zou toevoegen binnen een groep. Dit is wat de visuele representatie zou als volgt uitzien:

En dit is wat de boom zou worden:



Nu, stel dat we gaan om te bouwen van een oplossing voor het probleem van de kenmerken dat is er. Natuurlijk, we not gonna hebben een directe visuele representatie (we alleen kunnen zien het eindresultaat, oftewel het berekende kenmerk gezien de ruwe waarden en de bonussen), dus we denken in de samengestelde patroon met de vertegenwoordiging van de boom beginnen zal.
Modelleren van ons probleem
Om het mogelijk te model van onze kenmerken in een boom, moeten we elk kenmerk opsplitsen in de kleinste delen die we kunnen.
We weten dat we hebben bonussen, die ofwel een ruwe waarde aan het kenmerk toevoegen, of het te met een percentage verhogen. Er zijn bonussen die toevoegen aan het kenmerk, en anderen die zijn berekend na alle die eerste bonussen zijn toegepaste (bonussen van vaardigheden, bijvoorbeeld).
Dus kunnen we:
- Ruwe bonussen (toegevoegd aan de ruwe waarde van het kenmerk)
- Laatste bonussen (toegevoegd aan het kenmerk nadat alles is berekend)
Je misschien hebt gemerkt dat we zijn niet scheiden van bonussen die een waarde toevoegen aan het kenmerk van de bonussen die het kenmerk te met een percentage verhogen. Dat komt omdat wij elke bonus te kunnen veranderen op hetzelfde moment zijn modelleren. Hierdoor dat kunnen we een bonus die wordt 5 opgeteld bij de waarde en het kenmerk stijgt met 10%. Dit zullen allemaal worden behandeld in de code.
Deze twee soorten bonussen zijn alleen de bladeren van de boom. Ze zijn vrij veel als de driehoek
, vierkan
t en cirkel
klassen in ons voorbeeld van vóór.
Wij niet hebben nog gemaakt een entiteit die als een groep dienen zal. Deze entiteiten zullen de kenmerken zelf! De klasse van de groep
in ons voorbeeld zullen simpelweg het kenmerk zelf. We moeten dus een kenmerk
klasse die zich zoals elk attribuut gedragen zal.
Dit is hoe een kenmerk boom kon kijken:



Nu alles is beslist, zullen we beginnen onze code?
Maken de basisklassen
We zullen worden met behulp van ActionScript 3.0 als de taal voor de code in deze tutorial, maar maak je geen zorgen! De code zal worden volledig becommentarieerd daarna en alles dat uniek is voor de taal (en de Flash-platform) zullen worden verklaard en alternatieven zal worden voorzien--, zodat als u bekend met elke taal OOP bent, u zal zitten kundig voor volgen deze tutorial zonder problemen.
De eerste les die we moeten maken is de basisklasse voor elk kenmerk en bonussen. Het bestand zal worden genoemd BaseAttribute.as
, en maken het zeer eenvoudig is. Hier is de code, met reacties achteraf:
1 |
|
2 |
package
|
3 |
{
|
4 |
public class BaseAttribute |
5 |
{
|
6 |
private var _baseValue:int; |
7 |
private var _baseMultiplier:Number; |
8 |
|
9 |
public function BaseAttribute(value:int, multiplier:Number = 0) |
10 |
{
|
11 |
_baseValue = value; |
12 |
_baseMultiplier = multiplier; |
13 |
}
|
14 |
|
15 |
public function get baseValue():int |
16 |
{
|
17 |
return _baseValue; |
18 |
}
|
19 |
|
20 |
public function get baseMultiplier():Number |
21 |
{
|
22 |
return _baseMultiplier; |
23 |
}
|
24 |
}
|
25 |
}
|
Zoals u zien kunt, zijn dingen zeer eenvoudig in deze basisklasse. We gewoon maken de velden _value
en _multiplier
, toewijzen van hen in de constructor en maken twee methoden getter, een voor elk veld.
Nu moeten we de klassen RawBonus
en FinalBonus
maken. Dit zijn gewoon subklassen van BaseAttribute
, met niets toegevoegd. U kunt uitbreiden op het zo veel als u wilt, maar voor nu zullen we alleen deze twee lege subklassen van BaseAttribute
maken:
RawBonus.as
:
1 |
|
2 |
package
|
3 |
{
|
4 |
public class RawBonus extends BaseAttribute |
5 |
{
|
6 |
public function RawBonus(value:int = 0, multiplier:Number = 0) |
7 |
{
|
8 |
super(value, multiplier); |
9 |
}
|
10 |
}
|
11 |
}
|
FinalBonus.as
:
1 |
|
2 |
package
|
3 |
{
|
4 |
public class FinalBonus extends BaseAttribute |
5 |
{
|
6 |
public function FinalBonus(value:int = 0, multiplier:Number = 0) |
7 |
{
|
8 |
super(value, multiplier); |
9 |
}
|
10 |
}
|
11 |
}
|
Zoals u zien kunt, hebben deze klassen niets in hen maar een constructor.
Het kenmerk Class
Het kenmerk
klasse zal worden het equivalent van een groep in de samengestelde patroon. Het zal kan rauw of definitieve bonussen houden, en een methode voor het berekenen van de eindwaarde van het kenmerk. Aangezien het een subklasse van BaseAttribute
, zullen het gebied van de _baseValue van
de klasse de waarde van het kenmerk.
Bij het maken van de klasse, zal er een probleem bij het berekenen van de eindwaarde van het kenmerk: aangezien wij rauwe bonussen niet van de laatste bonussen scheiden bent, er is geen manier kunnen we het berekenen van de eindwaarde, omdat we niet weten wanneer toe te passen voor elke bonus.
Dit kan worden opgelost door een lichte wijziging aan het samengestelde basispatroon. In plaats van het toevoegen van ieder kind aan hetzelfde ''container'' binnen de groep, maken we twee "containers", een voor de ruwe bonussen en andere voor de laatste bonussen. Elke bonus zal nog steeds een kind van kenmerk
, maar zullen op verschillende plaatsen dat de berekening van de eindwaarde van het kenmerk.
Met dat uitgelegd, laten we naar de code!
1 |
|
2 |
package
|
3 |
{
|
4 |
public class Attribute extends BaseAttribute |
5 |
{
|
6 |
private var _rawBonuses:Array; |
7 |
private var _finalBonuses:Array; |
8 |
|
9 |
private var _finalValue:int; |
10 |
|
11 |
public function Attribute(startingValue:int) |
12 |
{
|
13 |
super(startingValue); |
14 |
|
15 |
_rawBbonuses = []; |
16 |
_finalBonuses = []; |
17 |
|
18 |
_finalValue = baseValue; |
19 |
}
|
20 |
|
21 |
public function addRawBonus(bonus:RawBonus):void |
22 |
{
|
23 |
_rawBonuses.push(bonus); |
24 |
}
|
25 |
|
26 |
public function addFinalBonus(bonus:FinalBonus):void |
27 |
{
|
28 |
_finalBonuses.push(bonus); |
29 |
}
|
30 |
|
31 |
public function removeRawBonus(bonus:RawBonus):void |
32 |
{
|
33 |
if (_rawBonuses.indexOf(bonus) >= 0) |
34 |
{
|
35 |
_rawBonuses.splice(_rawBonuses.indexOf(bonus), 1); |
36 |
}
|
37 |
}
|
38 |
|
39 |
public function removeFinalBonus(bonus:FinalBonus):void |
40 |
{
|
41 |
if (_finalBonuses.indexOf(bonus) >= 0) |
42 |
{
|
43 |
_finalBonuses.splice(_finalBonuses.indexOf(bonus), 1); |
44 |
}
|
45 |
}
|
46 |
|
47 |
public function calculateValue():int |
48 |
{
|
49 |
_finalValue = baseValue; |
50 |
|
51 |
// Adding value from raw
|
52 |
var rawBonusValue:int = 0; |
53 |
var rawBonusMultiplier:Number = 0; |
54 |
|
55 |
for each (var bonus:RawBonus in _rawBonuses) |
56 |
{
|
57 |
rawBonusValue += bonus.baseValue; |
58 |
rawBonusMultiplier += bonus.baseMultiplier; |
59 |
}
|
60 |
|
61 |
_finalValue += rawBonusValue; |
62 |
_finalValue *= (1 + rawBonusMultiplier); |
63 |
|
64 |
// Adding value from final
|
65 |
var finalBonusValue:int = 0; |
66 |
var finalBonusMultiplier:Number = 0; |
67 |
|
68 |
for each (var bonus:FinalBonus in _finalBonuses) |
69 |
{
|
70 |
finalBonusValue += bonus.baseValue; |
71 |
finalBonusMultiplier += bonus.baseMultiplier; |
72 |
}
|
73 |
|
74 |
_finalValue += finalBonusValue; |
75 |
_finalValue *= (1 + finalBonusMultiplier); |
76 |
|
77 |
return _finalValue; |
78 |
}
|
79 |
|
80 |
public function get finalValue():int |
81 |
{
|
82 |
return calculateValue(); |
83 |
}
|
84 |
}
|
85 |
}
|
De methoden addRawBonus()
, addFinalBonus()
, removeRawBonus()
en removeFinalBonus()
zijn zeer duidelijk. Alles wat ze doen is toevoegen of verwijderen van hun specifieke bonus type of naar de matrix waarin alle bonussen van dat type.
Het lastige deel is de calculateValue()
methode. Ten eerste, het vat alle waarden die de ruwe bonussen aan het kenmerk toevoegen en ook vat alle de multiplicatoren. Na dat, het wordt de som van alle waarden van de ruwe bonus toegevoegd aan het eerste kenmerk, en past vervolgens de multiplier. Later, doet dezelfde stap voor de definitieve bonussen, maar dit keer de waarden en multiplicatoren toepassen op de waarde van het attribuut final half-berekend.
En we zijn klaar met de structuur! Controleer de volgende stappen om te zien hoe zou u het gebruiken en uitbreiden.
Extra gedrag: Getimede bonussen
In onze huidige structuur hebben we alleen eenvoudige rauw en definitieve bonussen, die momenteel helemaal geen verschil. In deze stap, we zullen het toevoegen van extra gedrag aan de FinalBonus
klasse, zodat er meer uitziet als bonussen die zouden worden toegepast door middel van actieve vaardigheden in een spel.
Aangezien, zoals de naam al impliceert, deze vaardigheden alleen actief voor een bepaalde periode van tijd zijn, zullen we een timing gedrag toevoegen op de laatste bonussen. De ruwe bonussen kunnen worden gebruikt, bijvoorbeeld voor bonussen toegevoegd door middel van apparatuur.
Om dit te doen, zullen we gebruiken de klasse Timer
. Deze klasse is inheems vanuit ActionScript 3.0, en alles wat het doet is dat zich gedraagt als een timer, beginnend bij 0 seconden het aanroepen van een opgegeven functie na een opgegeven tijdsduur, resetten terug naar 0 en begint de telling opnieuw, totdat het opgegeven aantal is bereikt graven opnieuw. Als u hen niet opgeeft, zal de Timer
blijven actief totdat u het stopt. U kunt kiezen wanneer de timer begint en wanneer het stopt. Indien nodig, kunt u het gedrag eenvoudig met behulp van uw taal van de timing systemen met de juiste extra code, repliceren.
Laten we springen in de code!
1 |
|
2 |
package
|
3 |
{
|
4 |
import flash.events.TimerEvent; |
5 |
import flash.utils.Timer; |
6 |
|
7 |
public class FinalBonus extends BaseAttribute |
8 |
{
|
9 |
private var _timer:Timer; |
10 |
|
11 |
private var _parent:Attribute; |
12 |
|
13 |
public function FinalBonus(time:int, value:int = 0, multiplier:Number = 0) |
14 |
{
|
15 |
super(value, multiplier); |
16 |
|
17 |
_timer = new Timer(time); |
18 |
_timer.addEventListener(TimerEvent.TIMER, onTimerEnd); |
19 |
}
|
20 |
|
21 |
public function startTimer(parent:Attribute):void |
22 |
{
|
23 |
_parent = parent; |
24 |
|
25 |
_timer.start(); |
26 |
}
|
27 |
|
28 |
private function onTimerEnd(e:TimerEvent):void |
29 |
{
|
30 |
_timer.stop(); |
31 |
|
32 |
_parent.removeFinalBonus(this); |
33 |
}
|
34 |
}
|
35 |
}
|
In de constructor is het eerste grote verschil dat laatste bonussen nu vereisen een tijd
parameter, die zal laten zien hoe lang ze duren. Binnen de constructor, wij creëren een Timer
voor die hoeveelheid tijd (ervan uitgaande dat de tijd in milliseconden), en het toevoegen van een gebeurtenislistener aan het.
(Event luisteraars zijn in principe wat maakt de timer de juiste functie aanroepen wanneer het bereikt die bepaalde periode van tijd - in dit geval de functie genoemd onTimerEnd()
.) is
Merk op dat we de timer nog niet begonnen. Dit gebeurt in de startTimer()
-methode, die ook benodigt een parameter, ouder
, die een kenmerk
moet. Deze functie vereist het kenmerk die is het toevoegen van de bonus om te roept u die functie te activeren op zijn beurt, dit begint de timer en vertelt de bonus welke instantie te verzoeken dat de bonus te verwijderen wanneer de timer zijn limiet heeft bereikt.
Het deel van de verwijdering wordt gedaan in de onTimerEnd()
methode, die net de set ouder voor wegnemen op en stoppen van de timer zal vragen.
Nu, kunnen we gebruiken laatste bonussen als getimede bonussen, die aangeeft dat ze slechts voor een bepaalde hoeveelheid tijd duren zal.
Extra gedrag: Afhankelijke kenmerken
Één ding dat vaak gezien in RPG games zijn kenmerken die afhankelijk zijn van anderen. Laten we, bijvoorbeeld, het attribuut "attack snelheid". Het is niet alleen afhankelijk van het type wapen die u gebruiken, maar bijna altijd op de beweeglijkheid van het personage ook.
In ons huidige systeem toestaan we alleen dat bonussen aan kinderen van kenmerk
exemplaren. Maar we moeten in ons voorbeeld laat een kenmerk worden van een kind van een ander kenmerk. Hoe kunnen we dat doen? We kunnen maken van een subklasse van Attribute
, genaamd DependantAttribute
, en deze onderklasse al het gedrag dat we moeten geven.
Kenmerken toe te voegen als kinderen is heel simpel: alles wat we moeten doen is een andere array te houden kenmerken maken en toevoegen van specifieke code voor de berekening van het attribuut final. Omdat we niet weten of elk kenmerk zal worden berekend op dezelfde manier (u zou willen eerste gebruik beweeglijkheid te wijzigen van de snelheid van de aanval, en controleer de bonussen, maar eerst gebruik bonussen te wijzigen van magische aanval en vervolgens gebruikt, bijvoorbeeld, intelligentie) , we moeten ook scheiden van de berekening van het attribuut
final in de kenmerk-klasse in verschillende functies. Laten we dat eerst doen.
In Attribute.as
:
1 |
|
2 |
package
|
3 |
{
|
4 |
public class Attribute extends BaseAttribute |
5 |
{
|
6 |
private var _rawBonuses:Array; |
7 |
private var _finalBonuses:Array; |
8 |
|
9 |
protected var _finalValue:int; |
10 |
|
11 |
public function Attribute(startingValue:int) |
12 |
{
|
13 |
super(startingValue); |
14 |
|
15 |
_rawBbonuses = []; |
16 |
_finalBonuses = []; |
17 |
|
18 |
_finalValue = baseValue; |
19 |
}
|
20 |
|
21 |
public function addRawBonus(bonus:RawBonus):void |
22 |
{
|
23 |
_rawBonuses.push(bonus); |
24 |
}
|
25 |
|
26 |
public function addFinalBonus(bonus:FinalBonus):void |
27 |
{
|
28 |
_finalBonuses.push(bonus); |
29 |
}
|
30 |
|
31 |
public function removeRawBonus(bonus:RawBonus):void |
32 |
{
|
33 |
if (_rawBonuses.indexOf(bonus) >= 0) |
34 |
{
|
35 |
_rawBonuses.splice(_rawBonuses.indexOf(bonus), 1); |
36 |
}
|
37 |
}
|
38 |
|
39 |
public function removeFinalBonus(bonus:RawBonus):void |
40 |
{
|
41 |
if (_finalBonuses.indexOf(bonus) >= 0) |
42 |
{
|
43 |
_finalBonuses.splice(_finalBonuses.indexOf(bonus), 1); |
44 |
}
|
45 |
}
|
46 |
|
47 |
protected function applyRawBonuses():void |
48 |
{
|
49 |
// Adding value from raw
|
50 |
var rawBonusValue:int = 0; |
51 |
var rawBonusMultiplier:Number = 0; |
52 |
|
53 |
for each (var bonus:RawBonus in _rawBonuses) |
54 |
{
|
55 |
rawBonusValue += bonus.baseValue; |
56 |
rawBonusMultiplier += bonus.baseMultiplier; |
57 |
}
|
58 |
|
59 |
_finalValue += rawBonusValue; |
60 |
_finalValue *= (1 + rawBonusMultiplier); |
61 |
}
|
62 |
|
63 |
protected function applyFinalBonuses():void |
64 |
{
|
65 |
// Adding value from final
|
66 |
var finalBonusValue:int = 0; |
67 |
var finalBonusMultiplier:Number = 0; |
68 |
|
69 |
for each (var bonus:RawBonus in _finalBonuses) |
70 |
{
|
71 |
finalBonusValue += bonus.baseValue; |
72 |
finalBonusMultiplier += bonus.baseMultiplier; |
73 |
}
|
74 |
|
75 |
_finalValue += finalBonusValue; |
76 |
_finalValue *= (1 + finalBonusMultiplier); |
77 |
}
|
78 |
|
79 |
public function calculateValue():int |
80 |
{
|
81 |
_finalValue = baseValue; |
82 |
|
83 |
applyRawBonuses(); |
84 |
|
85 |
applyFinalBonuses(); |
86 |
|
87 |
return _finalValue; |
88 |
}
|
89 |
|
90 |
public function get finalValue():int |
91 |
{
|
92 |
return calculateValue(); |
93 |
}
|
94 |
}
|
95 |
}
|
Zoals je kunt zien aan de gemarkeerde regels, hebben we alleen applyRawBonuses ()
en applyFinalBonuses ()
toegepast en deze aangeroepen bij het berekenen van het laatste attribuut in calculationValue ()
. We hebben ook _finalValue
beschermd gemaakt, zodat we dit in de subklassen kunnen wijzigen.
Nu is alles ingesteld om de klasse DependantAttribute
te maken! Hier is de code:
1 |
|
2 |
package
|
3 |
{
|
4 |
public class DependantAttribute extends Attribute |
5 |
{
|
6 |
protected var _otherAttributes:Array; |
7 |
|
8 |
public function DependantAttribute(startingValue:int) |
9 |
{
|
10 |
super(startingValue); |
11 |
|
12 |
_otherAttributes = []; |
13 |
}
|
14 |
|
15 |
public function addAttribute(attr:Attribute):void |
16 |
{
|
17 |
_otherAttributes.push(attr); |
18 |
}
|
19 |
|
20 |
public function removeAttribute(attr:Attribute):void |
21 |
{
|
22 |
if (_otherAttributes.indexOf(attr) >= 0) |
23 |
{
|
24 |
_otherAttributes.splice(_otherAttributes.indexOf(attr), 1); |
25 |
}
|
26 |
}
|
27 |
|
28 |
public override function calculateValue():int |
29 |
{
|
30 |
// Specific attribute code goes somewhere in here
|
31 |
|
32 |
_finalValue = baseValue; |
33 |
|
34 |
applyRawBonuses(); |
35 |
|
36 |
applyFinalBonuses(); |
37 |
|
38 |
return _finalValue; |
39 |
}
|
40 |
}
|
41 |
}
|
In deze klasse moeten de functies addAttribute (
) en removeAttribute ()
bekend met u zijn. U moet op de overriden calculationValue ()
-functie letten. Hier gebruiken we de attributen niet voor het berekenen van de definitieve waarde -- je moet het doen voor elk afhankelijk attribuut!
Dit is een voorbeeld van hoe je dat zou doen voor het berekenen van de aanvalsnelheid:
1 |
|
2 |
package
|
3 |
{
|
4 |
public class AttackSpeed extends DependantAttribute |
5 |
{
|
6 |
public function AttackSpeed(startingValue:int) |
7 |
{
|
8 |
super(startingValue); |
9 |
}
|
10 |
|
11 |
public override function calculateValue():int |
12 |
{
|
13 |
_finalValue = baseValue; |
14 |
|
15 |
// Every 5 points in dexterity adds 1 to attack speed
|
16 |
var dexterity:int = _otherAttributes[0].calculateValue(); |
17 |
|
18 |
_finalValue += int(dexterity / 5); |
19 |
|
20 |
applyRawBonuses(); |
21 |
|
22 |
applyFinalBonuses(); |
23 |
|
24 |
return _finalValue; |
25 |
}
|
26 |
}
|
27 |
}
|
In deze klasse gaan we ervan uit dat je het kenmerk handigheid al hebt toegevoegd als een kind van AttackSpeed
en dat dit het eerste is in de array _otherAttributes
(dat zijn een hoop aannames te maken; bekijk de conclusie voor meer informatie). Na het ophalen van de behendigheid gebruiken we het eenvoudig om meer toe te voegen aan de uiteindelijke waarde van de aanvalsnelheid.
Conclusion
Hoe zou je deze structuur in een game gebruiken als alles klaar is? Het is heel eenvoudig: het enige dat u hoeft te doen, is verschillende attributen maken en elk van hen een Attribuut
-instantie toewijzen. Hierna gaat het allemaal om het toevoegen en verwijderen van bonussen via de reeds gemaakte methoden.
Wanneer een item is uitgerust of wordt gebruikt en het een bonus toevoegt aan een attribuut, moet je een bonusinstantie van het overeenkomstige type maken en dit vervolgens toevoegen aan het attribuut van het personage. Bereken daarna eenvoudig de definitieve attribuutwaarde.
Je kunt ook de verschillende soorten beschikbare bonussen uitbreiden. U kunt bijvoorbeeld een bonus hebben die de toegevoegde waarde of vermenigvuldiger in de loop van de tijd verandert. Je kunt ook negatieve bonussen gebruiken (die de huidige code al aankan).
Met elk systeem is er altijd meer dat u kunt toevoegen. Hier zijn een paar voorgestelde verbeteringen die u kunt aanbrengen:
- Identificeer attributen op naam
- Maak een "gecentraliseerd" systeem voor het beheer van de kenmerken
- Optimaliseer de prestaties (hint: u hoeft niet altijd de definitieve waarde volledig te berekenen)
- Maak het mogelijk voor sommige bonussen om andere bonussen te verzachten of te versterken
Bedankt voor het lezen!