Hej
Nu blev der jo ikke grillaften...så finder lige et af mine hyggeprojekter frem:)
Det er nu meget nede på jorden, jeg er lidt igang med at skrive nogle vector, renderings og partikel klasser som jeg vil lave til en lille AIR app der absolut ikke kan andet end at tjene som et sjovt stykke legetøj og måske spare mig selv lidt tid. Hvis jeg bliver nogenlunde tilfreds med resultatet smider jeg den på min blog sammen med lidt forklaring og kildekode:)
Systemet er bygget op i et Composite Pattern så jeg instantierer et PartikelSystem, der populeres med partikler, kalder update rekursivt ned i gennem.... og så alligevel ikke ![]()
Humlen med de her partikel ting er altid fart, så man kan jonglere flere og flere partikler.
Jeg har 2 branches i min SVN:
(1) en der har logikken i PartikelSystem klassen, dvs. ParticleSystemFalling implements IParticleSystem, der indeholder metoder som update(), set amountParticles(), osv.
Nu er det så partikelSystem klassen der manipulerer en generisk partikel og partiklens største fornøjelse her i livet er at holde styr på nogle værdier som speed, force, offset osv. den ved faktisk ikke en gang hvor i verden den er.
(2) Den anden branch har rykket logikken ned i Partiklen, dette er nu en FallingParticle implements IParticle, hvor interfacen indeholder update() og en draw() inden i update funktionen sker alt magien så og partikelsystem klassen gør ikke så meget andet end at iterere hen over partiklerne, oprette nye og slette de overskydende alt efter hvor mange brugere ønsker (hiver i en lille slider). Det sidste den gør er at aflæse x,y værdierne i partiklen og sætte
Den første virker umiddelbart, den er simpel fordi PartikelSystem typen kan skiftes live meget enkelt:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | public var behaviorList:Array = [ "falling", "chase", "follow" ]; private var pSystem:IParticleSystem; private function init():void { behavior = behaviorList[0]; addEventListener( Event.ENTER_FRAME, update, false, 0, true ); } private function set behavior( bhr:String ):void { switch ( bhr ) { case behaviorList[ 0 ]: pSystem = new ParticleSystemFalling( countSlider.value, w, h ); break; case behaviorList[ 1 ]: pSystem = new ParticleSystemChasing( countSlider.value, w, h ); break; } } |
Det er en fin løsning fordi der er ingen kode omkring stillingstagen til hvilket system er jeg, hvilke partikler kan jeg tegne osv. der ryger ind i loopet der skal igennem alle 4000+ partikler 30 gange i sekundet.
MEN.. den kræver jo jeg hardcoder partikler inde i PartikelSystem klassen og at jeg skal lave gevaldige krumspring for at ændre disse, plus jeg propper en slags adapter(ParticleSystemXXXXX) ind imellem min "Main"(overstående) og mine partikler, denne skal opfylde kriterier for både overstående Main og partiklerne.
Hmm..Det ville være meget sjovere hvis man bare kunne skrive en partikel klasse op mod en interface, fordre den til en PartikelSystem klasse og så se resultatet i main med det samme, uden at skulle kigge sig over begge skuldre for at sikre sig at partikelsystemet og brugerfladen nu er af den rigtige type.
Den løsning jeg ønsker men ikke lige kan få til at spille uden at skulle caste de forskellige partikler hele tiden, hvilket skal ligge lige midt i partikelSystems update loop der helst skal op på at køre så hurtigt som muligt.. plus der skal files i PartikelSystemet før den kan forstå en ny slags partikel.
Her er ParticleSystem klassen, hvis eneste opgave helst skulle være at kalde update på alle partikler og ellers holde styr på om der skal laves nye eller fjernes overskydende partikler:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 | package com.rickigregersen.particles { public class ParticleSystem { private var particlesContainer : Sprite; private var numParticles : int; private var w : int; private var h : int; public function ParticleSystem( _numParticles : int, _w : int, _h : int ) { w = _w; h = _h; numParticles = _numParticles; particlesContainer = new Sprite(); for ( var i : int = 0; i < numParticles; i++ ) { //var p : ParticleFalling = new ParticleFalling( new Vector2D() ); particlesContainer.addChild(p); } } public function updateParticles() : void { var p : IParticle; for ( var i : int = 0; i < particlesContainer.numChildren; i++ ) { //p = particlesContainer.getChildAt( i ) as FallingParticle; p.update(); } } public function setNumParticles( n : int ) : void { numParticles = n; if ( numParticles > particlesContainer.numChildren ) { var p : IParticle; while ( particlesContainer.numChildren < numParticles ) { //p = new ParticleFalling( new Vector2D() ); particles.addChild( p ); } } else if ( numParticles < particlesContainer.numChildren ) { while ( particlesContainer.numChildren > numParticles ) { particlesContainer.removeChildAt( numParticles ); } } } public function get particles() : Sprite { return particlesContainer; } } } |
Jeg har udkommenteret alle de steder hvor jeg løber ind i at skulle caste typen af partikel istedet for at bruge interfacen :/ en given partikel extends Shape implements IParticle så skulle sagtens kunne addChild() osv. på den, men først efter den er castet.. dvs. nu er mit partikelSystem afhængig af at skulle jonglere typer, hvilket vil sige at den ikke er "plug-and-play" længere. Jeg ville gerne give et partikelSystem en parameter der hed "particleType"og at den så lavede alle de overstående ting, hvis jeg pludselig overskrev med et nyt particleSystem med en anden particleType som parameter, så tikkede partikelSystemet bare videre med den ![]()
Er Jeg ovre i Abstrakte klasser eller hvad skal jeg gøre for at få logikken ned i partiklen, men stadig bibeholde min struktur med at have tingene i en sprite jeg kan returnere til min renderings klasse og at jeg til hver en tid kan udskifte partiklen, så længe den er af typen "IParticle" og externder Shape?
Hmm når en post bliver så lang så har det, det altid med at blive noget vås
smid lige en "spænd hjelmen Ricki" hvis du har et godt forslag men ikke kan læse min kragesyntaks (kragesyntaks...?? den trademarker jeg lige)
Tak og god ferie alle sammen, med eller uden grill.
10 kommentarer
Uden at have tænkt alt for meget over om det lige opfylder alle dine ønsker er min idé denne:
Du laver en generator klasse til hver particle type som implementerer IParticleGenerator og har en enkelt funktion som er createParticle():IParticle som egentlig bare returnerer en ny instans af den givne particle type. Din ParticleSystem klasse tager så imod en generator klasse som den kan bruge til at lave nye partikler med, da den generatoren implementerer IParticleGenerator kan du løbende udskifte din particle generator klasse med en ny generator som laver en anden form for partikler.
Din ParticleSystem klasse vil nok komme til at se nognelunde sådan her ud:
Eksempel på en generator:
En alternativ metode til at have en generator klasse til hver type partikel kan du lave en generel generator klasse som tager imod en behavior:String som så bestemmer hvilken type partikel der bliver returneret med createParticle() funktionen.
Hej Artmos
Jeg syntes det lyder som en god ide og jeg vil prøve at implementere den som prof of concept med det samme.
Jeg skal så fremover bygge en particleGenerator og en Particle klasse til hver nye Particle behavior ... medmindre jeg kan lade partiklen implementere både iParticleGenerator og IParticle, så en partikel kan generere en ny partikel.. det går dog lidt i retning af at klassen får forskellige opgaver, dog kan man vel godt forsvare at en partikel kan lave x kloner af sig selv.
Jeg brygger lige et eksempel hvor din ide er implementeret, der efter prøver jeg at bygge en partikel der implementerer både IParticle og IParticleGenerator.
En ide der udspringer af din, kunne være at bygge en AbstractParticle der allerede implementerede en generator og så bruge den som boilerplate hver gang man bygger en ny partikel.
Nu vælter det ud med ideer, tak for dit indspark det var lige det jeg trængte til
Mvh. Ricki
AS1 < AS2 < AS3
Glad for at kunne give lidt inspiration. Efter min mening skal selve Partikel klasserne (f.eks. ParticleFalling) være så simple som muligt og kun forholde sig til sig selv og ikke en generator, men derfor kunne de sagtens have en slags clone metode som lavede en ny instans af samme type som sig selv, på den måde er det muligvis slet ikke nødvendigt med en generator.
Øv øv og dobbelt øv, den fejler ikke i oprettelsen af en IParticle men simpelthen
når der forsøges at lave addChild på noget den ikke kender. Dette er selv om at partiklen extender Shape ... men det står der selvfølgelig ikke noget om i Interfacen :/
Så denne detalje herunder resulterer i de fejl der står nedenunder igen:
1067: Implicit coercion of a value of type com.rickigregersen.dualParticle:IParticle to an unrelated type flash.display:DisplayObject. ParticleSystem.as DualInterfaceParticlePOC/src/com/rickigregersen/dualParticle line 25 Flex Problem
Dvs. den kan ikke finde nogen x property på en IParticle, det kunne nok klares ved at have sådan en i interfacen, dog vil det ikke hjælpe på at den bare ikke vil lave addChild med noget der ikke er helt sikkert DisplayObject.
Dette her virker dog helt efter hensigten:
Det er simpelthen addChild og flash der er så utrolig følsom omkring sine DisplayObjects at det er ved at blive småtræls.
Mvh. Ricki
AS1 < AS2 < AS3
Hejsa RickyG
Jeg vil lige henvise til denne artikel FF artikel
Med venlig hilsen, best regards
Rene´
Du kan enten inkludere alle de propeties og functions du har brug for at anvende fra DisplayObject i dit Interface, eller også så skal du bare caste din particle til et DisplayObject, når du bruger det.
Bemærk desuden at jeg flyttede din variable oprettelse uden for loopet. Hvis det er performance du sigter efter, så er der en del at hente i loops, ved kun at oprette variabler en gang.
Hejsa alle sammen, fedt i byder ind.
The-Builder og Rene i har fat i den samme ende, altså at typecaste mine objekter når jeg adder dem til et DisplayObject og hiver dem frem igen.
Den får jeg samme fejl som i indlægget tidligere, altså at den ikke mener jeg kan mase noget af typen IParticle ned i DisplayObject.
paster lige de forskellige klasser ind (kan snige sig en fejl ind da jeg sidder og retter i dem hele tiden...bla. at variablen blev erklæret i loopet osv
)
Dette er et nyt projekt jeg har lavet til kun at løse den del omkring hvordan jeg får lavet hotswap af objekter, så klasserne er for det meste bare skelet:
Mvh. Ricki
AS1 < AS2 < AS3
Din "p" variable er jo stadig af typen IParticle!
Hvis du vil gemme den som en IParticle skal du caste den hver gang du vil bruge variablen som et displayObject.
DisplayObject(p).x = 500;
I forbindelse med typecasting mener jeg at det er hurtigere at sige 'DisplayObject(particle)' i stedet for 'particle as DisplayObject', da den sidste metode tester om particle kan fungere som DisplayObject hvorimod den første bare behandler particle som DisplayObject uden at teste på den. Kan være jeg tager fejl, men mener at det er sådan det fungerer.
Lige et hurtigt design mæssigt indspark.
Du kunne lave en IDisplayable datatype med metoden displayObject. Med den defineret kan du både have abstrakte, logiske og reelle DisplayObject klasser, der alle kan bruges ensartet.
IDisplayable:
Concrete Inheritage
Composite Display
Det er én måde at abstrahere fra konkrete display objekt constraints forbundet med polymophism.
God fornøjelse med dit projekt.
Cheers
Asger